#include-once
#include <GuiTab.au3>
#include <WinAPISysWin.au3>

#cs============================================================================= Function List =====

_SGI_GetAllHwnd             Retrieves all SciTE-related handles from all existing SciTE instances
_SGI_GetActiveSciTEHwnd     Gets the handle of the active SciTE window
_SGI_SetPollTime            Defines the interval for updating the SciTE handles or deactivates them

#ce============================================================================= /Function List ====


;============================================================================= Global Variables ====

;======================================================= Activates TEST Run ==
Global $gbTEST = False
;~ Global $gbTEST = True   ; True: Run the TEST part - output in console
;=============================================================================

$gSGI_mSciTE = _MapNew('Instances', _ArrayNull())   ; Map to store all infos
$gSGI_bPoll = True                                  ; refills the info map by polling time (True) or by function call (False)
$gSGI_iPollTime = 750                               ; polling time (min value 250), "-1" sets $gSGI_bPoll to False

;============================================================================= /Variables ==========


;============================================================================= Main ================
If $gSGI_bPoll Then AdlibRegister(__SGI_PollInfo, $gSGI_iPollTime)
;============================================================================= /Main ===============


;============================================================================= T E S T =============
If $gbTEST Then
    HotKeySet('{ESC}', _TestExit)
    Local $iInstancesLast = 0
    While True
        Sleep(100)
        If $iInstancesLast <> ($gSGI_mSciTE.Instances)[0] Then
            $iInstancesLast = ($gSGI_mSciTE.Instances)[0]
            For $i = 1 To ($gSGI_mSciTE.Instances)[0]
                ConsoleWrite('Instance: ' & $i & @CRLF)
                Local $h = ($gSGI_mSciTE.Instances)[$i]
                For $k In MapKeys($gSGI_mSciTE[$h])
                    ConsoleWrite(StringFormat('-> %-15s%s', $k, $gSGI_mSciTE[$h][$k]) & @CRLF)
                Next
            Next
            ConsoleWrite('>> Stop with {Esc}' & @CRLF & @CRLF)
        EndIf
    WEnd
EndIf

Func _TestExit()
    Exit
EndFunc
;============================================================================= / T E S T ===========


#Region - Functions
; #FUNCTION# =======================================================================================
; Name ..........: _SGI_GetAllHwnd
; Description ...: Retrieves all SciTE-related handles from all existing SciTE instances.
; ...............: For each instance, a map is saved in the global map $gSGI_mSciTE with the
; ...............: SciTE window handle as the key.
;  The data map .: $gSGI_mSciTE Keys:   .Instances = Array with SciTE window handles [count, hWnd_1, .. , hWnd_n]
;                   If one or more SciTE windows are present:
;                   For each instance: $gSGI_mSciTE[hwnd_1 SciTE] .. [hwnd_n SciTE] = MapSciTE
;                   MapSciTE    Keys:   .PID       = SciTE Process ID
;                                       .hWnd      = hwndSciTE
;                                       .Title     = SciTE Window Title
;                                       .Director  = hWnd DirectorExtension
;                                       .Editor    = hWnd Editor pane
;                                       .Output    = hWnd Output pane
;                                       .Toolbar   = hWnd Toolbar Ctrl
;                                       .TabCtrl   = hWnd Tab Ctrl
;                                       .iTabItem  = Index of the current active Tab-Item
;                                       .sTabItem  = Text of the current active Tab-Item
;                                       .Statusbar = hWnd Statusbar Ctrl
; Syntax ........: _SGI_GetAllHwnd([$_bReturn = False])
; Parameters ....: $_bReturn    - [optional] Returns the global result map (Default: False)
; Return values .: Related to $_bReturn
; Author ........: BugFix
; ==================================================================================================
Func _SGI_GetAllHwnd($_bReturn=False)
    __SGI_Purge()
    Local $aWin = WinList('[Class:SciTEWindow]')
    If  $aWin[0][0] = 0 Then Return
    Local $aInstances[$aWin[0][0]+1] = [$aWin[0][0]]
    Local $PID, $PIDExt, $aExtension, $hDirector
    For $i = 1 To $aWin[0][0]
        $aInstances[$i] = $aWin[$i][1]
        $PID = WinGetProcess($aWin[$i][1])
        $aExtension = WinList("DirectorExtension")
        For $j = 1 To $aExtension[0][0]
            $PIDExt = WinGetProcess($aExtension[$j][1])
            If $PIDExt = $PID Then
                $hDirector = $aExtension[$j][1]
                ExitLoop
            EndIf
        Next
        $gSGI_mSciTE.Instances = $aInstances
        $gSGI_mSciTE[$aWin[$i][1]] = _MapNew('PID', $PID, 'hWnd', $aWin[$i][1], 'Title', $aWin[$i][0], 'Director', $hDirector)
        __SGI_GetChildWnd($gSGI_mSciTE[$aWin[$i][1]])
    Next
    If $_bReturn Then Return $gSGI_mSciTE
