[CmdletBinding()]
Param(
    [Parameter(Position = 0, Mandatory = $true, HelpMessage = "Enter the event rule name")]
    [string] $EventRuleName = "asd",

    [Parameter(Position = 1, Mandatory = $false, HelpMessage = "Enter a host name or IP address")]
    [String] $EFTHost = "https://localhost:4433",

    [Parameter(Position = 2, Mandatory = $false, HelpMessage = "Enter login")]
    [String] $EFTAdminUsername = "admin",

    [Parameter(Position = 3, Mandatory = $false, HelpMessage = "Enter password")]
    [String] $Password = "Super2003"
)
$SchedulerQueuePath = "C:\temp\Scheduler"
$SchedulerQueueResponse = "$SchedulerQueuePath\response\$EventRuleName\"
$SchedulerQueueHistory = "$SchedulerQueuePath\history\$EventRuleName\"
$sw = [Diagnostics.Stopwatch]::StartNew()
$MAX_TIMEOUT = 1000 * 30
$WAIT_SECONDS = 2

Enum ResultCodes {
    UnhandledException = -1
    Success = 0
    ErrorInvokingWebService = 1
    UnkownResponse = 2
    EventRuleNotFound = 3
    FailureInvokingEventRule = 4
    ResponseTimeout = 5
    FilesWithErrors = 6
}

$customWebclientCode = @"
using System.Net;
public class CustomWebclientCode : WebClient {
    public int TimeoutSeconds;
    protected override WebRequest GetWebRequest(System.Uri address) {
        WebRequest request = base.GetWebRequest(address);
        if (request != null) { request.Timeout = TimeoutSeconds * 1000; }
        return request;
    }
    public CustomWebclientCode() {
        TimeoutSeconds = 300; // Timeout value by default
    }
}
"@

