com.start-automating.scriptdeck.sdPlugin/WatchPath.@KeyDown,WillAppear.ps1

$invokeError = $null
$settings = $event.MessageData.payload.settings
if (-not $settings.Path) { return }


$eventName         = $settings.Path
$fileWatcherFilter = $settings.PathFilter
$eventSubscribers  = Get-EventSubscriber
$separator         = [IO.Path]::DirectorySeparatorChar
$eventName         = $ExecutionContext.SessionState.InvokeCommand.ExpandString($eventName)
# If the event name was not a path,
if (-not "$eventName".Contains("$separator")) {
    return # we are done.
}

# Split the path into parts
$pathParts = @($eventName.Split("$separator"))
# If the last part contained wildcards, it's a filter
$fileWatcherPath, $fileWatcherFilter = 
    if ($pathParts[-1] -match '[\*\?]') {
        ($pathParts[0..($pathParts.Length - 2)] -join $separator)
        $pathParts[-1]
    }
    elseif ($pathParts[-1] -match '\.') {
        ($pathParts[0..($pathParts.Length - 2)] -join $separator)
        $pathParts[-1]
    }
    else {
        $pathParts -join $separator
        $fileWatcherFilter
    }

# Find any previous event subscriptions from this button.
$toRemove = $eventSubscribers | 
    Where-Object {
        $_.SourceObject -is [IO.FileSystemWatcher] -and 
        $_.SourceObject.SourceEvent.MessageData.Context -eq $event.MessageData.Context
    }

# And remove them.
$toRemove |
    Unregister-Event

# Create a FileSystemWatcher
$fileSystemWatcher = [IO.FileSystemWatcher]::new()
$fileSystemWatcher | Add-Member SourceEvent $event -Force
$fileSystemWatcher.Path = $fileWatcherPath
# set the filter,
if ($fileWatcherFilter) {
    $fileSystemWatcher.Filter = $fileWatcherFilter
}
# (recurse if they said they want to),
if ($settings.Recurse) {
    $fileSystemWatcher.IncludeSubdirectories = $true
}
# set up the notification files,
$NotifyFilter = $settings.FileChangeEvent -as [IO.NotifyFilters]
if (-not $NotifyFilter) { $NotifyFilter = 'LastWrite'}
$fileSystemWatcher.NotifyFilter = $NotifyFilter
# predetermine the event id
$fileChangedSourceId = "FileChanged_$($event.MessageData.Context)"
# and create a handler to propagate the event.
$propagateFileEvent = "
    `$fileChangedContext = '$($event.MessageData.Context)'
    `$fileChangedSourceId = '$fileChangedSourceId'
"
 + {
    # Why not subscribe directly?
    # FileSystemWatcher often sends multiple events,
    # so we'll guard against that by propagating only the first in a timeframe.
    if ($script:LastFileEvent) {
        if (($event.TimeGenerated - $script:LastFileEvent.TimeGenerated) -gt '00:00:00.25') {
            $script:LastFileEvent = $null
        }
    }

    # If the last event was from the same context, return
    if ($script:LastFileEvent -and $event.SourceArgs[1].FullPath -eq $script:LastFileEvent.SourceArgs[1].FullPath -and
        ($script:LastFileEvent.MessageData.Context -eq $event.MessageData.Context)) {
        return
    }
    
    $script:LastFileEvent = $event

    # Create an object for the file change
    $eventMessageData = [Ordered]@{
        FilePath = $event.SourceArgs[1].FullPath
    }
    # and get the subscriber.
    $sourceSubscriber = Get-EventSubscriber | 
        Where-Object { $_.SourceObject.SourceEvent.MessageData.Context -eq $fileChangedContext }            
        
    # The subscriber has the source event, which provides additional context
    foreach ($prop in $sourceSubscriber.SourceObject.SourceEvent.MessageData.psobject.properties) {
        # so add that to the message.
        $eventMessageData[$prop.Name] = $prop.Value
    }

    $eventMessageData = [PSCustomObject]$eventMessageData
    # and generate the file event.
    New-Event -SourceIdentifier $fileChangedSourceId -MessageData $eventMessageData
}

# Now, we need to unregister all of the events subscribers related to this button.
Get-EventSubscriber -SourceIdentifier $fileChangedSourceId -ErrorAction Ignore | Unregister-Event

# and register our changed event.
Register-ObjectEvent -EventName Changed -Action (
    [scriptblock]::Create($propagateFileEvent)
) -InputObject $fileSystemWatcher

# If there was a specific handler
if ($settings.Handler) {
    try {
        # Register for it
        $createdHandler = [ScriptBlock]::Create($settings.Handler)
        Register-EngineEvent -SourceIdentifier $fileChangedSourceId -Action $createdHandler
    } catch {
        $ex = $_
        Send-StreamDeck -LogMessage "WatchEvent@ScriptDeck: Could not create handler: $($ex | Out-String)"
        Send-StreamDeck -ShowAlert -Context $event.MessageData.Context
    }
}

# If they want to automatically set images
if ($settings.AutoSetImage) {
    # register a handler that
    Register-EngineEvent -SourceIdentifier $fileChangedSourceId -Action {
        $eventFile = $event.MessageData.FilePath -as [IO.FileInfo]
        # will set the image if the event file is an image file.
        if ($eventFile.Extension -in '.gif', '.svg' ,'.png', '.jpg', '.jpeg', '.bmp') {
            Send-StreamDeck -ImagePath $eventFile.Fullname -Context $event.MessageData.Context
        }
    }
}

# If they want to automatically set the title,
if ($settings.AutoSetTitle) {
    # register a handler
    Register-EngineEvent -SourceIdentifier $fileChangedSourceId -Action {
        $eventFile = $event.MessageData.FilePath -as [IO.FileInfo]
        # that sets the title to the name of the file.
        Send-StreamDeck -Title $eventFile.Name -Context $event.MessageData.Context                
    }
}

# If they want to send a message
if ($settings.SendMessage) {
    # write this event to disk
    $context = $event.MessageData.context
    $messageDataJson = $event.MessageData | ConvertTo-Json -Depth 10
    $messagePath = 
        Join-Path $fileWatcherPath "$(@($event.SourceIdentifier -split '\.' -ne '')[-1]).$context.json"
    $messageDataJson | Set-Content $messagePath
}

# If they want to RunScripts
if ($settings.RunScripts) {
    # create a handler that will run any .ps1
    Register-EngineEvent -SourceIdentifier $fileChangedSourceId -Action {
        $eventFile = $event.MessageData.FilePath -as [IO.FileInfo]        
        if ($eventFile.Extension -ne '.ps1') { return }
        . $eventFile.FullName
    }
}
    
if ($invokeError) {
    Send-StreamDeck -ShowAlert -Context $event.MessageData.Context
} else {
    Send-StreamDeck -ShowOK -Context $event.MessageData.Context
}