modules/FeedProcessor/RampProcessor.psm1

using module '..\Enums.psm1'
using module '..\Helper\DateTimeHelper.psm1'
using module '.\AuditLog\Message.psm1'
using module '.\AuditLog\Event.psm1'
using module '.\AuditLog\Market.psm1'
using module '.\AuditLog\Outcome.psm1'
using module '.\AuditLog\Event\SportData.psm1'
using module '.\AuditLog\Event\Score.psm1'
using module '.\AuditLog\Message\Cardinality.psm1'
using module '.\ProcessorBase.psm1'

class RampProcessor: Processor{

    RampProcessor([SOURCE_TYPE] $sourceType): base($sourceType){
        $this.source = [SOURCE]::ramp

        $this.producers.Add('RMP', 41)
        $this.mapExternalKeyPrefix.Add('RampFeed', '')

        $this.shouldReprocess = $true
        $this.isTypeBased = $true
        $this.haveMarketSeparator = $false
        $this.needFeedProducer = $false
    }

    #region Internal Resolving Methods

    hidden [string] ResolveEventState([string] $scheduledStartTime, [string] $oir, [string] $live) {
        if (-not $scheduledStartTime -or -not $oir -or -not $live) { return '' }

        $result = [CONST]::ENDED
        if ([DateTimeHelper]::getStringToLocalDate($scheduledStartTime, '') -gt [DateTimeHelper]::getStringToLocalDate($this.message.createdAt, '')) {
            $result = [CONST]::MATCH_PREMATCH
        }
        elseif ([DateTimeHelper]::getStringToLocalDate($scheduledStartTime, '') -lt [DateTimeHelper]::getStringToLocalDate($this.message.createdAt, '') `
             -and $oir -eq 'True') {

            switch ($live) {
                'NOT_APPLICABLE' { $result = [Const]::MATCH_PREMATCH }
                'YES' { $result = [CONST]::MATCH_INPLAY }
                'NO' { $result = [CONST]::MATCH_FINISHED }
            }
        }

        return $result
    }

    hidden [string] ResolveEventStatus([string] $bettingStatus, [string] $display, [string] $resulted){
        $result = ''
        switch ($bettingStatus) {
            'ACTIVE' {
                switch ($display) {
                    'True' { $result = [CONST]::STATUS_ACTIVE }
                    'False' { $result = [CONST]::STATUS_STOPPED }
                }
            }
            'SUSPENDED' { $result = [CONST]::STATUS_SUSPENDED }
        }
        if ($resulted -eq 'True'){
            $result = [CONST]::STATUS_RESULTED
        }

        return $result
    }

    hidden [string] ResolveMarketStatus([string] $bettingStatus, [string] $display, [string] $oir, [string] $resulted, [string] $action, [string] $eventState, [string] $eventStatus){
        $result = ''
        if ($eventStatus -in [CONST]::STATUS_ACTIVE){
            switch ($bettingStatus) {
                'ACTIVE' {
                    switch ($display) {
                        'True' {
                            switch ($eventState) {
                                ([CONST]::MATCH_PREMATCH) { $result = [CONST]::STATUS_ACTIVE }
                                ([CONST]::MATCH_INPLAY) {
                                    if ($oir -eq 'True') { $result = [CONST]::STATUS_ACTIVE }
                                    else { $result = [CONST]::STATUS_STOPPED }
                                }
                                ([CONST]::MATCH_FINISHED) { $result = [CONST]::STATUS_ACTIVE }
                                ([CONST]::MATCH_ENDED) { $result = [CONST]::STATUS_ACTIVE }
                            }
                        }
                        'False' { $result = [CONST]::STATUS_STOPPED }
                    }
                }
                'SUSPENDED' { $result = [CONST]::STATUS_SUSPENDED }
            }
        }
        else {
            $result = $eventStatus
        }
        if ($resulted -eq 'True'){
            $result = [CONST]::STATUS_RESULTED
        }

        return $result
    }

    hidden [string] ResolveOutcomeStatus([string] $bettingStatus, [string] $display, [string] $resulted, [string] $marketStatus){
        $result = ''
        if ($marketStatus -in [CONST]::STATUS_ACTIVE){
            switch ($bettingStatus) {
                'ACTIVE' {
                    switch ($display) {
                        'True' { $result = [CONST]::STATUS_ACTIVE  }
                        'False' { $result = [CONST]::STATUS_STOPPED }
                    }
                }
                'SUSPENDED' { $result = [CONST]::STATUS_SUSPENDED }
            }
        }
        else {
            $result = $marketStatus
        }

        if ($resulted -eq 'True'){
            $result = [CONST]::STATUS_RESULTED
        }

        return $result
    }

    # TODO (RAMP)
    [string] ResolveSettlementStatus([string] $status){
        return $status
    }

    #endregion

    #region Processing Methods

    [void] ProcessMessage([PSCustomObject] $line) {
        ([Processor]$this).ProcessMessage($line)

        $this.message.uniqueIdentifier = $line.content.timestampInformation.operatorMessageTimestamp
        $this.message.timestamp = $line.content.timestampInformation.operatorMessageTimestamp
    }

    [void] ProcessEvent([PSCustomObject] $line, [bool] $includeSportData) {

        $this.ProcessMessage($line)
        $this.message.event = $this.getEvent($line.content, $includeSportData)

        $this.isEventProcessed = $true
    }

    [void] ProcessCardinality([PSCustomObject] $line) {

        $this.message.cardinality = $this.getCardinality($line.content)
    }

    [void] ProcessEnrichment([PSCustomObject] $line) {
        $this.ProcessEvent($line, $false)
        $this.message.event.scoreDetails = $this.getScoreboard($line.content)
    }

    [void] ProcessMarket([PSCustomObject] $line, [Nullable[SEARCH_SCOPE]] $searchScope, [string[]] $marketId, [string[]] $outcomeId) {

        if ($null -eq $searchScope) { $searchScope = [SEARCH_SCOPE]::typeId }
        if (-not $this.message.event) {
            $this.ProcessEvent($line, $false)
        }

        $this.message.event.markets = @()
        foreach ($market in $this.FilterMarkets($line.content.markets, $searchScope, $marketId)) {
            $m = $this.getMarket($market, $outcomeId)
            $m.action = $line.message_type

            $this.message.event.markets += $m
        }

        $this.isMarketProcessed = $true
    }

    [bool] isEventRelated([PSCustomObject] $line){
        return $line.content.scheduling.scheduledStartTime -or $line.content.live -or $line.content.display `
            -or $line.content.offeredInRunning -or $line.content.bettingStatus -or $line.content.resulted
    }

    [bool] isEnrichmentRelated([PSCustomObject] $line){
        return ($line.content.participantAScore -or $line.content.participantBScore -or $line.content.matchStatistics -or $line.content.clockStage)
    }

    [bool] isMarketRelated([PSCustomObject] $line, [Nullable[SEARCH_SCOPE]] $searchScope, [string[]] $marketId){
        if (-not $searchScope) { $searchScope = [SEARCH_SCOPE]::typeId }
        return ($null -ne $this.FilterMarkets($line.content.markets, $searchScope, $marketId))
    }

    [void] Resolve(){
        $this.message.event = $this.Resolve($this.message.event)

        foreach ($market in $this.message.event.markets) {
            $market = $this.Resolve($market, $this.message.event)

            foreach ($outcome in $market.outcomes) {
                $outcome = $this.Resolve($outcome, $market)
            }
        }
    }

    #endregion

    #region Private Methods

    hidden [Event] Resolve([Event] $eventItem){
        $eventItem.status = $this.ResolveEventStatus($eventItem.other.bettingStatus, $eventItem.other.display, $eventItem.other.resulted)

        $matchState = $this.ResolveEventState($eventItem.startDate, $eventItem.liveCoverage, $eventItem.other.live)
        if($matchState) {
            if ($eventItem.other.Contains('matchState')){
                $eventItem.other.matchState = $matchState
            }
            else {
                $eventItem.other.Add('matchState', $matchState)
            }
        }

        return $eventItem
    }

    hidden [Market] Resolve([Market] $market, [Event] $eventItem){
        if ($null -eq $eventItem) {
            $matchState = ''
            $matchStatus = ''
        }
        else {
            $matchState = $eventItem.other.matchState
            $matchStatus = $eventItem.status
        }

        $market.status = $this.ResolveMarketStatus($market.other.bettingStatus, $market.other.display, $market.other.oir, `
            $market.resulted, $market.action, $matchState, $matchStatus)

        return $market
    }

    hidden [Outcome] Resolve([Outcome] $outcome, [Market] $market){
        if ($null -eq $market) {
            $marketStatus = ''
        }
        else {
            $marketStatus = $market.status
        }

        $outcome.status = $this.ResolveOutcomeStatus($outcome.other.bettingStatus, $outcome.other.display, $outcome.resulted, $marketStatus)

        return $outcome
    }

    hidden [PSCustomObject] FilterMarkets([PSCustomObject] $marketsContent, [SEARCH_SCOPE] $searchScope, [string[]] $marketId){
        return ($marketsContent | Where-Object { ($searchScope -eq [SEARCH_SCOPE]::typeId -and $_.typeId -in $marketid) -or `
                ($searchScope -eq [SEARCH_SCOPE]::externalId -and $_.externalId -in $marketid) -or `
                ($searchScope -eq [SEARCH_SCOPE]::internalId -and $_.id -in $marketid) -or `
                ('*' -in $marketid) })
    }

