modules/FeedProcessor/AuditLog/Message.psm1

using module '..\..\Enums.psm1'
using module '..\..\Helper\ObjectHelper.psm1'
using module '..\..\Helper\DateTimeHelper.psm1'
using module '.\Event.psm1'
using module '.\Market.psm1'
using module '.\Outcome.psm1'
using module '.\Message\Performance.psm1'
using module '.\Message\Cardinality.psm1'

class Message {
    [long] $id
    [datetime]$createdAt
    [datetime]$updatedAt
    [string] $producer
    [PSCustomObject] $metrics
    [SOURCE] $source
    [SOURCE_TYPE] $sourceType

    [Event] $event

    [string] $changeType
    [hashtable] $other
    [string] $uniqueIdentifier
    [string] $timestamp
    [PSCustomObject] $content

    [Performance] $performance
    [Cardinality] $cardinality
    [DateTime] $cardinalityDate

    Message() {
        $this.other = @{}
        $this.performance = $null
    }

    Message([string] $id, [datetime] $createdAt, [datetime] $updatedAt, [string] $changeType, [string] $externalId, `
        [string] $producer, [PSCustomObject] $metrics) {

        $this.Message()

        $this.id = $id
        $this.createdAt = $createdAt
        $this.updatedAt = $updatedAt
        $this.changeType = $changeType
        $this.externalId = $externalId
        $this.producer = $producer
        $this.metrics = $metrics
    }

    [void] CalculatePerformance([SOURCE_TYPE] $targetType, [bool] $showAbsoluteNumbers, [bool] $ignoreProviderTimestamp) {
        $this.CalculatePerformance($this.sourceType, $targetType, $showAbsoluteNumbers, $ignoreProviderTimestamp)
    }

    [void] CalculatePerformance([SOURCE_TYPE] $sourceType, [SOURCE_TYPE] $targetType, [bool] $showAbsoluteNumbers, [bool] $ignoreProviderTimestamp) {

        $this.performance = $null

        $start=0; $end=0

        $start = [DateTimeHelper]::ConvertToTimestamp($this.createdAt.ToUniversalTime())
        $end = [DateTimeHelper]::ConvertToTimestamp($this.updatedAt.ToUniversalTime())

        $this.performance = [Performance]::new($sourceType, $targetType, $start, $end, $this.metrics, $showAbsoluteNumbers, $ignoreProviderTimestamp)
    }

    [datetime] GetCardinalityDate([int]$groupByMinutes){
        if ($groupByMinutes -eq 0){
            return $this.createdAt
        }
        else {
            return (Get-Date -year $this.createdAt.Year -month $this.createdAt.month -day $this.createdAt.day `
                -hour $this.createdAt.hour -minute ($groupByMinutes*[math]::Floor($this.createdAt.minute/$groupByMinutes)) -second 0 -millisecond 0)
        }
    }

    static [Cardinality[]] CardinalityGroupByMinute([Message[]] $messages, [int] $groupByMinutes){
        [Cardinality[]] $allCardinalities = @()
        [Cardinality] $card = $null

        $prevGroup = ''
        foreach ($m in $messages) {
            $messageDate = $m.GetCardinalityDate($groupByMinutes)

            if ($messageDate -ne $prevGroup){
                if ($null -ne $card) { $allCardinalities += $card }

                $card = [Cardinality]::new()
                $card.group = $messageDate
                $prevGroup = $card.group
            }

            $card.messages += $m.cardinality.messages
            $card.fixtures += $m.cardinality.fixtures
            $card.markets += $m.cardinality.markets
            $card.outcomes += $m.cardinality.outcomes
            $card.other += $m.cardinality.other
        }
        if ($null -ne $card) { $allCardinalities += $card }

        return $allCardinalities
    }

    #region Outputs

    [PSCustomObject] EventToOutput([DATATYPE] $dataType, [bool] $traceProducers){
        [PSCustomObject] $obj = $null

        switch ($dataType) {
            ([DATATYPE]::Event) {
                $obj = [PSCustomObject]@{PSTypeName='DisplayEvent'; msgId=$this.id; createdAt=$this.createdAt; action=$this.event.action;
                    status=$this.event.status; startDate=$this.event.startDate; liveCoverage=$this.event.liveCoverage;
                    other=[ObjectHelper]::ConvertToObject($this.other + $this.event.other)}
            }
            ([DATATYPE]::Market) {
                $obj = [PSCustomObject]@{PSTypeName='DisplayMarket'; msgId=$this.id; createdAt=$this.createdAt; action=$this.event.action;
                    status=$this.event.status; id=''; info=[ObjectHelper]::ConvertToObject($this.info + $this.event.info); specifiers='';
                    other=[ObjectHelper]::ConvertToObject($this.other + $this.event.other);}
            }
            ([DATATYPE]::Outcome) {
                $obj = [PSCustomObject]@{PSTypeName='DisplayOutcome'; msgId=$this.id; createdAt=$this.createdAt; action=$this.event.action;
                    status=$this.event.status; id=''; name=''; specifiers=''; price=''; info=[ObjectHelper]::ConvertToObject($this.info + $this.event.info)
                    other=[ObjectHelper]::ConvertToObject($this.other + $this.event.other);}
            }
        }
        if ($traceProducers) { $obj | Add-Member 'producer' ($this.producer) }

        return $obj
    }

    [PSCustomObject] MarketToOutput([DATATYPE] $dataType, [Market] $market, [bool] $traceProducers){
        [PSCustomObject] $obj = $null

        switch ($dataType) {
            ([DATATYPE]::Market) {
                $info = @{}
                if ($market.externalId) { $info.Add('external', $market.externalId) }
                if ($market.type) { $info.Add('type', $market.type) }
                if ($market.resulted) { $info.Add('resulted', $market.resulted) }

                $obj = [PSCustomObject]@{PSTypeName='DisplayMarket'; msgId=$this.id; createdAt=$this.createdAt; action=$market.action;
                    status=$market.status; id = $market.id; info=([ObjectHelper]::ConvertToObject($info)); specifiers=([ObjectHelper]::ConvertToObject($market.specifiers));
                    other=[ObjectHelper]::ConvertToObject($this.other + $market.other)}
            }
            ([DATATYPE]::Outcome) {
                $info = @{}
                if ($market.externalId) { $info.Add('external', $market.externalId) }
                if ($market.type) { $info.Add('type', $market.type) }
                if ($market.resulted) { $info.Add('resulted', $market.resulted) }

                $obj = [PSCustomObject]@{PSTypeName='DisplayOutcome'; msgId=$this.id; createdAt=$this.createdAt; action=$market.action;
                    status=$market.status; id=$market.id; name='';}

                if ($market.specifiers){ $obj | Add-Member 'specifiers' ([ObjectHelper]::ConvertToObject($market.specifiers)) }
                $obj | Add-Member 'price' ''
                $obj | Add-Member 'info' ([ObjectHelper]::ConvertToObject($info))
                $obj | Add-Member 'other' ([ObjectHelper]::ConvertToObject($this.other + $market.other))
            }
        }
        if ($traceProducers) { $obj | Add-Member 'producer' ($this.producer) }
        return $obj
    }

    hidden [PSCustomObject] OutcomeToOutput([DATATYPE] $dataType, [Market] $market, [Outcome] $outcome){
        [PSCustomObject] $obj = $null

        switch ($dataType) {
            ([DATATYPE]::Outcome) {
                $info = @{}
                if ($outcome.externalId) { $info.Add('external', $outcome.externalId) }
                if ($outcome.resulted) { $info.Add('resulted', $outcome.resulted) }
                if ($outcome.settlement) { $info.Add('settlement', $outcome.settlement) }

                $obj = [PSCustomObject]@{PSTypeName='DisplayOutcome'; msgId=''; createdAt=''; action=$market.action;
                    status=$outcome.status; id=$outcome.id; name=$outcome.name; specifiers=[ObjectHelper]::ConvertToObject($market.specifiers);
                    price=$outcome.price; info=([ObjectHelper]::ConvertToObject($info));
                    other=[ObjectHelper]::ConvertToObject($outcome.other)}
            }
        }
        return $obj
    }

    [PSCustomObject] PerformanceToOutput(){
        [PSCustomObject] $retValue = [PSCustomObject]@{PSTypeName='DisplayPerformance'; msgId=$this.id; createdAt=$this.createdAt}

        $outputMembers = $this.performance.ToOutput()
        foreach ($member in ($outputMembers.PSObject.Members | Where-Object { $_.MemberType -eq 'NoteProperty'})) {
            $retValue | Add-Member $member.name $member.value
        }

        return $retValue
    }

    [PSCustomObject] ScoreToOutput() {
        $score = $this.event.scoreDetails

        return [PSCustomObject]@{PSTypeName='DisplayScoreboard'; msgId=$this.id; createdAt=$this.createdAt; periodId=$score.periodId; minute=$score.playingMinute;
            home=$score.homeScore; away=$score.awayScore; scores=$score.scores; server=$score.currentServer; data=$score.data; }
    }

    [Message] Copy(){
        $message = [Message]::new()

        $message.id = $this.id
        $message.createdAt = $this.createdAt
        $message.updatedAt = $this.updatedAt
        $message.producer = $this.producer
        $message.metrics = $this.metrics
        $message.source = $this.source
        $message.sourceType = $this.sourceType

        if ($this.event) { $message.event = $this.event.Copy() }

        $message.changeType = $this.changeType
        $message.other = $this.other
        $message.uniqueIdentifier = $this.uniqueIdentifier
        $message.timestamp = $this.timestamp

        return $message
    }

    #endregion
}