##/*********************************************************************************************
##Author                :  Guravareddy.T
##Purpose               :  Display the Skype Audio cals
##Created               :  11/08/2018
##Modified By		    :	

##reference link        :(Poor call definition by Microsoft 
#                         http://guybachar.net/2015/06/11/script-get-lyncskype4b-users-which-reported-having-poor-calls/
#                         https://realtimeuc.com/2016/10/sfbo-session-details-preview/)

clear
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$egInstallpath=Get-ChildItem Env:EGURKHA_INSTALL_DIR |Select Value
$egurkhaPath=$egInstallpath.Value.ToString()
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
$egEncryPath=$scriptPath+"\EGFileEncryption.psm1"
$egDatnKy=$scriptPath+"\GetDatnKeyFiles.psm1"
Import-Module $egEncryPath,$egDatnKy

$testargs=$args
$reportingname='SBO\'+$testargs[0]
$longcaldurInMin=$testargs[1]
$egInstallpath=Get-ChildItem Env:EGURKHA_INSTALL_DIR |Select Value

$readfiles=Eg-ReadFile -ComntRptPath $reportingname -FileName "SyRatMycalFeedBack" -keyFileName "kSyRatMycalFeedBack" -EgPath $egurkhaPath
$datafile=$readfiles[1] -replace (".csv",".dat") 
$csvfile=Unprotect-File $datafile -Algorithm AES -KeyAsPlainText $readfiles[0]	
#importing data from csv and sorting depending on DialogId because every session traffic having the unique Dailog id
[array]$userSession= import-csv $csvfile| Select-Object * | Where-Object { $_.MediaTypesDescription -Like "*Audio*" } | Sort -property DialogId -Unique                              			 			 					
Remove-Item $csvfile
Eg-DeleteFiles -FilePath $readfiles[2] -Pattern 'SyRatMycalFeedBack' -InputFile $readfiles[3]
Eg-DeleteFiles -FilePath $readfiles[2] -Pattern 'kSyRatMycalFeedBack' -InputFile $readfiles[4]
Write-Host "ReadFile:"$readfiles[3]

$totalaudiocalls=0
$comptedaudiocls=0
$poorcalscnt=0
$poorcalsperct=0
$failedcnt=0
$failedclsperct=0
$longcalscnt=0
$totalsesduration=0
$totalcnferncecals=0
$CnfOrganisersCnt=0
$CnfParticpatedUsersCnt=0
$CurrentSessions=0
$totalbandwdthused=0
$longcalslist=@{}
$cnfurlStrtNendtime=@{}  # its for conference cal min start and max ending time by checking the alltraffic in that conference url
$CnfrncurlNinstancid=@{} # confrence url as key and ConfInstance is value
$bandwithddmap=@{} # key(unique) as dd and value as bandwidth
$empty='-'

#Date Format 
$CultureDateTimeFormat = (Get-Culture).DateTimeFormat
$DateFormat = $CultureDateTimeFormat.ShortDatePattern
$TimeFormat = $CultureDateTimeFormat.LongTimePattern
$DateTimeFormat = "$DateFormat $TimeFormat"

if($longcaldurInMin -eq $null -and $longcaldurInMin -eq " "){ $longcaldurInMin=60 }# default value
$longcaldurInMin=[int]$longcaldurInMin

if($userSession){

    $totalaudiocalls=$userSession.count
    ## getting the only conference sessions from all audio sessions
    [array]$cnfrncecals=$userSession | Select-Object FromUri,ToUri,MediaTypesDescription,ConferenceUrl,ConfInstance,StartTime,EndTime,StartedTime,EndedTime | Where-Object { $_.MediaTypesDescription -Like "*Conference*"} 
    ## geeting current running sessions (endtime of session is null)
    [array]$currentcals=$userSession | Select-Object FromUri,ToUri,MediaTypesDescription,StartTime,EndTime,StartedTime,EndedTime | Where-Object { $_.EndTime -eq "" } | Sort-Object { $_.StartTime -as [datetime] } -Descending #| select -first 10 
    ## getting all audio sessions which are having the QoeReport
    [array]$output=$userSession | Select-Object * | Where-Object { $_.QoEReport -ne "" }
}

