;---FUNCTIONS-----------------------------------------------------------------------
; Misc Functions that are called by both the Video and Social Media poster


; -------------------------------Variables-------------------------------
; Declare global variables here so they don't have to be declared in each script
global ChromeTabsURLArray
global DriverTitleArray
global LastWebsitePostURL
global ScreenshotsTaken
global ChromeFilepath
global CurrentTabURL
global URLOfLastErrorPage

; #Include %A_ScriptDir%\ChromeAutomationFunctions.ahk
; #Include %A_ScriptDir%\RunCMD.ahk


DevModeMsgBox(Message){
    if(!DevMode)
    return

    Msgbox, 4096, DevModeMsgBox, %Message%
    return
}


CheckForUpdates(GitReleasesAPIURL){
    ; msgbox, checking for updates
    Message = Checking For Updates
    SaveOrPostProgress(Message,PostType:="ErrorLoggingTextFile")

    data := URLDownloadToVar(GitReleasesAPIURL)
    ; Msgbox % "data: " data

    parsed := JSON.Load(data)

    UpdateVersionNumber := parsed.1.name

    Message = UpdateVersionNumber: %UpdateVersionNumber%
    DevModeMsgBox(Message)


    if(ScriptVersion = UpdateVersionNumber OR ScriptVersion > UpdateVersionNumber){
       ToolTip
       return 0
   }
   else, {
    UpdateAvailable := 1
    ; msgbox, update found!
    Message = Program Update Found
    SaveOrPostProgress(Message:=Message,PostType:="ErrorLoggingTextFile")
    ; IniWrite, 1, %SettingsIniFilepath%, %ScriptSettingsSection%, UpdateAvailable
    ; ToolTip
    return 1
}

}


UpdateScript(){
    data := URLDownloadToVar(GitReleasesAPIURL)

    parsed := JSON.Load(data)

    UpdateVersionNumber := parsed.1.name
    ChangeLog := parsed.1.body
    exename := parsed.1.assets.1.name
    exeURL := parsed.1.assets.1.browser_download_url

    ; Msgbox % "UpdateVersionNumber: " UpdateVersionNumber
    ; msgbox, Version: %Version%
    ; Msgbox % "ChangeLog: " ChangeLog
    ; Msgbox % "exeURL: " exeURL
    ; Msgbox % "exename: " exename

    ExeName := StrReplace(exename, ".exe", "")
    UpdateExeName = %exename% %UpdateVersionNumber%.exe
    UpdateExeFilepath = %A_ScriptDir%\%UpdateExeName%

    if(ScriptVersion = UpdateVersionNumber){
        ; IniWrite, 0, %SettingsIniFilepath%, %ScriptSettingsSection%, UpdateAvailable
        MsgBox, You are Up-To-Date
        ; IniRead, UpdateAvailable, %SettingsIniFilepath%, %ScriptSettingsSection%, UpdateAvailable, 0
        return
    }

    Changelog = %ScriptVersion% --> %UpdateVersionNumber%`n%Changelog%

    OnMessage(0x44, "OnMsgBoxUpdateAvailable")
    MsgBox 0x44, Update Available, %Changelog%
    OnMessage(0x44, "")

    IfMsgBox Yes, {
        Return
    } 
    Else IfMsgBox No, {
        SaveOrPostProgress(Message:="Downloading Update",PostType:="Tooltip,ErrorLoggingTextFile")
        ; Msgbox, downloading to: %A_ScriptDir%\%UpdateExeName%
        UrlDownloadToFile, %exeURL%, %UpdateExeFilepath%
        run, "%UpdateExeFilepath%" "%A_ScriptFullPath%"
        ExitApp
    }
    return
}



; -------------------------------SaveOrPostProgress-------------------------------
; PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging,DiscordVideos"
SaveOrPostProgress(Message:="",PostType:=""){ 

    MessageBU := Message
    ; Msgbox % "PostType: " PostType
    ; Msgbox % "CurrentSite: " CurrentSite

    if(CurrentSite != "")
    Message := CurrentSite . ": " . Message

    if(InStr(PostType, "Tooltip")){
        TooltipThis(Message)
    }
    if(InStr(PostType, "ErrorLoggingTextFile")){
        Func_LogErrorsToTextFile(Message)
    }
    if(InStr(PostType, "ErrorSummaryVar")){
        Func_LogErrorsToVar(Message)
    }
    if(InStr(PostType, "DiscordErrorLogging")){
        PostToDiscordChannel(Message,DiscordErrorLoggingWebhookBotURL)
    }
    if(InStr(PostType, "DevModeMsgBox")){
        DevModeMsgBox(Message)
    }
    if(InStr(PostType, "DiscordVideos")){
        Message := MessageBU
        PostToDiscordChannel(Message,DiscordVideosWebhookURL)
    }
    if(InStr(PostType, "DiscordParler")){
        Message := MessageBU
        PostToDiscordChannel(Message,DiscordParlerWebhookURL)
    }



}
; -------------------------------/SaveOrPostProgress-------------------------------
TakeScreenshotOfPage(SaveFilepath := ""){

    if(!ScreenshotResult)
    return

    TooltipThis("Sleeping 5 Seconds Before Taking Screenshot")
    ; sleep, 5000

    if(SaveFilepath = ""){
       SaveFilepath := ErrorLoggingDirectory
   }

   ; if(!FileExist(SaveFilepath))
   FileCreateDir, %SaveFilepath%

 /*   if(!TakeScreenshotsOfErrors)
    Return
    */
    ; Take a screenshot of the page and save it. 
    FormatTime, TodayDate , YYYYMMDDHH24MISS, yyyyMMdd_hhmmss 

    ; Msgbox % "ErrorLoggingDirectory: " ErrorLoggingDirectory
    savepath = %SaveFilepath%\%TodayDate%.jpg
    ; Msgbox % "savepath: " savepath
    try driver.TakeScreenshot().SaveAs(savepath)

    ; ScreenshotsTaken := 1

}




; -------------------------------TooltipThis-------------------------------
TooltipThis(String){
    ; Xposition := StrLen(String)
    StringFirstLine := StrSplit(String, "`n")
    StringFirstLine := StringFirstLine[1]
    Xposition := StrLen(StringFirstLine)
    ; Msgbox % "String: " String
    Xposition := Xposition * 4
    X := (A_ScreenWidth / 2) - Xposition
    ; Msgbox % "X: " X
    if(ShowTooltipProgress){
        ToolTip, %String%, %X%, 0
    }
}
; -------------------------------/TooltipThis-------------------------------