## Private Functions
function Invoke-EventRule($responsePath) {
    $output = ""
    $url = "$EFTHost/WebService/InvokeEventRule?EventRuleName=$EventRuleName&EventParams=VAR.RESPONSE_PATH=$responsePath"
    $webclient = New-Object CustomWebclientCode
    $credCache = new-object System.Net.CredentialCache
    #Setting timeout to 900 seconds
    $webclient.TimeoutSeconds = 900
    $creds = new-object System.Net.NetworkCredential($EFTAdminUsername, $Password)
    $credCache.Add($url, "Basic", $creds)
    $webclient.Credentials = $credCache
    [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
    try {
        $output = $webclient.DownloadString($url)
        [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $null
    }
    catch {
        Write-Error "Error Calling EFT Web Service $_"
        $returnCode = [ResultCodes]::ErrorInvokingWebService
    }

    try {
        $xml = New-Object -TypeName System.Xml.XmlDocument
        $xml.LoadXml($output)
        switch ($xml.int.Innertext) {
            "1" { $returnCode = [ResultCodes]::Success}
            "-1" { $returnCode = [ResultCodes]::EventRuleNotFound}
            "0" { $returnCode = [ResultCodes]::FailureInvokingEventRule}
            default { $returnCode = [ResultCodes]::UnkownResponse}
        }
    }
    catch {
        Write-Error "Error parsing Web Service result $_"
        $returnCode = [ResultCodes]::UnkownResponse
    }
    return $returnCode, $output
}
function Wait-File ($path) {
    $fileReady = $false
    $sw.Restart()

    while ($sw.ElapsedMilliseconds -le $MAX_TIMEOUT) {
        if (test-path $path) {
            $fileReady = $true
            break
        }
        Start-Sleep $WAIT_SECONDS
    }
    $sw.Stop()
    if (!($fileReady)) {
        return [ResultCodes]::ResponseTimeout
    }
    else {
        return [ResultCodes]::Success
    }
}

function Exec-Query( $sql, $parameters = @{}, $conn, $timeout = 30, [bool]$Wait = $false) {

    $cmd = new-object system.Data.SqlClient.SqlCommand($sql, $conn)
    $cmd.CommandTimeout = $timeout
    foreach ($p in $parameters.Keys) {
        [Void] $cmd.Parameters.AddWithValue("@$p", $parameters[$p])
    }
    $ds = New-Object system.Data.DataSet
    $da = New-Object system.Data.SqlClient.SqlDataAdapter($cmd)

    # Query DB until results are found

    if (!($Wait)) {
        $da.fill($ds) | Out-Null
        return [ResultCodes]::Success, $ds
    }

    #Query and wait for data
    $dataReady = $false
    $sw.Restart()
    while ($sw.ElapsedMilliseconds -le $MAX_TIMEOUT) {
        $da.fill($ds) | Out-Null

        if ($null -ne $ds.Tables[0] -and $ds.Tables[0].Rows.Count -ge 1) {
            $dataReady = $true
            break
        }
        Start-Sleep $WAIT_SECONDS
    }
    $sw.Stop()
    if (!($dataReady)) {
        return [ResultCodes]::ResponseTimeout, $null
    }
    else {
        return [ResultCodes]::Success, $ds
    }
}


## Main
Add-Type -TypeDefinition $customWebclientCode -Language CSharp
$returnCode = [ResultCodes]::Success

$RequestID = [guid]::NewGuid()
write-host "RequestID: $RequestID"
$responsePath = "$SchedulerQueueResponse\$RequestID"

## Invoke EFT Event Rule
$output = Invoke-EventRule $responsePath
$returnCode = $output[0]

#Exit if Error
if ($returnCode -ne [ResultCodes]::Success) {
    return $returnCode
}

## Wait until response is ready
$returnCode = Wait-File $responsePath

#Exit if Error
if ($returnCode -ne [ResultCodes]::Success) {
    return $returnCode
}

$EventTransactionId = ""
# retrive the content of the transaction
$EventTransactionId = get-content $responsePath
Write-host "EventTransactionId: $EventTransactionId"

## Query for Files transfers
$sqlConn = New-Object System.Data.SqlClient.SqlConnection
$sqlConn.ConnectionString = "Server=GS0334;Integrated Security=true;Initial Catalog=EFTDB"

$sqlConn.Open()
$result = exec-query 'select * from tbl_Transactions  WHERE TransactionGUID = @EventTransactionId' -parameter @{EventTransactionId = $EventTransactionId} -conn $sqlConn  -Wait $true

$returnCode = $result[0]
if ($returnCode -ne [ResultCodes]::Success) {
    return $returnCode
}
$data = $result[1]
$transactionID = $data.tables[0].TransactionID

Write-host "transactionID: $transactionID"

$result = exec-query 'Select * from tbl_Actions where TransactionID = @TransactionID' -parameter @{TransactionID = $transactionID} -conn $sqlConn

$returnCode = $result[0]
if ($returnCode -ne [ResultCodes]::Success) {
    return $returnCode
}
$actionTransactions = $result[1]

Write-host "Actions"
$actionTransactions.tables[0] | Format-Table

Write-host "Client Operations"
$transferTransactions = exec-query 'select * from tbl_ClientOperations where TransactionID = @TransactionID' -parameter @{TransactionID = $transactionID} -conn $sqlConn
$transferTransactions.tables[0] | Format-Table 

foreach ($row in $transferTransactions.tables[0].Rows){
    if ($row.ResultID -ne 1 )
    {
        $returnCode = [ResultCodes]::FilesWithErrors
    }
}

if ($returnCode -ne [ResultCodes]::Success) {
    return $returnCode
}

$sqlConn.Close()

## Move the response to history
if (!(Test-path $SchedulerQueueHistory)) {
    New-Item -ItemType directory -Path $SchedulerQueueHistory
}
$ArchivePath = "$SchedulerQueueHistory$RequestID"
Move-Item $responsePath $ArchivePath

$returnCode