foreach($ot in $output)
{ 
    $ot.QoeReport=($ot.QoeReport) | ConvertFrom-Json

    
    if ($ot.QoeReport.AudioStreams) {  # for analying the poor calls by refering by refering these parameters
           
        $JitterInterArrival =$ot.QoeReport.AudioStreams.JitterInterArrival
        $PacketLossRate =$ot.QoeReport.AudioStreams.PacketLossRate
        $DegradationAvg =$ot.QoeReport.AudioStreams.DegradationAvg  
        $RoundTrip =$ot.QoeReport.AudioStreams.RoundTrip
        $RatioConcealedSamplesAvg = $ot.QoeReport.AudioStreams.RatioConcealedSamplesAvg
        $Bandwidth=$ot.QoeReport.AudioStreams.BandwidthEst
        $bandwidthtotal=0;$count=0;$BandwidthEst=0
        foreach($bndwdt in $Bandwidth){if($bndwdt){$bandwidthtotal+=[long]$bndwdt;$count++ }}
        if($bandwidthtotal){$BandwidthEst=$bandwidthtotal/$count}

        $JitterInterArrivalOutbound =if($JitterInterArrival[0] -and $JitterInterArrival[0] -ne " "){$JitterInterArrival[0].toString()}else{"0"}
        $PacketLossRateOutbound =if($PacketLossRate[0] -and $PacketLossRate[0] -ne " "){$PacketLossRate[0].toString()}else{"0"}
        $DegradationAvgOutbound = if($DegradationAvg[0] -and $DegradationAvg[0] -ne " "){$DegradationAvg[0].toString()}else{"0"}
        $RoundTripOutbound =if($RoundTrip[0] -and $RoundTrip[0] -ne " "){$RoundTrip[0].toString()}else{"0"}
        $RatioConcealedSamplesAvgOutbound =if($RatioConcealedSamplesAvg[0] -and $RatioConcealedSamplesAvg[0] -ne " "){$RatioConcealedSamplesAvg[0].toString()}else{"0"}

        $JitterInterArrivalInbound =if($JitterInterArrival[1] -and $JitterInterArrival[1] -ne " "){$JitterInterArrival[1].toString()}else{"0"}
        $PacketLossRateInbound =if($PacketLossRate[1] -and $PacketLossRate[1] -ne " "){$PacketLossRate[1].toString()}else{"0"}
        $DegradationAvgInbound =if($DegradationAvg[1] -and $DegradationAvg[1] -ne " "){$DegradationAvg[1].toString()}else{"0"}
        $RoundTripInbound=if($RoundTrip[1] -and $RoundTrip[1] -ne " "){$RoundTrip[1].toString()}else{"0"}
        $RatioConcealedSamplesAvgInbound =if($RatioConcealedSamplesAvg[1] -and $RatioConcealedSamplesAvg[1] -ne " "){$RatioConcealedSamplesAvg[1].toString()}else{"0"}             
    
    }else{
        # defaul values (if QoeReport not having the AudioStreams object)
        $JitterInterArrival =0
        $PacketLossRate =0
        $DegradationAvg =0 
        $RoundTrip =0
        $RatioConcealedSamplesAvg =0
        $BandwidthEst=0 
    }

        $fromIp=""
        $toIp=""
        [array]$medialLines=$ot.QoeReport.MediaLines  # having the two objects and  some times having one object
        if ($medialLines -ne $null -and $medialLines -ne " ") {
            $fromIp1="";$toIp1=""
            foreach($medllns in $medialLines)
            {
                  $fromIp1=($medllns.FromIPAddr).trim()
                  $toIp1=($medllns.ToIPAddr).trim()
                  if($fromIp1 -ne $toIp1)
                  {
                      $fromIp=$fromIp1;$toIp=$toIp1
                  }

            }
            if($fromIp -eq "" -or $toIp -eq "")
            {
                  $fromIp=$fromIp1;$toIp=$toIp1
            }
         }

    $mediastrttime=Eg-ConvertTime -Time ([datetime]($ot.QoeReport.Session.MediaStartTime).Replace('T',' '))  # converting to required time zone from skype server time
    $mediaendtime=Eg-ConvertTime -Time ([datetime]($ot.QoeReport.Session.MediaEndTime).Replace('T',' ')) #converting to required time zonee from skype server time
    $mediatype=($ot.MediaTypesDescription).Replace("]["," ").Replace("]","").Replace("[","")
    $MediaDurationInMinutes = ( $mediaendtime - $mediastrttime).TotalMinutes
    $totalsesduration=$totalsesduration+$MediaDurationInMinutes
    $fromdevice=$ot.QoeReport.medialines.FromRenderDev
    $todevice=$ot.QoeReport.medialines.ToRenderDev 
    # if the  ($ot.ErrorReports) having the 'UnexpectedFailure' or 'expectedFailure' then we will take it as failed call
    $strindex =  if((($ot.ErrorReports)).IndexOf("UnexpectedFailure") -gt 0 -or (($ot.ErrorReports)).IndexOf("expectedFailure") -gt 0) { 10} else{0}
  
    if($strindex -gt 1)
    {
        $failedcnt++ 
        $ot.ErrorReports=($ot.ErrorReports).Replace('\','').Replace(';',',').Replace(':','=').Replace('"','').Replace('Reason','reason')
        $errorreport=""

    try{
        ## getting proper error message from ErrorReports
        while($ot.ErrorReports.Length -gt 0)
        {
            $frstobj=$ot.ErrorReports.Substring(0,$ot.ErrorReports.IndexOf('}')+1).trim()
            $temp=$frstobj.Substring(1,$frstobj.IndexOf("reason")-1)
            $frstobj=$frstobj.Substring($frstobj.IndexOf("reason"))
            if($frstobj.Contains(',')){
                $temp=$temp+$frstobj.Substring(0,$frstobj.IndexOf(","))+';'
            }
            else{
                $temp=$temp+$frstobj.Substring(0,$frstobj.IndexOf("}"))+';'
            }
            if($temp.IndexOf("UnexpectedFailure") -gt 0 -or $temp.IndexOf("expectedFailure") -gt 0){
                $errorreport=$errorreport+$temp
                $temp=''
            }
            $ot.ErrorReports=$ot.ErrorReports.Substring($ot.ErrorReports.IndexOf('}')+1)

        }

        }catch{
            $errormsg=$_.Exception.Message
            Write-Host 'error occured while writting  ErrorReports' $errormsg
        }


        $faileddd=''+$mediastrttime+'~!~'+$mediaendtime+'~!~'+'-'+'~!~'+$mediatype+'~!~'+$ot.FromUri+'~!~'+$ot.FromClientVersion+'~!~'+'-'+'~!~'+'-'+'~!~'+'-'+'~!~'+$fromIp+'~!~'+$ot.FromTelNumber+'~!~'+'-'+'~!~'+'-'+'~!~'+'-'+'~!~'+'-'+ '~!~'+'-'+'~!~'+ $ot.ToUri +'~!~'+$ot.ToClientVersion+'~!~'+'-'+'~!~'+'-'+'~!~'+'-'+'~!~'+$toIp+'~!~'+$ot.ToTelNumber+'~!~'+'-'+'~!~'+'-'+'~!~'+'-'+'~!~'+'-'+'~!~'+'-'+'~!~'+ $errorreport
        write-host "#faildcaldd~" $faileddd
        $faileddd=''
    }


       if( ($JitterInterArrival -gt 30) -or ($PacketLossRate -gt 0.1) -or ($DegradationAvg -gt 1.0 ) -or ($RoundTrip -gt 500) -or ($RatioConcealedSamplesAvg -gt 0.07))
       {
           $poorcalscnt++ 
           $poorcalsdd= ''+$mediastrttime+'~!~'+$mediaendtime+'~!~'+$MediaDurationInMinutes+'~!~'+$mediatype+'~!~'+$ot.FromUri+'~!~'+$ot.FromClientVersion+'~!~'+$ot.QoeReport.Session.FromOS+'~!~'+$fromdevice+'~!~'+([array]$ot.QoeReport.medialines.FromNetworkConnectionDetail)[0]+'~!~'+$fromIp+'~!~'+'-'+'~!~'+$JitterInterArrivalOutbound+'~!~'+$PacketLossRateOutbound+'~!~'+$RoundTripOutbound+'~!~'+$RatioConcealedSamplesAvgOutbound+'~!~'+$DegradationAvgOutbound+'~!~'+$ot.ToUri+'~!~'+$ot.ToClientVersion+'~!~'+$ot.QoeReport.Session.ToOS+'~!~'+$todevice+'~!~'+([array]$ot.QoeReport.medialines.ToNetworkConnectionDetail)[0]+'~!~'+$toIp+'~!~'+'-'+'~!~'+$JitterInterArrivalInbound+'~!~'+$PacketLossRateInbound+'~!~'+$RoundTripInbound+'~!~'+$RatioConcealedSamplesAvgInbound+'~!~'+$DegradationAvgInbound       
           Write-host '#poorcalsdd~' $poorcalsdd
           $poorcalsdd= ''
       }

       if($MediaDurationInMinutes -gt $longcaldurInMin)
       {
          $longcalscnt++
          $longcalsdd=''+$mediastrttime+'~!~'+$mediaendtime+'~!~'+$MediaDurationInMinutes+'~!~'+$mediatype+'~!~'+$ot.FromUri+'~!~'+$ot.FromClientVersion+'~!~'+$ot.QoeReport.Session.FromOS+'~!~'+$fromdevice+'~!~'+([array]$ot.QoeReport.medialines.FromNetworkConnectionDetail)[0]+'~!~'+$fromIp+'~!~'+'-'+'~!~'+'-'+'~!~'+'-'+'~!~'+'-'+'~!~'+'-'+'~!~'+'-'+'~!~'+$ot.ToUri+'~!~'+$ot.ToClientVersion+'~!~'+$ot.QoeReport.Session.ToOS+'~!~'+$todevice+'~!~'+([array]$ot.QoeReport.medialines.ToNetworkConnectionDetail)[0]+'~!~'+$toIp
          $longcalslist.Add($longcalsdd,$mediaendtime)
          $longcalsdd=''
       }

       if($BandwidthEst){$BandwidthEst=[double]($BandwidthEst/(1024*1024*1024))}  #intially bandwidth is in bytes so we are converting it into Gigabytes
       $totalbandwdthused=$totalbandwdthused+$BandwidthEst
       $BandwidthEst=$BandwidthEst.toString('#.####')
       $badwithdd=''+$mediastrttime+'~!~'+$mediaendtime+'~!~'+$empty+'~!~'+$mediatype+'~!~'+$ot.FromUri+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$fromIp+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$ot.ToUri+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$toIp+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+'~!~'+$BandwidthEst
       $bandwithddmap.Add($badwithdd,$BandwidthEst)             
}

## sorting the long sessions depending the latest endtime 
foreach($longcaldd in $longcalslist.GetEnumerator() |  Sort-Object { $_.Value -as [datetime] } -Descending)
{
    Write-host '#longcalsdd~' $longcaldd.key
}

foreach($bandwdtdd in $bandwithddmap.GetEnumerator() |  Sort-Object value  -Descending | select -First 10 )
{
    Write-host '#bandwidhtuseddd~' $bandwdtdd.key
}

## writting the top 10 current sessions by the latest start time
foreach($crtcal in $currentcals  | select -First 10)
{
    $CurrentSessions=$currentcals.Count
    $currentmediatype=($crtcal.MediaTypesDescription).Replace("]["," ").Replace("]","").Replace("[","")

    $crtcalStartTime = [DateTime]::ParseExact($crtcal.StartTime,$DateTimeFormat,[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None)
    $dd=''+(Eg-ConvertTime -Time $crtcalStartTime)+'~!~'+$empty+'~!~'+$empty+'~!~'+$currentmediatype+'~!~'+$crtcal.FromURI +'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$crtcal.ToURI+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty+'~!~'+$empty
    write-host '##currentcals' $dd
    $dd=$null
}


$CnfrurlNusers=@{}  # conferenceurl and users hashtable
$Cnfrurlusrcnt=@{}  # conferenceurl and users count hashtable
$cnfpartisipant=New-Object System.Collections.ArrayList #total conference paraticipated users list
$CnfOrgslist=New-Object System.Collections.ArrayList #unique conference organised users list


if($cnfrncecals)
{
    $totalcnferncecals=$cnfrncecals.count
    $cnfrncecals=$cnfrncecals | Select-Object * | Where-Object { $_.EndTime -ne ""}
    foreach($cfrccal in $cnfrncecals)
    {
        $cnfurl=$cfrccal.ConferenceUrl
        $instanceid=$cfrccal.ConfInstance
        $frmuri=$cfrccal.FromURI
        $touri= $cfrccal.ToURI
        $cfrccalStartTime = [DateTime]::ParseExact($cfrccal.StartTime,$DateTimeFormat,[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None)
        $cfrccalEndTime = [DateTime]::ParseExact($cfrccal.EndTime,$DateTimeFormat,[System.Globalization.DateTimeFormatInfo]::InvariantInfo,[System.Globalization.DateTimeStyles]::None)
        $strtime=Eg-ConvertTime -Time $cfrccalStartTime  
        $endtme=Eg-ConvertTime -Time $cfrccalEndTime

        if($CnfrurlNusers.Contains($cnfurl))
        {
            $list=$CnfrurlNusers[$cnfurl]
            if(!$list.Contains($FromURI)) { $null=$list.Add($frmuri) }

            if(!$list.Contains($touri)) { $null=$list.Add($touri) }

        }
        else
        {
            $list=New-Object System.Collections.ArrayList
            $list.Add($frmuri)
            if(!$list.Contains($touri))
            {
              $null=$list.Add($touri)  
            }
            $null=$CnfrurlNusers.Add($cnfurl,$list)       # mapping the conference users to conference url    
            $null=$CnfrncurlNinstancid.Add($cnfurl,$instanceid)   #adding cnfurl and instnce id to map
        }

        if(!$cnfpartisipant.Contains($FromURI)) { $null=$cnfpartisipant.Add($frmuri)}
        if(!$cnfpartisipant.Contains($touri)) { $null=$cnfpartisipant.Add($touri)}

        ### getting the (start of conference)start time and end time(end of conference) of the each conference

        if($cnfurlStrtNendtime.Contains($cnfurl))
        {
            $strttime1=$cnfurlStrtNendtime[$cnfurl]['starttime']
            if(([datetime]$strtime) -lt ([datetime]$strttime1)){$cnfurlStrtNendtime[$cnfurl]['starttime']=$strtime}
            $endtime1=$cnfurlStrtNendtime[$cnfurl]['endtime']
            if(([datetime]$endtme) -gt ([datetime]$endtime1)){$cnfurlStrtNendtime[$cnfurl]['endtime']=$endtme}
        }
        else
        {
            $temp=@{}
            $temp.Add('starttime',$strtime)
            $temp.Add('endtime',$endtme)
            $cnfurlStrtNendtime.Add($cnfurl,$temp)
        }
    }
}

if($CnfrurlNusers)
{
    $totalcnferncecals=$CnfrurlNusers.count

    foreach($parcon in $CnfrurlNusers.GetEnumerator())
    {
        $cnfurl=($parcon.key).ToString()
        $CnfOrgUser=$cnfurl.Substring(4,$cnfurl.IndexOf(";"))
        $CnfOrgUser=$CnfOrgUser.Substring(0,$CnfOrgUser.IndexOf(";"))
        if(!$CnfOrgslist.Contains($CnfOrgUser)) { $null=$CnfOrgslist.Add($CnfOrgUser)}
        $cnt=$parcon.value.count
        $null=$Cnfrurlusrcnt.Add($parcon.key,$cnt)
    }

    foreach($entry in $Cnfrurlusrcnt.GetEnumerator() | sort -Property value -Descending | select -First 10)
    {
        $cnfurl=($entry.key).ToString()
        $CnfOrgUser=$cnfurl.Substring(4,$cnfurl.IndexOf(";"))
        $CnfOrgUser=$CnfOrgUser.Substring(0,$CnfOrgUser.IndexOf(";"))
        if($CnfrurlNusers[$cnfurl].Count -gt 5){$CnfrurlNusers[$cnfurl].Remove($CnfOrgUser)}  #removing the conference organizer from conference participant users list 
        $CnfPartUsrs=([String]($CnfrurlNusers[$cnfurl] | select -First 5)).Replace(" ",",")
        Write-Host  '##conferencedd~' $CnfrncurlNinstancid[$entry.key]  '~!~' $CnfOrgUser '~!~' $entry.value '~!~' $CnfPartUsrs '~!~' $cnfurlStrtNendtime[$cnfurl]['starttime'] '~!~' $cnfurlStrtNendtime[$cnfurl]['endtime']
    }
}
    # getting complete Audio calls only
    $comptedaudiocls=$totalaudiocalls-$CurrentSessions

    if($comptedaudiocls -gt 0 -and $poorcalscnt -gt 0)
    {
        $poorcalsperct=((($poorcalscnt/$comptedaudiocls))*100).tostring("#.##")
    }
    if($comptedaudiocls -gt 0 -and $failedcnt -gt 0)
    {
        $failedclsperct=((($failedcnt/$comptedaudiocls))*100).tostring("#.##")
    }

    if($CnfOrgslist) { $CnfOrganisersCnt=$CnfOrgslist.count }
    if($cnfpartisipant) { $CnfParticpatedUsersCnt=$cnfpartisipant.count }
    if($totalsesduration){$totalsesduration=[double]$totalsesduration.ToString('#.##')}
    if($totalbandwdthused){ $totalbandwdthused=[double]$totalbandwdthused.ToString('#.####')}

    Write-Host 'measures~' $comptedaudiocls ~ $CurrentSessions ~ $poorcalscnt ~ $poorcalsperct ~ $failedcnt ~ $failedclsperct ~ $longcalscnt ~ $totalsesduration ~ $totalcnferncecals ~ $CnfOrganisersCnt ~ $CnfParticpatedUsersCnt ~ $totalbandwdthused