;------------------------------------------------
TimedToolTip(Text, x="", y="",RemoveAfterTime:=2000, SetWhichToolTip="") {  
    if(X = ""){
        Xposition := StrLen(Text)
        ; Msgbox % "Xposition: " Xposition
        Xposition := Xposition * 4
        ; Xposition := 0
        X := (A_ScreenWidth / 2) - Xposition
        ; Msgbox % "X: " X
    }
    (y = "")?(y:=0):(y:=y)
    
    ; Msgbox % "y: " y
    ToolTip, %Text%, %X%, %Y%
    SetTimer, RMApp_ToolTipRASub, % - RemoveAfterTime   
    return
    RMApp_ToolTipRASub:
    ToolTip,,,, %WhichToolTip%
    return
}


; -------------------------------LogErrorsToTextFile-------------------------------
Func_LogErrorsToTextFile(Text){
    ; ErrorLoggingFile := Filepath
    FormatTime, TodayDate , YYYYMMDDHH24MISS, yyyyMMdd_hhmmss
    text =
    (

        ---------------%TodayDate%---------------
        %Text%

        )
    FileAppend, %Text%, %ErrorLoggingFilePath%
}
; -------------------------------/LogErrorsToTextFile-------------------------------

; -------------------------------LogErrorsToVar-------------------------------
Func_LogErrorsToVar(Text){
    ErrorLogVar .= "`n" . Text
}
; -------------------------------/LogErrorsToVar-------------------------------


; -------------------------------Discord-------------------------------
PostToDiscordChannel(Message,WebhookChannel){
    ; Msgbox % "Message: " Message
    ; Msgbox % "WebhookChannel: " WebhookChannel

    ; Replace all the json forbidden characters
    SingleQuote = "
    ReplacedQuote = \"

    Message := StrReplace(Message, "\", "\\") ; Replace Tabs
    Message := StrReplace(Message, SingleQuote, ReplacedQuote) ; Replace single quote 
    Message := StrReplace(Message, "`r", "") ; Replace Carriage return
    Message := StrReplace(Message, A_Tab, "\t") ; Replace Tabs
    Message := StrReplace(Message, "`n", "\n") ; Escape New Line Character 
    Message := StrReplace(Message, "`f", "\f") ; Replace Tabs


    ; Convert into json string
    JsonString=
    (
    {
      "content": "%Message%"
  }
  )

    ; Msgbox % "JsonString: " JsonString
    ; 
    try WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
    try WebRequest.Open("POST", WebhookChannel, false)
    try WebRequest.SetRequestHeader("Content-Type", "application/json")
    try WebRequest.Send(JsonString)  
}


; -------------------------------/Discord-------------------------------



; -------------------------------TelegramAPI-------------------------------
TelegramMsgBox(Text:="", TelegramBotToken := "", TelegramBotChatID :=""){
    ; Send Images: 
    ; https://www.autohotkey.com/boards/viewtopic.php?f=76&t=68417&p=294332#p294332

    ; Msgbox % "Text: " Text


    ; Replace all forbidden characters - https://www.ascii-code.com/
    ; Text := StrReplace(Text, "`%", "%25") ; percent with 
    Text := StrReplace(Text, "`n", "%0A") ; New Line
    ; Text := StrReplace(Text, "`n", "%0A") ; New Line

    ; Text := StrReplace(Text, " ", "%23") ; New Line
    ; Text := 
    ; Text := StrReplace(Text, "`n", "%0A") ; New Line

    ; Msgbox % "Text: " Text

    ErrorLoggingPath = %A_ScriptDir%\Lib\ErrorLogging\check.rups

    loop 3
    {
        UrlDownloadToFile https://api.telegram.org/bot%TelegramBotToken%/sendmessage?chat_id=%TelegramBotChatID%&text=%Text%, %ErrorLoggingPath%
        sleep 1000
        ifexist %ErrorLoggingPath%
        {
            break
        }
        if A_index = 3
        {
            Message = Post failed due to API Issue. 
            SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging")
            Return "Failed"
            ; MsgBox, 16,, something went wrong with sending
        }
    }
    FileRead, TelegramOutput, %ErrorLoggingPath%
    TelegramOutput := "API Result: " . TelegramOutput
    ; Msgbox % "TelegramOutput: " TelegramOutput
    filedelete %ErrorLoggingPath%
    SaveOrPostProgress(Message:=TelegramOutput,PostType:="ErrorLoggingTextFile")

    if(InStr(TelegramOutput, "error_code")){
        Return "Failed"
    }

}

; -------------------------------/TelegramAPI-------------------------------

; Telegram Message API
;------------------------------------------------
SendTelegramMessage(token, chatID, text := "", ParseMode := "MarkdownV2")       ; you could add more options; compare the Telegram API docs
{
    ; ParseMode := "MarkdownV2"
    ; msgbox
    ; Msgbox % "text: " text
    url_str := "https://api.telegram.org/bot" token "/sendMessage"
    objParam := { "chat_id" : chatID                                                                              
    ,"parse_mode" : ParseMode
    ,"text" : text }

    CreateFormData(postData, hdr_ContentType, objParam)
    whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
    whr.Open("POST", url_str, true)
    whr.SetRequestHeader("Content-Type", hdr_ContentType)
    ; whr.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko")                ; ???????
    whr.Option(6) := False ; No auto redirect
    whr.Send(postData)
    whr.WaitForResponse()
    json_resp := whr.ResponseText
    whr :=                                              ; free COM object
    ; Msgbox % "json_resp: " json_resp
    if(InStr(json_resp, "error_code"))
    Return json_resp
}

/*

*bold \*text*
_italic \*text_
__underline__
~strikethrough~
*bold _italic bold ~italic bold strikethrough~ __underline italic bold___ bold*
[inline URL](http://www.example.com/)
[inline mention of a user](tg://user?id=123456789)
`inline fixed-width code`
```
pre-formatted fixed-width code block
```
```python
pre-formatted fixed-width code block written in the Python programming language
```

*/



; -------------------------------Telegram Image Sending-------------------------------
; https://www.autohotkey.com/boards/viewtopic.php?t=68417
SendTelegramPhoto(token, chatID, file, caption := "", ParseMode := "MarkdownV2")       ; you could add more options; compare the Telegram API docs
{

    ; ParseMode := "MarkdownV2"
    url_str := "https://api.telegram.org/bot" token "/sendPhoto" 
    objParam := {       "chat_id" : chatID                                                                              
    ,   "photo" : [file]  
    ,   "parse_mode" : ParseMode 
    , "caption" : caption}

    CreateFormData(postData, hdr_ContentType, objParam)
    whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
    whr.Open("POST", url_str, true)
    whr.SetRequestHeader("Content-Type", hdr_ContentType)
    ; whr.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko")                ; ???????
    whr.Option(6) := False ; No auto redirect
    whr.Send(postData)
    whr.WaitForResponse()
    json_resp := whr.ResponseText
    whr :=                                              ; free COM object
    ; Msgbox % "json_resp: " json_resp

    if(InStr(json_resp, "error_code"))
    Return json_resp
}


; -------------------------------Telegram Image Sending-------------------------------
; https://www.autohotkey.com/boards/viewtopic.php?t=68417
SendTelegramVideo(token, chatID, file, caption := "", ParseMode := "MarkdownV2")       ; you could add more options; compare the Telegram API docs
{

    ; ParseMode := "MarkdownV2"
    url_str := "https://api.telegram.org/bot" token "/sendVideo?caption=" caption
    objParam := {       "chat_id" : chatID                                                                              
    ,   "video" : [file]  
    ,   "parse_mode" : ParseMode }

    CreateFormData(postData, hdr_ContentType, objParam)
    whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
    whr.Open("POST", url_str, true)
    whr.SetRequestHeader("Content-Type", hdr_ContentType)
    ; whr.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko")                ; ???????
    whr.Option(6) := False ; No auto redirect
    whr.Send(postData)
    whr.WaitForResponse()
    json_resp := whr.ResponseText
    whr :=                                              ; free COM object
    ; Msgbox % "json_resp: " json_resp

    if(InStr(json_resp, "error_code"))
    Return json_resp
}



; -------------------------------Telegram File Sending-------------------------------
; https://www.autohotkey.com/boards/viewtopic.php?t=68417
SendTelegramFile(token, chatID, file, caption := "", ParseMode := "MarkdownV2")       ; you could add more options; compare the Telegram API docs
{

    ; ParseMode := "MarkdownV2"
    url_str := "https://api.telegram.org/bot" token "/sendDocument?caption=" caption
    objParam := {       "chat_id" : chatID                                                                              
    ,   "document" : [file]  
    ,   "parse_mode" : ParseMode }

    CreateFormData(postData, hdr_ContentType, objParam)
    whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
    whr.Open("POST", url_str, true)
    whr.SetRequestHeader("Content-Type", hdr_ContentType)
    ; whr.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko")                ; ???????
    whr.Option(6) := False ; No auto redirect
    whr.Send(postData)
    whr.WaitForResponse()
    json_resp := whr.ResponseText
    whr :=                                              ; free COM object
    ; Msgbox % "json_resp: " json_resp

    if(InStr(json_resp, "error_code"))
    Return json_resp
}






; -------------------------------/Telegram API Image Sending-------------------------------


ASCIISTRReplace(Message){
    ; Msgbox % "Message of function: " Message
    ; https://tech.saigonist.com/b/code/escaping-special-characters-markdown.html
    ; Replace all forbidden characters - https://www.ascii-code.com/

    LineBreakChar = `%0A ; Used for API


    Message := StrReplace(Message, "\", "\\") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "*", "\*") ; replace all new line characters with the global charater
    ; Message := StrReplace(Message, "`n", LineBreakChar) ; replace all new line characters with the global charater
    Message := StrReplace(Message, "!", "\!") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "_", "\_") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "{", "\{") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "}", "\}") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "[", "\[") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "]", "\]") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "(", "\(") ; replace all new line characters with the global charater
    Message := StrReplace(Message, ")", "\)") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "#", "\#") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "+", "\+") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "-", "\-") ; replace all new line characters with the global charater
    Message := StrReplace(Message, ".", "\.") ; replace all new line characters with the global charater
    Message := StrReplace(Message, ">", "\>") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "<", "\<") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "=", "\=") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "|", "\|") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "~", "\~") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "`", "\`") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "$", "\$") ; replace all new line characters with the global charater
    ; Message := StrReplace(Message, "%", "\%") ; replace all new line characters with the global charater
    Message := StrReplace(Message, "&", "\&") ; replace all new line characters with the global charater

    ; Msgbox % "replaced Message: " Message


    Return Message
}



