#############
#
# Auteur : Hubert Cornet
# date   : 13 avril 2022
#
# description du script : intérroge l'API d'OPCON
#
#############    

# Variable et argment dans le lancement du script
Param(
	[string] $OpScheduleDate = "",
    [string] $OpJobStatus = "",
    [string] $OpConUser = "ocadm",
	[string] $OpConPassword,
    [string] $ServerUrl = "https://10.78.56.27:443"
    )

clear

# Fonction
Function Ignore-SelfSignedCerts {
    add-type -TypeDefinition  @"
        using System.Net;
        using System.Security.Cryptography.X509Certificates;
        public class TrustAllCertsPolicy : ICertificatePolicy {
            public bool CheckValidationResult(
                ServicePoint srvPoint, X509Certificate certificate,
                WebRequest request, int certificateProblem) {
                return true;
            }
        }
"@
    [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
}

#
Function Invoke-OpConRestMethod {
    Param(
        [ValidateNotNullorEmpty()]
        [String]$Uri,
        [ValidateNotNullorEmpty()]
        [String]$Method,
        [object]$Body = $null
    )

    If (!$Global:OpconRESTApiUrl -or !$Global:OpconRESTApiAuthHeader) {
        Write-Warning "No values for Opcon REST Api.  Please use Logon-OpConApi before using cmdlet."
        throw [System.Exception] "Invalid OpCon REST API Values"
    }

    $uri = $Global:OpconRESTApiUrl + $Uri

    Write-Verbose ("Envoi de la requete Web ...")

    Try {
        If ($Body -eq $null) {
            $response = Invoke-RestMethod -Method $Method -Uri $uri -Headers $Global:OpconRESTApiAuthHeader -ErrorVariable $RestException
        }
        Else {
            $Body = ConvertTo-Json $Body -Depth 99
            $response = Invoke-RestMethod -Method $Method -Uri $uri -Headers $Global:OpconRESTApiAuthHeader -Body $Body -ContentType 'application/json; charset=utf-8' -ErrorVariable $RestException 
        }
        Write-Verbose ("`n")
        Write-Verbose("RESPONSE :")
        Write-Verbose(ConvertTo-Json $response -Depth 9)
        return $response
    }
    Catch {
        Write-Warning ("Erreur")
        Write-Warning ("Status Code : " + $_.Exception.Response.StatusCode.value__)
        Write-Warning ("Status Description : " + $_.Exception.Response.StatusDescription)
        $opconApiError = ConvertFrom-Json $_.ErrorDetails.Message
        Write-Warning ("Erreur Code : " + $opconApiError.code)
        Write-Warning ("Erreur Message : " + $opconApiError.message)
        throw
        ##exit $_.Exception.Response.StatusCode.value__
    }
}

#
Function Get-OpConApiToken {
    [cmdletbinding()]
    Param(
        [string] $Url,
        [string] $User,
        [string] $Password
    )

    $tokensUri = -join($Url, "/api/tokens")
    Write-Host ("Recuperation du token autorisation ...")
    Write-Host ("Api: " + $tokensUri)
    Write-Host ("Utilisateur: " + $User)
    $tokenObject = @{
        user = @{
            loginName = $User
            password = $Password
        }
        tokenType = @{
            type = "User"
        }
    }
    Try {
        Ignore-SelfSignedCerts
        $token = Invoke-RestMethod -Method Post -Uri $tokensUri -Body (ConvertTo-Json $tokenObject) -ContentType 'application/json; charset=utf-8' -ErrorVariable $RestException 
    }
    Catch {
        ## $error = ConvertFrom-Json $RestException.ErrorDetails.Message
        ##Write-Host ("Unable to fetch token for user '" + $user + "'")
        ##Write-Host ("Error Code: " + $error.code)
        ##Write-Host ("Message: " + $error.message)
        Write-Host ("Status Code : " + $_.Exception.Response.StatusCode.value__)
        Write-Host ("Status Description : " + $_.Exception.Response.StatusDescription)
        Write-Host ("Message : " + $_[0].message)
        ##$Global:OpConRESTAPIException = $_
        throw
        ##exit $_.Exception.Response.StatusCode.value__
    }
    Write-Host ("Token recu avec succes, Id : " + $token.id + ", Valide jusqu a : " + $token.validUntil)

    return $token
}

#
Function Get-OpConApiAuthHeader {
    Param(
        [string] $Token
    )

    $authHeader = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
    $authHeader.Add("Authorization", ("Token " + $Token))

    return $authHeader
}

#
Function Login-RestApi {
    [cmdletbinding()]
    Param(
        [string] $ApiUrl,
        [string] $OpConUser,
        [string] $OpConPassword
    )

    Write-Verbose ("Parametres =")
    Write-Verbose ("ApiUrl: " + $ApiUrl)
    Write-Verbose ("OpConUser: " + $OpConUser)
    Write-Verbose ("OpConPassword: (hidden)")

    $ApiUrl = $ApiUrl.ToLower().TrimEnd("/").TrimEnd("/api")

    Write-Host ("Connexion a OPCON REST API: " + $ApiUrl)

    $Global:OpconRESTApiUrl = $ApiUrl
    $Global:OpconRESTApiUser = $OpConUser
    $Global:OpConRESTApiPassword = $OpConPassword
    $token = Get-OpConApiToken -Url $ApiUrl -User $OpConUser -Password $OpConPassword
    $Global:OpconRESTApiToken = $token.id

    $Global:OpconRESTApiAuthHeader = Get-OpConApiAuthHeader -Token $token.id
    
    Write-Host ('Token stocke avec succes pour de futurs appels dans la session.')
} 

Function HistoryJobDay {
    [cmdletbinding()]
    Param(
        [string] $Dates,
        [string] $JobName
    )
    
    $JobDayListFull = New-Object System.Collections.Generic.List[System.Object]

    Try {
        #$JobName = "PlanDeProdRéel_C1-60MinutesAprèsMidi_CNT[C1-SS-FR-FluxAX_DHB_AttARV_Prod]|C2-DHB_DAX_DHB_REF_OFR_ART_CFG-STB-DHB"
        #$JobName = ""
        #$Dates   = "2022-04-20"
        
        #$jobNameParam = [System.Web.HttpUtility]::UrlEncode($jobName)
        $jobUri = -join("/api/jobhistories?uniqueJobIds=$jobName&from=$Dates&to=$Dates")
        #write-host "1 " $jobUri

        $uri = $Global:OpconRESTApiUrl + $jobUri
        #write-host "2 " $uri

        #$jobdayResponse = Invoke-OpConRestMethod -Uri $jobUri -Method GET -ContentType "application/json"-Headers $Global:OpconRESTApiAuthHeader -ErrorVariable $RestException; 
        $jobdayResponse = Invoke-RestMethod -Method GET -Uri $uri -Headers $Global:OpconRESTApiAuthHeader -ContentType 'application/json' -ErrorVariable $RestException
        #write-host "3 " $jobdayResponse.id
        
        #https://10.78.56.27/api/jobhistories?uniqueJobIds=$JobName&from=$Dates&to=$Dates
        #https://10.78.56.27/api/jobhistories?uniqueJobIds=PlanDeProdR%C3%A9el_C1-60MinutesApr%C3%A8sMidi_CNT%5BC1-SS-FR-FluxAX_DHB_AttARV_Prod%5D%7CC1-DHB_DAX_DHB_DAX_DHB_CMC_SUV_LIG_CDE_CLI-STB-DHB&from=2022-04-13&to=2022-04-13
        #https://10.78.56.27/api/jobhistories?uniqueJobIds=PlanDeProdRéel_C1-60MinutesAprèsMidi_CNT[C1-SS-FR-FluxAX_DHB_AttARV_Prod]|C1-DHB_DAX_DHB_DAX_DHB_CMC_SUV_LIG_CDE_CLI-STB-DHB&from=2022-04-13&to=2022-04-13
        #https://10.78.56.27/api/jobhistories?uniqueJobIds=C9-SC-GRP-EXP-ReportingOpcon_C9-ExtractionDesCommandesAvecUneLivraisonEnJPlus1-CNT-EXP[C9-SS-FR-TSM-EXP-ExtractionCommandJPlus1]|C9-ArchiveExtraction-SQL-EXP&from=2022-04-13&to=2022-04-13
        
        If (($jobdayResponse.Length -Ne 1) -And ($jobdayResponse.Length -Ne 0)) { 
            Foreach($JobDay in $JobDayResponse) {
                #write-host $JobDay
                #$entry= "$($JobDay.schedule.name) - $($JobDay.id)"
                $JobDayListFull.Add($JobDay)
                #$JobDayListFull.Add(@{id = $JobDay.id})
                #Write-Host ("Job name : $($JobDay.id)")
            }
            
            $sizeDay = $jobdayResponse.Length;
            $JobDayListFullsize = $JobDayListFull.Count
            Write-Host ("Partiel/Total nombre de job recuperer : $sizeDay/$JobDayListFullsize")
        }
    }
    Catch [Exception] {
        write-host $_
        write-host $_.Exception.Message
    }
    return, $JobDayListFull 
}

Function GetJobListToUpdateInTrances {
    [cmdletbinding()]
    Param(
        [string] $Status,
        [string] $Dates,
        [string] $JobType
    )

    $offset =0; # start from 
    $size=0; # number of jobs retrieved each call
    $limit=5000; # max number of record x trance
    $jobListFull = New-Object System.Collections.Generic.List[System.Object]

    Write-Host ("===> Commence a recuperer des jobs dans la limite de $limit ")
        
    Do{
        $jobUri = -join("/api/dailyJobs/?dates=$Dates&scheduleIds=$($daily.id)&status=$Status&jobType=$JobType&limit=$limit&offset=$offset")
        #$jobUri = -join($Url, "/api/dailyJobs/?dates=$Dates&scheduleIds=$($daily.id)&status=$Status&jobType=$JobType&limit=$limit&offset=$offset")
        #$jobUri = -join($Url, "/api/dailyJobs/?dates=$Dates&scheduleIds=$($daily.id)&jobType=$JobType&limit=$limit&offset=$offset")

         $jobResponse = Invoke-OpConRestMethod -Uri $jobUri -Method GET -ContentType "application/json"-Headers $Global:OpconRESTApiAuthHeader -ErrorVariable $RestException; 
        #Write-Host ("Job URI : $($jobUri)")
                       
        Foreach($job in $jobResponse) {
            #$entry= "$($job.schedule.name) - $($job.id)"
            $jobListFull.Add($job)
            #$jobListFull.Add(@{id = $job.id})
            #Write-Host ("Job name : $($job.id)")
        }
            
        $size = $jobResponse.Length;
        $jobListFullsize = $jobListFull.Count
        Write-Host ("Partiel/Total nombre recuperer : $size/$jobListFullsize")

        $offset+=$limit;
        If ($size -lt $limit) {
            $size = 0;
        }

        # If is necessary a delay between calls uncomment and tune the line below
        # Start-Sleep -s 5
    }While ($size -gt 0)

    If ($jobListFull.Count -gt 0) {
        Write-host ("Jobs total recuperer : $($jobListFull.Count)")
    }
		
    return,   $jobListFull      
}

#
Function TryParseDate {
    [cmdletbinding()]
    Param(
       [object] $inDate,
       [string] $format
    )

    $outDate = ""
    Try {
        $outDate =[datetime]::parseexact($($inDate), $($format),$null)
    }
    Catch {
        $outDate = "?"
    }

    return $outDate
} 

#
Function DisplayDailyJobs {
    [cmdletbinding()]
    Param(
        [string] $Status,
        [string] $Action,
        [string] $Dates,
        [string] $JobType
    )

    [int]$Rows                 = 0
    [int]$RowsOK               = 0
    [int]$RowsCancelled        = 0
    [int]$RowsSkipped          = 0
    [int]$RowsFailed           = 0
    [int]$RowsRun              = 0
    [int]$Percentage_Ok        = 0
    [int]$Percentage_Skipped   = 0
    [int]$Percentage_Cancelled = 0
    [int]$Percentage_Failed    = 0
    [int]$Percentage_Run       = 0
    [int]$RowsStartRetard      = 0
    [int]$RowsEndRetard        = 0

    #Get job list to update in trances
    $jobList = GetJobListToUpdateInTrances -Status $Status -Dates $Dates -JobType $JobType

    #$lst  = jobList.chunked(3)
    [int]$Total = $jobList.Count

    Foreach($job in $jobList) {
        [int]$Rows = [int]$Rows + 1
        [int]$Pourcentage =[int]$Rows * 100 / [int]$Total

        Write-Progress -Activity "Analyse du contenu OPCON pour la journée $Dates" -Status "Job : $Rows sur $Total :" -PercentComplete $Pourcentage

        #$dt = [datetime]::parseexact($($job.schedule.date), 'yyyy-MM-ddTHH:mm:ss.fffffffzzz',$null)
        $dt = TryParseDate -inDate $job.schedule.date -format  'yyyy-MM-ddTHH:mm:ss.fffffffzzz' 
        $StartTimeProgrammed = TryParseDate -inDate $job.computedStartTime.ProgrammedFor -format 'yyyy-MM-ddTHH:mm:ss.fffffffzzz'

        $StartTimeTime =TryParseDate -inDate $job.computedStartTime.time -format 'yyyy-MM-ddTHH:mm:ss.fffffffzzz'
        $StartTimeTimeEstimated = ""

        If ($job.computedStartTime.isEstimated -contains "True") {
            $StartTimeTimeEstimated =  "*"
        }

        $EndTimeProgrammed = TryParseDate -inDate $job.computedEndTime.ProgrammedFor -format 'yyyy-MM-ddTHH:mm:ss.fffffffzzz'
        $EndTimeTime = TryParseDate -inDate $job.computedEndTime.time -format 'yyyy-MM-ddTHH:mm:ss.fffffffzzz'
        $EndTimeTimeEstimated = ""

        If ($job.computedEndTime.isEstimated -contains "True") {
            $EndTimeTimeEstimated =  "*"
        }

        $DurationEstimated = ""

        If ($job.computedDuration.isEstimated -contains "True") {
            $DurationEstimated =  "*"
        }

        $DateStr = $dt.ToString("dd/MM/yyyy")
            
        $htmlCellStyle =  ""
        If ($job.status.description -Contains "Failed") {
            $htmlCellStyle =  "style='background:#FF0000'"
            $RowsFailed = $RowsFailed + 1
        }
        ElseIf ($job.status.description -Contains "Skipped") {
            $htmlCellStyle =  "style='background:#F000FF'"
            $RowsSkipped = $RowsSkipped + 1
        }
        ElseIf ($job.status.description -Contains "Cancelled") {
            $htmlCellStyle =  "style='background:#0017FF'"
            $RowsCancelled = $RowsCancelled + 1
        }
        ElseIf ($job.status.description -Contains "Job Running") {
            $htmlCellStyle =  "style='background:#000000;color:white'"
            $RowsRun = $RowsRun + 1
        }
        Else {
            $RowsOK = $RowsOK + 1
        }

        $htmlCellStyleStartRetard =  ""
        $htmlCellStyleEndRetard =  ""

        If ($job.status.description -NotContains "Skipped") {
            If ($StartTimeTime -NotContains "?") {
            
                $RetardStart = New-TimeSpan -start $StartTimeTime -End $StartTimeProgrammed
                $RetardEnd   = New-TimeSpan -start $EndTimeTime -End $EndTimeProgrammed
    
                $htmlCellStyleStartRetard =  ""
                If ($RetardStart.TotalMinutes -lt 0  ) {
                    $htmlCellStyleStartRetard =  "style='background:#C3D50F'"
                }
                ElseIf ($RetardStart.TotalMinutes -eq 0  ) {
                    $htmlCellStyleStartRetard =  ""
                }
                ElseIf ($RetardStart.TotalMinutes -gt 0  ) {
                    $htmlCellStyleStartRetard =  "style='background:#0FD536'"
                    $RowsStartRetard = $RowsStartRetard + 1
                }
                Else {
                    $htmlCellStyleStartRetard =  ""
                }

                $htmlCellStyleEndRetard =  ""
                If ($RetardEnd.TotalMinutes -lt 0  ) {
                    $htmlCellStyleEndRetard =  "style='background:#C3D50F'"
                }
                ElseIf ($RetardEnd.TotalMinutes -eq 0  ) {
                    $htmlCellStyleEndRetard =  ""
                }
                ElseIf ($RetardEnd.TotalMinutes -gt 0  ) {
                    $htmlCellStyleEndRetard =  "style='background:#0FD536'"
                    $RowsEndRetard = $RowsEndRetard + 1
                }
                Else {
                    $htmlCellStyleEndRetard =  ""
                }
            }
        }

        $DataRow = "
        <tr>
        <td>$($DateStr) </td>
        <td>$($job.schedule.name) </td>
        <td> </td>
        <td>$($job.name)</td>
        <td>$($job.primaryMachine.name)</td>
        <td>$($job.jobType.description)</td>
        <td $($htmlCellStyle)>$($job.status.description)</td>
        <td>$($StartTimeProgrammed)</td>
        <td>$($EndTimeProgrammed)</td>
        <td $($htmlCellStyleStartRetard)>$($StartTimeTime) $($StartTimeTimeEstimated)</td>
        <td $($htmlCellStyleEndRetard)>$($EndTimeTime) $($EndTimeTimeEstimated)</td>
        <td>$($job.computedDuration.duration/1000/60) $($DurationEstimated)</td>
        </tr>"

        $FinalData += $DataRow

        $jobSearch = $job.schedule.name+"|"+$job.name

        $ListSousJob = HistoryJobDay -Dates $Dates -JobName $jobSearch

        If ($ListSousJob.Count -ne 0) {
            Foreach($SousJob in ($ListSousJob|Select -skip 1)) { 

                $SousStartTimeTime =TryParseDate -inDate $SousJob.jobStartTime -format 'yyyy-MM-ddTHH:mm:ss.fffffffzzz'
                $SousEndTimeTime = TryParseDate -inDate $SousJob.jobTermination -format 'yyyy-MM-ddTHH:mm:ss.fffffffzzz'

                If ($SousJob.jobstatus.description -Contains "Failed") {
                    $htmlCellStyle =  "style='background:#FF0000'"
                    $RowsFailed = $RowsFailed + 1
                }
                ElseIf ($SousJob.jobstatus.description -Contains "Skipped") {
                    $htmlCellStyle =  "style='background:#F000FF'"
                    $RowsSkipped = $RowsSkipped + 1
                }
                ElseIf ($SousJob.jobstatus.description -Contains "Cancelled") {
                    $htmlCellStyle =  "style='background:#0017FF'"
                    $RowsCancelled = $RowsCancelled + 1
                }
                ElseIf ($SousJob.jobstatus.description -Contains "Job Running") {
                    $htmlCellStyle =  "style='background:#000000;color:white'"
                    $RowsRun = $RowsRun + 1
                }
                Else {
                    $RowsOK = $RowsOK + 1
                }

                $DataRow = "
                <tr>
                <td>$($DateStr) </td>
                <td>$($job.schedule.name) </td>
                <td><img src='./media/horloge.png' width='10' height='10'></td>
                <td>$($job.name)</td>
                <td>$($job.primaryMachine.name)</td>
                <td>$($job.jobType.description)</td>
                <td $($htmlCellStyle)>$($SousJob.jobstatus.description)</td>
                <td>$($StartTimeProgrammed)</td>
                <td>$($EndTimeProgrammed)</td>
                <td $($htmlCellStyleStartRetard)>$($SousStartTimeTime)</td>
                <td $($htmlCellStyleEndRetard)>$($SousEndTimeTime)</td>
                <td>$($SousJob.Duration/1000/60)</td>
                </tr>"

                $FinalData += $DataRow

                [int]$Rows  = [int]$Rows + 1
                [int]$Total = [int]$Total + 1
            }
        }
      
    }

    (Get-Content -path HtmlTemplate.html -Raw) -replace 'ROWS_PLACE_HOLDER',$FinalData | Out-File -FilePath Rapport-$OpScheduleDate-tmp-01.html
    (Get-Content -path Rapport-$OpScheduleDate-tmp-01.html -Raw) -replace 'ROWS_OK_NUMBER',$RowsOK | Out-File -FilePath Rapport-$OpScheduleDate-tmp-02.html
    (Get-Content -path Rapport-$OpScheduleDate-tmp-02.html -Raw) -replace 'ROWS_SKIPPED_NUMBER',$RowsSkipped | Out-File -FilePath Rapport-$OpScheduleDate-tmp-03.html
    (Get-Content -path Rapport-$OpScheduleDate-tmp-03.html -Raw) -replace 'ROWS_CANCELLED_NUMBER',$RowsCancelled | Out-File -FilePath Rapport-$OpScheduleDate-tmp-04.html
    (Get-Content -path Rapport-$OpScheduleDate-tmp-04.html -Raw) -replace 'ROWS_FAILED_NUMBER',$RowsFailed | Out-File -FilePath Rapport-$OpScheduleDate-tmp-05.html
    (Get-Content -path Rapport-$OpScheduleDate-tmp-05.html -Raw) -replace 'ROWS_RUN_NUMBER',$RowsRun | Out-File -FilePath Rapport-$OpScheduleDate-tmp-06.html
    (Get-Content -path Rapport-$OpScheduleDate-tmp-06.html -Raw) -replace 'ROWS_NUMBER',$Rows | Out-File -FilePath Rapport-$OpScheduleDate-tmp-07.html

    $Percentage_Ok = ($RowsOK * 100 ) / $Rows
    $Percentage_Skipped = ($RowsSkipped * 100 ) / $Rows
    $Percentage_Cancelled = ($RowsCancelled * 100 ) / $Rows
    $Percentage_Failed = ($RowsFailed * 100 ) / $Rows
    $Percentage_Run = ($RowsRun * 100 ) / $Rows

    (Get-Content -path Rapport-$OpScheduleDate-tmp-07.html -Raw) -replace 'PERCENTAGE_OK_NUMBER',$Percentage_Ok | Out-File -FilePath Rapport-$OpScheduleDate-tmp-08.html
    (Get-Content -path Rapport-$OpScheduleDate-tmp-08.html -Raw) -replace 'PERCENTAGE_SKIPPED_NUMBER',$Percentage_Skipped | Out-File -FilePath Rapport-$OpScheduleDate-tmp-09.html
    (Get-Content -path Rapport-$OpScheduleDate-tmp-09.html -Raw) -replace 'PERCENTAGE_CANCELLED_NUMBER',$Percentage_Cancelled | Out-File -FilePath Rapport-$OpScheduleDate-tmp-10.html
    (Get-Content -path Rapport-$OpScheduleDate-tmp-10.html -Raw) -replace 'PERCENTAGE_FAILED_NUMBER',$Percentage_Failed | Out-File -FilePath Rapport-$OpScheduleDate-tmp-11.html
    (Get-Content -path Rapport-$OpScheduleDate-tmp-11.html -Raw) -replace 'PERCENTAGE_RUN_NUMBER',$Percentage_Run | Out-File -FilePath Rapport-$OpScheduleDate-tmp-12.html

    (Get-Content -path Rapport-$OpScheduleDate-tmp-12.html -Raw) -replace 'ROWS_START_Retard',$RowsStartRetard | Out-File -FilePath Rapport-$OpScheduleDate-tmp-13.html
    (Get-Content -path Rapport-$OpScheduleDate-tmp-13.html -Raw) -replace 'ROWS_END_Retard',$RowsEndRetard | Out-File -FilePath Rapport-$OpScheduleDate.html

    Remove-Item Rapport-$OpScheduleDate-tmp-*.html -Force -Confirm:$False
}

#
$SecPass = $null;
$clearPassword = ""
If ($OpConPassword.Length -eq 0 ) {
    $SecPass = Read-Host 'Quel est le mot de passe ?' -AsSecureString    
    $clearPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
                     [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecPass))
}
Else {
    $clearPassword = $OpConPassword
}

Login-RestApi -ApiUrl $ServerUrl -OpConUser $OpConUser -OpConPassword $clearPassword 

DisplayDailyJobs -Status $OpJobStatus -Dates $OpScheduleDate -JobType "" 

Invoke-Item .\Rapport-$OpScheduleDate.html