    hidden [PSCustomObject] FilterOutcomes([PSCustomObject] $outcomesContent, [string[]] $outcomeId){
        return $outcomesContent | Where-Object { ($_.id -in $outcomeId) -or ('*' -in $outcomeId) }
    }

    hidden [Event] getEvent([PSCustomObject] $messageContent, [bool] $includeSportData){
        [Event] $eventItem = [Event]::new()

        if ($includeSportData) { $eventItem.sportData = $this.getSportData($messageContent) }

        $eventItem.startDate = $messageContent.scheduling.scheduledStartTime
        $eventItem.liveCoverage = $messageContent.offeredInRunning
        $eventItem.action = $messageContent.action

        if($messageContent.bettingStatus) { $eventItem.other.Add('bettingStatus', $messageContent.bettingStatus) }
        if($messageContent.live) { $eventItem.other.Add('live', $messageContent.live) }
        if($messageContent.display) { $eventItem.other.Add('display', $messageContent.display) }
        if($messageContent.resulted) { $eventItem.other.Add('resulted', $messageContent.resulted) }

        $eventItem = $this.Resolve($eventItem)

        return $eventItem
    }

    hidden [Market] getMarket([PSCustomObject] $marketContent, [string[]] $outcomeId) {

        [Market] $market = [Market]::new()

        $market.id = $marketContent.id
        $market.name = $marketContent.name

        $market.type = $marketContent.typeId
        $market.specifiers = $marketContent.templateName.parameters
        $market.resulted = $marketContent.resulted
        $market.action = $marketContent.action

        if($marketContent.bettingStatus) { $market.other.Add('bettingStatus', $marketContent.bettingStatus) }
        if($marketContent.display) { $market.other.Add('display', $marketContent.display) }
        if($marketContent.offeredInRunning) { $market.other.Add('oir', $marketContent.offeredInRunning) }

        $market = $this.Resolve($market, $null)

        foreach ($outcome in $this.FilterOutcomes($marketContent.selections, $outcomeId)) {
            $market.outcomes += $this.getOutcome($outcome, $market)
        }

        return $market
    }