EndFunc


; #FUNCTION# =======================================================================================
; Name ..........: _SGI_GetActiveSciTEHwnd
; Description ...: Gets the handle of the active SciTE window
; Syntax ........: _SGI_GetActiveSciTEHwnd()
; Parameters ....: None
; Return values .: SciTE hwnd or Null (if active window isn't SciTE)
; Author ........: BugFix
; ==================================================================================================
Func _SGI_GetActiveSciTEHwnd()
    Local $hActive = WinGetHandle('[ACTIVE]')
    Return (_WinAPI_GetClassName($hActive) = 'SciTEWindow' ? $hActive : Null)
EndFunc


; #FUNCTION# =======================================================================================
; Name ..........: _SGI_SetPollTime
; Description ...: Defines the interval for updating the SciTE handles or deactivates them.
; Syntax ........: _SGI_SetPollTime([$_iTime = 750])
; Parameters ....: $_iTime      - [optional] The time to read again all handles. (Default is 750).
; ...............:                -1 deactivates polling.
; Return values .: None
; Remarks .......: The lowest permissible polling time is 250 ms.
; Author ........: BugFix
; ==================================================================================================
Func _SGI_SetPollTime($_iTime=750)
    If $_iTime = -1 Then
        $gSGI_bPoll = False
    Else
        ; don't allow polling < 250 ms
        $gSGI_iPollTime = ($_iTime < 250 ? 250 : $_iTime)
    EndIf
EndFunc
#EndRegion - Functions


;============================================================================= Internal ============
; Refresh information in the polling intervall
Func __SGI_PollInfo()
    AdlibUnRegister(__SGI_PollInfo)
    _SGI_GetAllHwnd()
    AdlibRegister(__SGI_PollInfo, $gSGI_iPollTime)
EndFunc

; Remove entries that no longer exist
Func __SGI_Purge()
    Local $n = 0
    For $k In MapKeys($gSGI_mSciTE)
        If $k = 'Instances' Then ContinueLoop
        If Not WinExists($k) Then
            MapRemove($gSGI_mSciTE, $k)
            __SGI_InstanceRemove($k)
        Else
            $n += 1
        EndIf
    Next
EndFunc

; Removing entries from the hWnd list
Func __SGI_InstanceRemove($_hWnd)
    Local $aRepl[UBound($gSGI_mSciTE.Instances)-1] = [($gSGI_mSciTE.Instances)[0] -1], $n = 1
    For $i = 1 To ($gSGI_mSciTE.Instances)[0]
        If ($gSGI_mSciTE.Instances)[$i] <> $_hWnd Then
            $aRepl[$n] = ($gSGI_mSciTE.Instances)[$i]
            $n += 1
        EndIf
    Next
    $gSGI_mSciTE.Instances = $aRepl
EndFunc

; Compile all window information for a SciTE instance
Func __SGI_GetChildWnd(ByRef $_mInstance)
    Local $iScintilla = 0, $sKey
    Local $aChWnd = _WinAPI_EnumChildWindows($_mInstance.hWnd, False)
    For $i = 1 To $aChWnd[0][0]
        Switch $aChWnd[$i][1]
            Case 'Scintilla'
                $iScintilla += 1
                $sKey = $iScintilla = 1 ? 'Editor' : 'Output'
            Case 'ToolbarWindow32'
                $sKey = 'Toolbar'
            Case 'SciTeTabCtrl'
                $sKey = 'TabCtrl'
            Case 'msctls_statusbar32'
                $sKey = 'Statusbar'
            Case Else
                ContinueLoop
        EndSwitch
        $_mInstance[$sKey] = $aChWnd[$i][0]
        If $sKey = 'TabCtrl' Then
            $_mInstance['iTabItem'] = _GUICtrlTab_GetCurFocus($_mInstance.TabCtrl)
            $_mInstance['sTabItem'] = _GUICtrlTab_GetItemText($_mInstance.TabCtrl, $_mInstance.iTabItem)
        EndIf
    Next
EndFunc

; Create new map
; Optional: assign until 5 key/value-pairs ([Key1, Val1 [, Key2, Val2 [, ...]]])
Func _MapNew($_k1=Null, $_v1=Null, $_k2=Null, $_v2=Null, $_k3=Null, $_v3=Null, _
             $_k4=Null, $_v4=Null, $_k5=Null, $_v5=Null)
    Local $m[], $aKV[5][2] = [[$_k1,$_v1],[$_k2,$_v2],[$_k3,$_v3],[$_k4,$_v4],[$_k5,$_v5]]
    If $_k1 <> Null Then
        For $i = 0 To 4
            If $aKV[$i][0] = Null Then ExitLoop
            $m[$aKV[$i][0]] = $aKV[$i][1]
        Next
    EndIf
    Return $m
EndFunc

; Create empty array
Func _ArrayNull()
    Local $a[] = [0]
    Return $a
EndFunc
;===================================================================================================
