packages feed

codeforces-cli-0.1.0: src/Codeforces/App/Commands/StandingsCmd.hs

--------------------------------------------------------------------------------

-- | Standings command.
module Codeforces.App.Commands.StandingsCmd
    ( standingsList
    ) where

import           Codeforces.API          hiding ( RankColor(..) )
import           Codeforces.App.Format
import           Codeforces.App.Options
import           Codeforces.App.Table
import           Codeforces.App.Watcher
import           Codeforces.Error

import           Control.Monad.Trans.Except

import qualified Data.Map                      as M
import           Data.Text                      ( Text )
import qualified Data.Text                     as T

import           System.Console.ANSI.Types

--------------------------------------------------------------------------------

standingsList :: ContestId -> UserConfig -> StandingOpts -> IO ()
standingsList cId cfg StandingOpts {..} =
    handleWatch optStandWatch $ runExceptT $ do
        friends <- handleAPI $ getFriends cfg

        let mHs = if optFriends
                then Just (cfgHandle cfg : friends)
                else Nothing

        (standings, rcs) <- handleAPI $ getContestStandings' StandingsParams
            { paramContestId  = cId
            , paramFrom       = Just optFromIndex
            , paramRowCount   = Just optRowCount
            , paramRoom       = optRoom
            , paramUnofficial = optShowUnofficial
            , paramHandles    = mHs
            }

        if null (standingsRanklist standings)
            then
                throwE
                    (if optFriends
                        then StandingsWithFriendsEmpty
                        else StandingsEmpty
                    )
            else pure $ standingsTable standings rcs

standingsTable :: Standings -> M.Map Handle RatingChange -> Table
standingsTable s rcs = makeTable headers rows
  where
    headers = [("#", 5), ("Who", 20), ("=", totalPointsColW), ("*", 5)]
        ++ map (\p -> (problemIndex p, problemColW)) (standingsProblems s)
    rows = map
        (\RanklistRow {..} ->
            [ plainCell $ showText rrRank
                , partyCell rrParty rcs
                , totalPointsCell rrPoints
                , plainCell $ showText rrPenalty
                ]
                ++ map (problemResultCell scoringType) rrProblemResults
        )
        (standingsRanklist s)

    scoringType     = contestType $ standingsContest s

    -- Final score in ICPC contest is number of problems solved (single digit)
    totalPointsColW = if scoringType == ScoringICPC then 2 else 5
    -- Problem score in ICPC contest is only 2-3 chars wide (e.g. "+5", "-2")
    problemColW     = if scoringType == ScoringICPC then 3 else 5

partyCell :: Party -> M.Map Handle RatingChange -> Cell
partyCell Party {..} rcs = case partyMembers of
    [Member {..}] -> case M.lookup memberHandle rcs of
        Nothing -> plainCell $ participant $ unHandle memberHandle
        Just rc ->
            coloredCell (userColor rc) (participant $ unHandle memberHandle)

    ms -> case partyTeamName of
        Nothing       -> plainCell $ participant $ memberList ms
        Just teamName -> plainCell $ participant teamName
  where
    participant = fmtParticipation partyParticipantType
    memberList  = T.intercalate "," . map (unHandle . memberHandle)
    userColor   = convertRankColor . rankColor . getRank . rcOldRating

-- | 'fmtParticipation' @participantType text@ returns the @text@ with either a
-- prefix/suffix/no changes, to indicate the type of contest participation.
fmtParticipation :: ParticipantType -> Text -> Text
fmtParticipation Virtual    t = t <> " #"
fmtParticipation Contestant t = t
fmtParticipation _          t = "* " <> t

-- | 'showPoints' @points@ returns a textual representation of the points type.
-- If @points@ is an integer (e.g. @42.0@) then the integer without decimals
-- is returned (@42@), otherwise the decimals are shown.
showPoints :: Points -> Text
showPoints x = if x == fromInteger r then showText r else showText x
    where r = round x

-- | Cell showing the total points obtained by a user in the contest.
totalPointsCell :: Points -> Cell
totalPointsCell = plainCell . showPoints

-- | Cell showing the points obtained for a problem submission.
problemResultCell :: ScoringType -> ProblemResult -> Cell
problemResultCell st pr@ProblemResult {..} = if prNotAttempted pr
    then blankCell
    else case st of
        ScoringCF -> if prPoints == 0
            then coloredCell Red $ "-" <> showText prRejectedAttemptCount
            else coloredCell Green $ showPoints prPoints
        ScoringICPC -> if prPoints == 0
            then coloredCell Blue $ "-" <> showText prRejectedAttemptCount
            else coloredCell Green $ if prRejectedAttemptCount == 0
                then "+"
                else "+" <> showText prRejectedAttemptCount
        ScoringIOI -> case prPoints of
            0   -> blankCell
            100 -> coloredCell Green "100"
            x   -> plainCell (showPoints x)

--------------------------------------------------------------------------------