    hidden [Outcome] getOutcome([PSCustomObject] $outcomeContent, [Market] $market) {
        [Outcome] $outcome = [Outcome]::new()

        $outcome.id = $outcomeContent.id
        $outcome.name = $outcomeContent.name
        $outcome.action = $outcomeContent.action

        $outcome.settlement = $this.ResolveSettlementStatus($outcomeContent.resultType)

        $outcome.price = $outcomeContent.priceDecimal
        if ($outcomeContent.resultType) {
            $outcome.resulted = 'True'
        }
        else {
            $outcome.resulted = ''
        }

        if($outcomeContent.bettingStatus) { $outcome.other.Add('bettingStatus', $outcomeContent.bettingStatus) }
        if($outcomeContent.display) { $outcome.other.Add('display', $outcomeContent.display) }

        $outcome = $this.Resolve($outcome, $null)

        return $outcome
    }

    hidden [SportData] getSportData([PSCustomObject] $messageContent){
        $_sportId = $messageContent.eventDescriptor.subclassId
        $_sport = $messageContent.eventDescriptor.subclassName
        $_categoryId = ''
        $_category = ''
        $_leagueId = $messageContent.eventDescriptor.typeId
        $_league = $messageContent.eventDescriptor.typeName
        $_matchId = $messageContent.id

        $_match = $messageContent.name
        $_competitors = ($messageContent.participants | Sort-Object label)

        $_homeId = ''; $_home = ''; $_awayId = ''; $_away = ''
        if ($_competitors){
            $_homeId = $_competitors[0].id
            $_home = $_competitors[0].name
            $_awayId = $_competitors[1].id
            $_away = $_competitors[1].name
        }
        $_references = ''

        return [SportData]::new($_sportId, $_sport, $_categoryId, $_category, $_leagueId, $_league, $_matchId, $_match, $_homeId, $_home, $_awayId, $_away, $_references)
    }

