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

    static [DATATYPE] $dataType
    static [string] $displayType
    static [string[]] $displayPropertySet

    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
    }

    #region Calculations

    [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
    }

    #endregion

    #region Display outputs

    [PSCustomObject] displayInfo(){
        return ([ObjectHelper]::ConvertToObject($this.event.info))
    }

    [PSCustomObject] displayOrigin(){
        return ([ObjectHelper]::ConvertToObject($this.event.other + $this.other))
    }

    static [void] SetDisplay([DATATYPE] $dataType){

        [Message]::dataType = $dataType

        switch ($dataType) {
            ([DATATYPE]::Event) { [Message]::displayType = 'DisplayEvent' }
            ([DATATYPE]::Market) { [Message]::displayType = 'DisplayMarket' }
            ([DATATYPE]::Outcome) { [Message]::displayType = 'DisplayOutcome' }
        }
    }

    [PSCustomObject] ToOutput(){
        $obj = [PSCustomObject]@{
            PSTypeName=[Message]::displayType;
            msgId=$this.id;
            createdAt=$this.createdAt;
            action=$this.event.action;
            status=$this.event.status;
            startDate=$this.event.startDate;
            liveCoverage=$this.event.liveCoverage;

            info=$this.displayInfo();
            producer=$this.producer;
            origin=$this.displayOrigin();
        }

        return $obj
    }

    [PSCustomObject] ToOutput([Market] $market){
        $obj = [PSCustomObject]@{
            PSTypeName=[Message]::displayType;
            msgId=$this.id;
            createdAt=$this.createdAt;
            action=$this.event.action;
            status=$market.status;
            startDate=$this.event.startDate;
            liveCoverage=$this.event.liveCoverage;

            id=$market.id;
            name=$market.name;
            specifiers=([ObjectHelper]::ConvertToObject($market.specifiers));

            info=$this.displayInfo();
            producer=$this.producer;
            origin=$this.displayOrigin(); }

        return $obj
    }

    hidden [PSCustomObject] ToOutput([Market] $market, [Outcome] $outcome){
        $obj = [PSCustomObject]@{
            PSTypeName=[Message]::displayType;
            msgId=$this.Id;
            createdAt=$this.createdAt;
            action=$this.event.action;
            status=$outcome.status;
            startDate=$this.event.startDate;
            liveCoverage=$this.event.liveCoverage;

            id=$outcome.id;
            name=$outcome.name;
            specifiers=([ObjectHelper]::ConvertToObject($market.specifiers));
            price=$outcome.price;

            info=$this.displayInfo();
            producer=$this.producer;
            origin=$this.displayOrigin();
        }

        return $obj
    }

    #TODO review
    [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
    }

    #TODO review
    [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
}