; -------------------------------Discord Images-------------------------------
UploadImageToDiscord(Webhook, Message:="", Filepath:=""){

    filepath := [Filepath] ; Create object
    
    objParam := {file: filepath, content: Message}
    CreateFormData(PostData, hdr_ContentType, objParam)

    HTTP := ComObjCreate("WinHTTP.WinHTTPRequest.5.1")
    HTTP.Open("POST", Webhook, true)
    HTTP.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko")
    HTTP.SetRequestHeader("Content-Type", hdr_ContentType)
    HTTP.SetRequestHeader("Pragma", "no-cache")
    HTTP.SetRequestHeader("Cache-Control", "no-cache, no-store")
    HTTP.SetRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT")
    HTTP.Send(PostData)
    HTTP.WaitForResponse()
    ; msgbox % HTTP.ResponseText
    return HTTP.ResponseText
}
; -------------------------------/Discord Images-------------------------------


;---------------------------Discord Messages---------------------
UploadMessageToDiscord(Webhook, Message:=""){

    ; filepath := [Filepath] ; Create object

    objParam := {file: filepath, content: Message}
    CreateFormData(PostData, hdr_ContentType, objParam)

    HTTP := ComObjCreate("WinHTTP.WinHTTPRequest.5.1")
    HTTP.Open("POST", Webhook, true)
    HTTP.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko")
    HTTP.SetRequestHeader("Content-Type", hdr_ContentType)
    HTTP.SetRequestHeader("Pragma", "no-cache")
    HTTP.SetRequestHeader("Cache-Control", "no-cache, no-store")
    HTTP.SetRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT")
    HTTP.Send(PostData)
    HTTP.WaitForResponse()
    ; msgbox % HTTP.ResponseText
    return HTTP.ResponseText
}




;---------------------------/Discord Messages---------------------







; -------------------------------CreateFormData - Creates "multipart/form-data" for http post-------------------------------

; Used for WinHttp.WinHttpRequest.5.1, Msxml2.XMLHTTP ...
CreateFormData(ByRef retData, ByRef retHeader, objParam) {
    New CreateFormData(retData, retHeader, objParam)
}