    hidden [Score] getScoreboard([PSCustomObject] $messageContent){
        $_periodId=''; $_home=''; $_away=''; $_scores=''; $_currentServer=''; $_playingMinute=''; $_data=''

        #Tennis
        if (($messageContent.participantAScore -and $messageContent.participantAScore.Contains('*')) -or `
            ($messageContent.participantBScore -and $messageContent.participantBScore.Contains('*'))){

            $_scoreDetails = $messageContent.participantBScore.Split(' ')

            $_scores = @()
            foreach ($i in $_scoreDetails) {
                # this is the last game score
                $_individualScore = $i.Split('-')
                if ($i.Contains('*')){
                    $_home = $_individualScore[0]
                    $_away = $_individualScore[1]
                    if ($_home.Contains('*')) {
                        $_home = $_home.Replace('*','')
                        $_currentServer = 'HOME'
                    }
                    if ($_away.Contains('*')) {
                        $_away = $_away.Replace('*','')
                        $_currentServer = 'AWAY'
                    }
                }
                else {
                    $_home = $_individualScore[0]
                    $_away = $_individualScore[1]

                    $_scores += $_home + ':' + $_away
                    if ($_home -gt $_away){

                    }
                }
            }
            $_periodId = $_scores.Count
            $_data = $messageContent
        }
        #Soccer
        elseif ($messageContent.matchStatistics){
            $_periodId = $messageContent.clockStage.periodId
            $_home = $messageContent.participantAScore
            $_away = $messageContent.participantBScore
            $_scores = @()
            $_currentServer = ''
            $_data = $messageContent.matchStatistics
        }
        #Only score
        else {
            $_home = $messageContent.participantAScore
            $_away = $messageContent.participantBScore
            $_data = $messageContent.matchStatistics
        }

        return [Score]::new($_periodId, $_home, $_away, $_scores, $_currentServer, $_playingMinute, $_data)
    }

    hidden [Cardinality] getCardinality([PSCustomObject] $messageContent){
        $cardinality = [Cardinality]::new()

        $cardinality.markets = $messageContent.markets.count
        $cardinality.outcomes = $messageContent.markets.selections.count

        if ($cardinality.markets -eq 0){
            if ($this.isEventRelated($messageContent)) {
                $cardinality.fixtures = 1
            }
            else {
                $cardinality.other = 1
            }
        }

        return $cardinality
    }

    #endregion
}