{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

-- | The 'IsPerasVote' projection/injection class.
module Ouroboros.Consensus.Peras.Vote.Class
  ( IsPerasVote (..)
  , getPerasVoteId
  , getPerasVoteTarget
  ) where

import Ouroboros.Consensus.Block.Abstract (Point)
import Ouroboros.Consensus.BlockchainTime.WallClock.Types (WithArrivalTime (..))
import Ouroboros.Consensus.Peras.Types
  ( BoostedBlock
  , BoostedBlockCompatibleWithPoint (..)
  , PerasRoundNo
  , PerasSeatIndex
  , PerasVoteId (..)
  , PerasVoteTarget (..)
  )

-- | Types that support being treated as Peras votes
class
  BoostedBlockCompatibleWithPoint (BoostedBlock vote) blk =>
  IsPerasVote vote blk
    | vote -> blk
  where
  getPerasVoteRound :: vote -> PerasRoundNo
  getPerasVoteBlock :: vote -> BoostedBlock vote
  getPerasVoteSeatIndex :: vote -> PerasSeatIndex

  getPerasVotePoint :: vote -> Point blk
  getPerasVotePoint = BoostedBlock vote -> Point blk
forall boostedBlock blk.
BoostedBlockCompatibleWithPoint boostedBlock blk =>
boostedBlock -> Point blk
boostedBlockToPoint (BoostedBlock vote -> Point blk)
-> (vote -> BoostedBlock vote) -> vote -> Point blk
forall b c a. (b -> c) -> (a -> b) -> a -> c
. vote -> BoostedBlock vote
forall vote blk. IsPerasVote vote blk => vote -> BoostedBlock vote
getPerasVoteBlock

-- | Extract the vote ID from a Peras vote container
getPerasVoteId :: IsPerasVote vote blk => vote -> PerasVoteId
getPerasVoteId :: forall vote blk. IsPerasVote vote blk => vote -> PerasVoteId
getPerasVoteId vote
vote =
  PerasVoteId
    { pviRoundNo :: PerasRoundNo
pviRoundNo = vote -> PerasRoundNo
forall vote blk. IsPerasVote vote blk => vote -> PerasRoundNo
getPerasVoteRound vote
vote
    , pviSeatIndex :: PerasSeatIndex
pviSeatIndex = vote -> PerasSeatIndex
forall vote blk. IsPerasVote vote blk => vote -> PerasSeatIndex
getPerasVoteSeatIndex vote
vote
    }

-- | Extract the vote target from a Peras vote container
getPerasVoteTarget :: IsPerasVote vote blk => vote -> PerasVoteTarget blk
getPerasVoteTarget :: forall vote blk.
IsPerasVote vote blk =>
vote -> PerasVoteTarget blk
getPerasVoteTarget vote
vote =
  PerasVoteTarget
    { pvtRoundNo :: PerasRoundNo
pvtRoundNo = vote -> PerasRoundNo
forall vote blk. IsPerasVote vote blk => vote -> PerasRoundNo
getPerasVoteRound vote
vote
    , pvtBlock :: Point blk
pvtBlock = vote -> Point blk
forall vote blk. IsPerasVote vote blk => vote -> Point blk
getPerasVotePoint vote
vote
    }

instance
  IsPerasVote vote blk =>
  IsPerasVote (WithArrivalTime vote) blk
  where
  getPerasVoteRound :: WithArrivalTime vote -> PerasRoundNo
getPerasVoteRound = vote -> PerasRoundNo
forall vote blk. IsPerasVote vote blk => vote -> PerasRoundNo
getPerasVoteRound (vote -> PerasRoundNo)
-> (WithArrivalTime vote -> vote)
-> WithArrivalTime vote
-> PerasRoundNo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WithArrivalTime vote -> vote
forall a. WithArrivalTime a -> a
forgetArrivalTime
  getPerasVoteBlock :: WithArrivalTime vote -> BoostedBlock (WithArrivalTime vote)
getPerasVoteBlock = vote -> BoostedBlock vote
forall vote blk. IsPerasVote vote blk => vote -> BoostedBlock vote
getPerasVoteBlock (vote -> BoostedBlock vote)
-> (WithArrivalTime vote -> vote)
-> WithArrivalTime vote
-> BoostedBlock vote
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WithArrivalTime vote -> vote
forall a. WithArrivalTime a -> a
forgetArrivalTime
  getPerasVoteSeatIndex :: WithArrivalTime vote -> PerasSeatIndex
getPerasVoteSeatIndex = vote -> PerasSeatIndex
forall vote blk. IsPerasVote vote blk => vote -> PerasSeatIndex
getPerasVoteSeatIndex (vote -> PerasSeatIndex)
-> (WithArrivalTime vote -> vote)
-> WithArrivalTime vote
-> PerasSeatIndex
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WithArrivalTime vote -> vote
forall a. WithArrivalTime a -> a
forgetArrivalTime