; Used for WinInet
CreateFormData_WinInet(ByRef retData, ByRef retHeader, objParam) {
    New CreateFormData(safeArr, retHeader, objParam)

    size := safeArr.MaxIndex() + 1
    VarSetCapacity(retData, size, 1)
    DllCall("oleaut32\SafeArrayAccessData", "ptr", ComObjValue(safeArr), "ptr*", pdata)
    DllCall("RtlMoveMemory", "ptr", &retData, "ptr", pdata, "ptr", size)
    DllCall("oleaut32\SafeArrayUnaccessData", "ptr", ComObjValue(safeArr))
}

Class CreateFormData {

    __New(ByRef retData, ByRef retHeader, objParam) {

        CRLF := "`r`n"

        Boundary := this.RandomBoundary()
        BoundaryLine := "------------------------------" . Boundary

        ; Loop input paramters
        binArrs := []
        For k, v in objParam
        {
            If IsObject(v) {
                For i, FileName in v
                {
                    str := BoundaryLine . CRLF
                    . "Content-Disposition: form-data; name=""" . k . """; filename=""" . FileName . """" . CRLF
                    . "Content-Type: " . this.MimeType(FileName) . CRLF . CRLF
                    binArrs.Push( BinArr_FromString(str) )
                    binArrs.Push( BinArr_FromFile(FileName) )
                    binArrs.Push( BinArr_FromString(CRLF) )
                }
            } 
            Else {
                str := BoundaryLine . CRLF
                . "Content-Disposition: form-data; name=""" . k """" . CRLF . CRLF
                . v . CRLF
                binArrs.Push( BinArr_FromString(str) )
            }
        }

        str := BoundaryLine . "--" . CRLF
        binArrs.Push( BinArr_FromString(str) )

        retData := BinArr_Join(binArrs*)
        retHeader := "multipart/form-data; boundary=----------------------------" . Boundary
    }

    RandomBoundary() {
        str := "0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z"
        Sort, str, D| Random
        str := StrReplace(str, "|")
        Return SubStr(str, 1, 12)
    }

    MimeType(FileName) {
        n := FileOpen(FileName, "r").ReadUInt()
        Return (n        = 0x474E5089) ? "image/png"
        : (n        = 0x38464947) ? "image/gif"
        : (n&0xFFFF = 0x4D42    ) ? "image/bmp"
        : (n&0xFFFF = 0xD8FF    ) ? "image/jpeg"
        : (n&0xFFFF = 0x4949    ) ? "image/tiff"
        : (n&0xFFFF = 0x4D4D    ) ? "image/tiff"
        : "application/octet-stream"
    }

}
;#############################################################################################################
; Update: 2015-6-4 - Added BinArr_ToFile()

BinArr_FromString(str) {
    oADO := ComObjCreate("ADODB.Stream")

    oADO.Type := 2 ; adTypeText
    oADO.Mode := 3 ; adModeReadWrite
    oADO.Open
    oADO.Charset := "UTF-8"
    oADO.WriteText(str)

    oADO.Position := 0
    oADO.Type := 1 ; adTypeBinary
    oADO.Position := 3 ; Skip UTF-8 BOM
    return oADO.Read, oADO.Close
}

BinArr_FromFile(FileName) {
    oADO := ComObjCreate("ADODB.Stream")

    oADO.Type := 1 ; adTypeBinary
    oADO.Open
    oADO.LoadFromFile(FileName)
    return oADO.Read, oADO.Close
}

BinArr_Join(Arrays*) {
    oADO := ComObjCreate("ADODB.Stream")

    oADO.Type := 1 ; adTypeBinary
    oADO.Mode := 3 ; adModeReadWrite
    oADO.Open
    For i, arr in Arrays
    oADO.Write(arr)
    oADO.Position := 0
    return oADO.Read, oADO.Close
}

BinArr_ToString(BinArr, Encoding := "UTF-8") {
    oADO := ComObjCreate("ADODB.Stream")

    oADO.Type := 1 ; adTypeBinary
    oADO.Mode := 3 ; adModeReadWrite
    oADO.Open
    oADO.Write(BinArr)

    oADO.Position := 0
    oADO.Type := 2 ; adTypeText
    oADO.Charset  := Encoding 
    return oADO.ReadText, oADO.Close
}

BinArr_ToFile(BinArr, FileName) {
    oADO := ComObjCreate("ADODB.Stream")

    oADO.Type := 1 ; adTypeBinary
    oADO.Open
    oADO.Write(BinArr)
    oADO.SaveToFile(FileName, 2)
    oADO.Close
}
; -------------------------------/CreateFormData - Creates "multipart/form-data" for http post-------------------------------

; -------------------------------CheckDirExistAndCreate-------------------------------
; Check if directory exists and if not, create it
CheckDirExistAndCreate(Path){
    if(!FileExist(Path)){
        FileCreateDir, %Path%
    }
}
; -------------------------------/CheckDirExistAndCreate-------------------------------



CheckIfUpdateAvailable(Filepath, CurrentVersion){
    FileRead, ScriptUpdateContents, %Filepath%
    FileContents := StrSplit(ScriptUpdateContents, "ScriptVersion")
    FileContents := FileContents[2]
    FileContents := StrSplit(FileContents, "`n")
    UpdateVersion := FileContents[1]
    ; msgbox % UpdateVersion

    if(!InStr(UpdateVersion, CurrentVersion)){ ; Update found for file, write to settings.ini for next time script is run
        Message = Update Available to Download
        SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile")
        Return True
    }
    Return False
}



FindUpdateChangeLog(Filepath){
    FileRead, ScriptUpdateContents, %Filepath%

    ; Set Variables
    ChangelogStart =;---Changelog------------------------------------------------------
    ChangelogEnd =;---/Changelog------------------------------------------------------

    ; Msgbox % "ScriptUpdateContents: " ScriptUpdateContents
    ChangeLog := StrSplit(ScriptUpdateContents, ChangelogStart)
    ChangeLog := ChangeLog[2]
    ChangeLog := StrSplit(ChangeLog, ChangelogEnd)
    ChangeLog := ChangeLog[1]
    Return Changelog
}






CheckSeleniumDriver(){
    try Driver := SChrome_Get("", ChromeProfile := "")  ; open new tab page with with specified profile
    catch e {
        ShowSeleniumErrorMsgbox()
        ; Message = Failed to Make Connection to Chrome. Check for Any Open Dialogue Boxes or out of date ChromeDriver
        ; SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging")
        Return "Failed"
    }
    ; Driver := SChrome_Get("https://www.bitchute.com/", ChromeProfile)  ; open new tab page with with specified profile
    ; driver.executeScript("return document.readyState").equals("complete") ; wait until page loads completely before proceeding
    try driver.executeScript("return document.readyState").equals("complete") ; wait until page loads completely before proceeding
    catch e {
        ShowSeleniumErrorMsgbox()
        ; Message = Failed to send command to Chrome. Check for an Open Dialogue Box.
        ; SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging")
        Return "Failed"
    }
    DriverStatus := 1

    if(ReuseTabs)
    CreateArrayOfChromeTabs()


}

SeleniumConnectToActiveTab(IP_Port := "127.0.0.1:9222"){
    Driver := ComObjCreate("Selenium.ChromeDriver")
    Driver.SetCapability("debuggerAddress", IP_Port)
    try Driver.Start()
    catch e {
        ShowSeleniumErrorMsgbox()
        ; msgbox, failed to connect to Chrome for some reason.
        ; Message = Failed to Connect to Chrome for some reason.
        ; SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging")
    }
    return Driver
}

CreateArrayOfChromeTabs() {
    Message = Creating an Array of All Chrome Tabs
    SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile")

    ; Create an arrays
    DriverTitleArray := [] 
    ChromeTabsURLArray := []

    try TotalTabsFound := Driver.Windows.Count
    ; Message = TotalTabsFound: %TotalTabsFound%
    ; DevModeMsgBox(Message)
    ; DevModeMsgBox(TotalTabsFound)

/*    ; if only 1 tab exists, grab info, push to array and return
    if(TotalTabsFound = 1){
        try Title := Driver.Title
        try URL := Driver.URL

        if(Title != "")
        DriverTitleArray.Push(Title)
        if(URL != "")
        ChromeTabsURLArray.Push(URL)
        return
    }

    */
    ; Msgbox % "TotalTabsFound: " TotalTabsFound
    ; if(DevMode)
    ; Msgbox % "TotalTabsFound: " TotalTabsFound
    ; msgbox % "total Tabs:" Driver.Windows.Count
    ; Message = Creating an Array of Chrome Tabs
    ; SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile")

    ; StartTime := A_TickCount
    ; Sleep, 1000
    StartTime := A_TickCount



    ; 5 is arbitrary number to do some extra loops to make sure all tabs are gone through
    ; most likely not necessary because unloaded tabs cannot be activated
    TotalTabLoops := TotalTabsFound + 5
    ; Message = TotalTabLoops: %TotalTabLoops%
    ; DevModeMsgBox(message)

    Loop % TotalTabLoops {
        Message = Creating an Array of All Chrome Tabs`nCurrent Loop: %A_index%/%TotalTabLoops% (Cannot check on unloaded tabs)`nSometimes might get stuck for a short while if there is something loading in active tab
        TooltipThis(Message)

        ; exit after looping through 1 tab, if only 1 tab found in count
        if(TotalTabsFound = 1 AND A_index > TotalTabsFound){
            Message = Exiting Early after 1 loop
            DevModeMsgBox(message)
            break
        }
        

        TabEndTime :=  A_TickCount - TabFoundStartTime
        TabEndTimeArray .= TabEndTime . ","


        ; Message = Time to switch to new tab: %TabEndTime%`nCurrent Loop: %A_index%/%TotalTabsFound%
        ; SaveOrPostProgress(Message:=Message,PostType:="ErrorLoggingTextFile,DiscordErrorLogging")

        TabFoundStartTime := A_TickCount
        
        ; TimeToGrabCurrentTab := A_TickCount - StartTime
        ; Msgbox % "TimeToGrabCurrentTab: " TimeToGrabCurrentTab

        ; Stop page refresh if it's happening
        ; try driver.executeScript("return window.stop")

        try Title := Driver.Title
        try URL := Driver.URL

        ; TimeToGrabCurrentTab := A_TickCount - StartTime
        ; Msgbox % "TimeToGrabCurrentTab: " TimeToGrabCurrentTab
        ; VAR := HasVal(ChromeTabsURLArray, STRINGVAR)    ; returns position of value in array

/*
        if(HasVal(ChromeTabsURLArray, URL)){    ; returns position of value in array
            DevModeMsgBox("Skipping rest of loop and continuing")
           Continue
       }

       */


       if(Title != "")
       DriverTitleArray.Push(Title)
       if(URL != "")
       ChromeTabsURLArray.Push(URL)


       try driver.SwitchToNextWindow               ;Focuses Selenium on the newly opened/next window. 
       ; DevModeMsgBox("switching to next tab")
       } ; end of loop

       ; TimeToLoopThroughAllTabs := A_TickCount - StartTime
       ; Message = Time to Loop through all tabs: %TimeToLoopThroughAllTabs%
       ; SaveOrPostProgress(Message:=Message,PostType:="ErrorLoggingTextFile,DiscordErrorLogging")
       ; DevModeMsgBox(Message)

       return


   } 

   InputFilePathIntoOpenWindow(Filepath){
    ; Msgbox % "Filepath: " Filepath
    Message = Waiting for "Open" window to appear to input filepath into
    SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile")
    ; Tooltip,Waiting for "Open" window to appear to input filepath into,850,0
    ; WinWait, Open
    WinWait,Open,,5 ; Wait for 10 seconds for window
    if(ErrorLevel)
    {
        ; msgbox, failed to find window.
        Return "Failed"
    }
    WinActivate, Open
    sleep, 1000
    ControlSetText, Edit1, %Filepath%, Open
    sleep, 1000
    ControlSend, Edit1, {Enter}, Open
    sleep, 1000

    ; Do an extra check in case the Open window is still open.
    OpenWindowExist := WinExist("Open")
    if(OpenWindowExist)
    ControlSend, Edit1, {Enter}, Open
    ToolTip, 
}

; -------------------------------NavigateFromBaseURLTo-------------------------------
ExtractBaseURL(URL){
    URLBase := StrReplace(URL,"https://","") ; remove beginning of URL
    URLBase := StrReplace(URLBase,"http://","") ; remove beginning of URL
    URLBase := StrReplace(URLBase, "www.","") ; remove www if there 1
    URLBase := StrSplit(URLBase, "/") ; remove text after url base
    URLBase := URLBase[1]

    return URLBase
}


ActivateChromeTab(URL){
    ; convert to baseUR
    if(InStr(URL, "/")){
        URLBase := ExtractBaseURL(URL)
    }
    else, {
        URLBase := URL
    }


    Message = Finding Tab with URL base: %URLBase%
    SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile")
    DevModeMsgBox(Message)


    ; if not connected to selenium chrome, then re-connect
    if(!DriverStatus){
        Status := CheckSeleniumDriver()
        if(Status)
        Return "Failed"

        ; CreateArrayOfChromeTabs() ; moved to the end of checkseleniumdriver()
    }


    TabFoundSuccessfully := 

    NumberOfTabActivationLoops := ChromeTabsURLArray.Length()
    Message := "NumberOfTabActivationLoops: " NumberOfTabActivationLoops
    DevModeMsgBox(Message)

    ; NumberOfTabLoops := Driver.Windows.Count + 2
    loop %  NumberOfTabActivationLoops { ; loop through tabs to find matching tab
     try driver.SwitchToNextWindow()   

     ; sleep, 1000
     ; msgbox, looping through tabs
     try CurrentTabTitle := driver.window.title
     try CurrentTabURL := driver.Url

     if(InStr(CurrentTabURL, URLBase)){

        Message = Found Tab:.`n%CurrentTabTitle% = %PageTitle%`n%CurrentTabURL% = %URLBase%
        DevModeMsgBox(message)

        TabFoundSuccessfully := 1
        ; msgbox %CurrentTabTitle% = %PageTitle%
        ; msgbox %CurrentTabURL% = %URL%
        return
    }

    ; / loop through tabs 
}
return "Failed"
}

/*ActivateChromeTab(URL){



    ; ChromeTabsURLArray
    if(!HasSubstringVal(ChromeTabsURLArray, URLBase))    
    {
        try, run "%ChromeFilepath%" "%URL%"
        ChromeTabsURLArray.Push(URL)    ; Append the new url to the array
        NewTabCreated := 1
        sleep, 1000
    }
}


*/



NavigateFromBaseURLTo(URL,PageTitle := "TodoDeleteme"){
    if(!DriverStatus){ ; if not connected to selenium chrome, then re-connect
        Status := CheckSeleniumDriver()
        if(Status)
        Return "Failed"

        ; CreateArrayOfChromeTabs() ; moved to the end of checkseleniumdriver()
    }

    ; ArrayOfOpenTabsLength := ChromeTabsURLArray.Length()   ; Save total number of items in the array


    ; message = URL: %URL%
    ; DevModeMsgBox(message)

    URLBase := ExtractBaseURL(URL)


/*    if(ReuseTabs){ 
        URLBase := StrReplace(URL,"https://","") ; remove beginning of URL
        URLBase := StrSplit(URLBase, "/") ; remove text after url base
        URLBase := URLBase[1]
        URLBase := StrReplace(URLBase, "www.","") ; remove www if there 1
    }

    */
    ; Message = URLbase after cleaning: %URLBase%`nOriginal URL: %URL%
    ; DevModeMsgBox(message)

    ; if URLBase is NOT a substring within any of the values in the array
    if(!HasSubstringVal(ChromeTabsURLArray, URLBase))    
    {
        ; DevModeMsgBox("Creating new tab")
        try, run "%ChromeFilepath%" "%URL%"
        ChromeTabsURLArray.Push(URL)    ; Append the new url to the array
        NewTabCreated := 1
        sleep, 1000
    }

    message = NewTabCreated: %NewTabCreated%
    DevModeMsgBox(message)


    status := ActivateChromeTab(URLBase)
    message = ActivateChromeTab Status: %status%
    DevModeMsgBox(message)

    if(!NewTabCreated){ ; if re-using a tab then we want to re-navigate to URL because it might be the wrong page

        ; Double check that the current tab URL matches the url base
        try, CurrentTabURl := driver.url
        Message = Reusing Tab. `nCurrentTabURl: %CurrentTabURl%`nURL Navigating to: %URL%
        DevModeMsgBox(Message)


        try driver.Get(URL) ;Open selected URL
        catch e {
            Message = Failed to Navigate to URL in pre-existing tab`nPlease See Error #5648 for code section
            SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging")
            ; SaveDriverURLOFErrorPage()
            ; Return

            ; msgbox, error caught. trying something
            try driver.switchToalert().accept()
            try driver.Get(URL) ;Open selected URL
            catch e {
                Message = Failed to Navigate to %URL%: Please Check for Any Open Dialogue Boxes
                SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging")
                Return "Failed"
            }
        }
        try driver.executeScript("return document.readyState").equals("complete") ; wait until page loads completely before proceeding
    }
    ; msgbox, no error caught
    ; }


    Return
} 




; End of Function
; -------------------------------/NavigateFromBaseURL-------------------------------

SaveDriverURL(){ ; save the url of the result page. That way if a tab is not found for a site, we can open up a tab from this tab instead of middle of nowhere. That way we can keep the tabs together
    try LastWebsitePostURL := driver.URL

    return LastWebsitePostURL
}


; -------------------------------SChrome_Get-------------------------------
SChrome_Get(URL := "", Profile := "Profile 1", IP_Port := "127.0.0.1:9222"){
    IP_Port_Nr := RegExReplace(IP_Port, ".*:(\d*)", "$1")
    if WinExist("ahk_exe Chrome.exe"){
        WinGet, pid, PID, ahk_exe chrome.exe
        for item in ComObjGet("winmgmts:").ExecQuery("SELECT * FROM Win32_Process WHERE ProcessId='" pid "'"){
            if RegExMatch(item.CommandLine, "i)--remote-debugging-port=\K\d+", port){
                break
            }
        }

        if (Port=""){
            MsgBox, 36, ,Chrome Needs to be started in debugging mode in order for the Uploader to control it with Selenium.`nAutomatically restart Chrome in debug mode to enable a connection?
            IfMsgBox, Yes
            {
                Message = Restarting Chrome in Debug Mode
                SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging")

                While(WinExist("ahk_exe chrome.exe")) {
                    WinClose, ahk_exe chrome.exe
                }
                Process, WaitClose, chrome.exe
            }
            Else{
                Msgbox, 4096, Error, Cannot connect to Chrome profile if it is Not running in debug mode. Program Exiting
                ExitApp
                ; @todo: Make this error out to the script result screen
            }
        }
    }

    ; ; yuriy's settings
    ; IniRead, ChromeFilepath, C:\Users\%A_username%\Documents\Autohotkey\Lib\ScriptSettings.ini, Selenium, %A_Computername%, %A_Space%

    ; ; Establish Variable with Filepath to be used throughout the script
    ; if(ChromeFilepath = ""){
        if(FileExist("C:\Program Files\Google\Chrome\Application\chrome.exe")){
            ChromeFilepath = C:\Program Files\Google\Chrome\Application\chrome.exe
        }
        else if (FileExist("C:\Program Files (x86)\Google\Chrome\Application\chrome.exe")){
            ChromeFilepath = C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
        }


        if(ChromeFilepath = ""){
            Message = Failed to find chrome.exe in the usual locations.
            SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging")
            MsgBox 0x30, Error!, Unable to find Chrome.exe in the usual locations. `nScript Exiting. 
            ExitApp
        }

        if(!winExist("ahk_exe chrome.exe")){
            run, %ChromeFilepath% --remote-debugging-port=%IP_Port_Nr% %URL%
        }

        Driver := ComObjCreate("Selenium.ChromeDriver")
        Driver.SetCapability("debuggerAddress", IP_Port)
        try Driver.Start()
        catch e {

            ShowSeleniumErrorMsgbox()

            } ; end of catch

            ; Save current chrome version to ini file
            return Driver
        }
        ; -------------------------------/SChrome_Get-------------------------------

        ShowSeleniumErrorMsgbox(){
            GetChromeVersionCommand = powershell (Get-Item '%ChromeFilepath%').VersionInfo.ProductVersion
            Chromeversion := RunCMD(GetChromeVersionCommand)
            ChromeVersion := StrReplace(ChromeVersion, "`n", "")

            ; Clipboard := ChromeVersion
            ; Msgbox % "Chromeversion: " Chromeversion
            IniRead, PreviousWorkingChromeVersion, Settings.ini, Misc, ChromeVersion, %A_Space%
            ; IniWrite, %ChromeVersion%, Settings.ini, Misc, ChromeVersion
            ; msgbox, failed to connect to Chrome for some reason.
            ; Message = Failed to Connect to Chrome. Most likely problem is either Chrome has some sort of dialogue box open or ChromeDriver needs to be updated.
            ; SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging")

            OnMessage(0x44, "OnMsgBoxChromeDriverFailed")
            MsgBox 0x40043, Error, Failed to Connect to Chrome. `nMost likely issue is either Chrome has some sort of dialogue box open or ChromeDriver needs to be updated.`n`nClick "Reload" to reload the script to try again`nClick "ChromeDriver" to open up the ChromeDriver download page. `n`nClick "Instructions" to open up .pdf file with instructions for updating chromedriver.exe`n`nPossibly Helpful Info:`nCurrent Chrome Version: %Chromeversion%Chrome Version of Last Successfull Upload: %PreviousWorkingChromeVersion%
            OnMessage(0x44, "")

            IfMsgBox Yes, {
                ; Reload script
                Reload
                } Else IfMsgBox No, {
                    run, https://chromedriver.chromium.org/downloads
                    ExitApp
                    ; open chromedriver site
                    } Else IfMsgBox Cancel, {
                        URL = https://freedomainplaylists.com/wp-content/FreedomainScripts/Update`%20Selenium`%20ChromeDriver.pdf
                        Filepath = %A_ScriptDir%\Lib\Update Selenium ChromeDriver.pdf
                        if(!FileExist(Filepath)){
                            UrlDownloadToFile, %URL%, %Filepath%

                            run, %Filepath%
                        }
                        ExitApp

                    }
                }


                ; -------------------------------HasVal-------------------------------
                ; Function needed for finding a value in an array
                HasVal(haystack, needle)
                {
                    if !(IsObject(haystack)) || (haystack.Length() = 0)
                    return 0
                    for index, value in haystack
                    if (value = needle)
                    return index
                    return 0
                }
                ; -------------------------------/HasVal-------------------------------

                HasSubstringVal(haystack, needle)
                {
                    if !(IsObject(haystack)) || (haystack.Length() = 0)
                    return 0
                    for index, value in haystack
                    if (InStr(value, Needle))
                    return index
                    return 0
                }

                ; SubStr(String, StartingPos [, Length])

                ; InStr(value, Needle)






                ; -------------------------------FileXPro Get File Attributes-------------------------------
                ;https://www.autohotkey.com/boards/viewtopic.php?t=59882

                Filexpro( sFile := "", Kind := "", P* ) {           ; v.90 By SKAN on D1CC @ goo.gl/jyXFo9
                    Local
                    Static xDetails 

                    If ( sFile = "" )
                    {                                                           ;   Deinit static variable
                        xDetails := ""
                        Return
                    }

                    fex := {}, _FileExt := "" 

                    Loop, Files, % RTrim(sfile,"\*/."), DF 
                    {
                        If not FileExist( sFile:=A_LoopFileLongPath )
                        {
                          Return
                      } 

                      SplitPath, sFile, _FileExt, _Dir, _Ext, _File, _Drv

                      If ( p[p.length()] = "xInfo" )                          ;  Last parameter is xInfo 
                      {
                          p.Pop()                                           ;         Delete parameter
                          fex.SetCapacity(11)                               ; Make room for Extra info
                          fex["_Attrib"]    := A_LoopFileAttrib
                          fex["_Dir"]       := _Dir
                          fex["_Drv"]       := _Drv
                          fex["_Ext"]       := _Ext
                          fex["_File"]      := _File
                          fex["_File.Ext"]  := _FileExt
                          fex["_FilePath"]  := sFile
                          fex["_FileSize"]  := A_LoopFileSize
                          fex["_FileTimeA"] := A_LoopFileTimeAccessed
                          fex["_FileTimeC"] := A_LoopFileTimeCreated
                          fex["_FileTimeM"] := A_LoopFileTimeModified
                      }              
                      Break            
                  }

                  If Not ( _FileExt )                                   ;    Filepath not resolved
                  {
                    Return
                }        


                objShl := ComObjCreate("Shell.Application")
                objDir := objShl.NameSpace(_Dir) 
                objItm := objDir.ParseName(_FileExt) 

                If ( VarSetCapacity(xDetails) = 0 )                           ;     Init static variable
                {
                    i:=-1,  xDetails:={},  xDetails.SetCapacity(309)

                    While ( i++ < 309 )
                    {
                        xDetails[ objDir.GetDetailsOf(0,i) ] := i
                    } 

                    xDetails.Delete("")
                }

                If ( Kind and Kind <> objDir.GetDetailsOf(objItm,11) )        ;  File isn't desired kind  
                {
                    Return
                }

                i:=0,  nParams:=p.Count(),  fex.SetCapacity(nParams + 11) 

                While ( i++ < nParams )
                {
                    Prop := p[i]

                    If ( (Dot:=InStr(Prop,".")) and (Prop:=(Dot=1 ? "System":"") . Prop) )
                    {
                      fex[Prop] := objItm.ExtendedProperty(Prop)
                      Continue 
                  }

                  If ( PropNum := xDetails[Prop] ) > -1
                  {
                      fex[Prop] := ObjDir.GetDetailsOf(objItm,PropNum)
                      Continue 
                  }  
              }

              fex.SetCapacity(-1)
              Return fex  

              } ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



              ; GuiButtonIcon
              ;------------------------------------------------
              GuiButtonIcon(Handle, File, Index := 1, Options := "")
              {
                RegExMatch(Options, "i)w\K\d+", W), (W="") ? W := 16 :
                RegExMatch(Options, "i)h\K\d+", H), (H="") ? H := 16 :
                RegExMatch(Options, "i)s\K\d+", S), S ? W := H := S :
                RegExMatch(Options, "i)l\K\d+", L), (L="") ? L := 0 :
                RegExMatch(Options, "i)t\K\d+", T), (T="") ? T := 0 :
                RegExMatch(Options, "i)r\K\d+", R), (R="") ? R := 0 :
                RegExMatch(Options, "i)b\K\d+", B), (B="") ? B := 0 :
                RegExMatch(Options, "i)a\K\d+", A), (A="") ? A := 4 :
                Psz := A_PtrSize = "" ? 4 : A_PtrSize, DW := "UInt", Ptr := A_PtrSize = "" ? DW : "Ptr"
                VarSetCapacity( button_il, 20 + Psz, 0 )
                NumPut( normal_il := DllCall( "ImageList_Create", DW, W, DW, H, DW, 0x21, DW, 1, DW, 1 ), button_il, 0, Ptr )   ; Width & Height
                NumPut( L, button_il, 0 + Psz, DW )     ; Left Margin
                NumPut( T, button_il, 4 + Psz, DW )     ; Top Margin
                NumPut( R, button_il, 8 + Psz, DW )     ; Right Margin
                NumPut( B, button_il, 12 + Psz, DW )    ; Bottom Margin 
                NumPut( A, button_il, 16 + Psz, DW )    ; Alignment
                SendMessage, BCM_SETIMAGELIST := 5634, 0, &button_il,, AHK_ID %Handle%
                return IL_Add( normal_il, File, Index )
            }

            ; \GuiButtonIcon
            ;------------------------------------------------


            ToggleTestingMode(){

                IniRead, TestingMode, Settings.ini, General, TestingMode, 0
                ; Msgbox % "TestingMode: " TestingMode
                if(TestingMode)
                IniWrite, 0, Settings.ini, General, TestingMode
                else, 
                IniWrite, 1, Settings.ini, General, TestingMode
            }

            ToggleManualSubmit(){

                IniRead, ManualSubmit, Settings.ini, General, ManualSubmit, 0
                ; Msgbox % "TestingMode: " TestingMode
                if(ManualSubmit)
                IniWrite, 0, Settings.ini, General, ManualSubmit
                else, 
                IniWrite, 1, Settings.ini, General, ManualSubmit
            }


            ToggleDevMode(){

                IniRead, DevMode, Settings.ini, General, DevMode, 0
                ; Msgbox % "TestingMode: " TestingMode
                if(DevMode)
                IniWrite, 0, Settings.ini, General, DevMode
                else, 
                IniWrite, 1, Settings.ini, General, DevMode
            }


            FormatTextToJSText(Var){ ; Replaces AHK newline characters with javascript ones
/*\b  Backspace
\f  Form Feed
\n  New Line - done
\r  Carriage Return 
\t  Horizontal Tabulator
\v  Vertical Tabulator
\'  Single quote - done
\"  Double quote - done
\\  Backslash - done
*/

SingleQuotationmark = "
; Variable of Escaped Symbols
EscapedSingleQuote = \'
EscapedDoubleQuote = \"
EscapedBackslash = \\
EscapedNewLine = \n

; Replace each character that needs replacing in the text string
Var := StrReplace(Var, "\", EscapedBackslash)  ; needed otherwise selenium will error out
Var := StrReplace(Var, "`n", EscapedNewLine)    ; needed otherwise selenium will error out
Var := StrReplace(Var, "`r", "")  ; needed otherwise selenium will error out
Var := StrReplace(Var, SingleQuotationmark, EscapedDoubleQuote)  ; needed otherwise selenium will error out
Var := StrReplace(Var, "'", EscapedSingleQuote)  ; needed otherwise selenium will error out
; Var := StrReplace(Var, "`r", "")  ; needed otherwise selenium will error out
Return Var
}



; OnMsgbox Functions
;------------------------------------------------
OnMsgBoxUpdateAvailable() {
    DetectHiddenWindows, On
    Process, Exist
    If (WinExist("ahk_class #32770 ahk_pid " . ErrorLevel)) {
        ControlSetText Button1, Cancel
        ControlSetText Button2, Install
    }
}


OnMsgBoxChromeDriverFailed() {
    DetectHiddenWindows, On
    Process, Exist
    If (WinExist("ahk_class #32770 ahk_pid " . ErrorLevel)) {
        WinMove,, 0
        ControlSetText Button1, Reload Script
        ControlSetText Button2, ChromeDriver
        ControlSetText Button3, Instructions
    }
}


SaveCurrentChromeVersionToIniFile(){

    ; Msgbox % "ChromeFilepath: " ChromeFilepath
    GetChromeVersionCommand = powershell (Get-Item '%ChromeFilepath%').VersionInfo.ProductVersion
    Chromeversion := RunCMD(GetChromeVersionCommand)
    if(InStr(ChromeVersion, "scripts is disabled on this system")){
        ChromeVersion = Not Able to Grab Because: "scripts are disabled in powershell"
    }
    ; Msgbox % "Chromeversion: " Chromeversion

    ; Msgbox % "Chromeversion: " Chromeversion


    if(ChromeFilepath = "")
    return

    ; Chromeversion := StrSplit(Chromeversion, "`n")
    ; Chromeversion := Chromeversion[4]
    IniWrite, %ChromeVersion%, Settings.ini, Misc, ChromeVersion
}


SaveDriverURLOFErrorPage(){ ; save the url of the result page. That way if a tab is not found for a site, we can open up a tab from this tab instead of middle of nowhere. That way we can keep the tabs together
    try URLOfLastErrorPage := driver.URL
}

