{-# LANGUAGE DeriveGeneric #-}
-- | Card suit data type and its processing functions

module CardParts.Suits(Suit(..), parseSuit) where

import Data.List (elemIndex)
import Data.Char ( toLower, isDigit, digitToInt )
import GHC.Generics (Generic)
import Data.Aeson (FromJSON)
import Data.Aeson.Types (ToJSON)

-- | This type represents card suit.

data Suit = Hearts
    | Diamonds
    | Clubs
    | Spades deriving (Suit -> Suit -> Bool
(Suit -> Suit -> Bool) -> (Suit -> Suit -> Bool) -> Eq Suit
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Suit -> Suit -> Bool
$c/= :: Suit -> Suit -> Bool
== :: Suit -> Suit -> Bool
$c== :: Suit -> Suit -> Bool
Eq, Int -> Suit -> ShowS
[Suit] -> ShowS
Suit -> String
(Int -> Suit -> ShowS)
-> (Suit -> String) -> ([Suit] -> ShowS) -> Show Suit
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Suit] -> ShowS
$cshowList :: [Suit] -> ShowS
show :: Suit -> String
$cshow :: Suit -> String
showsPrec :: Int -> Suit -> ShowS
$cshowsPrec :: Int -> Suit -> ShowS
Show, Int -> Suit
Suit -> Int
Suit -> [Suit]
Suit -> Suit
Suit -> Suit -> [Suit]
Suit -> Suit -> Suit -> [Suit]
(Suit -> Suit)
-> (Suit -> Suit)
-> (Int -> Suit)
-> (Suit -> Int)
-> (Suit -> [Suit])
-> (Suit -> Suit -> [Suit])
-> (Suit -> Suit -> [Suit])
-> (Suit -> Suit -> Suit -> [Suit])
-> Enum Suit
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Suit -> Suit -> Suit -> [Suit]
$cenumFromThenTo :: Suit -> Suit -> Suit -> [Suit]
enumFromTo :: Suit -> Suit -> [Suit]
$cenumFromTo :: Suit -> Suit -> [Suit]
enumFromThen :: Suit -> Suit -> [Suit]
$cenumFromThen :: Suit -> Suit -> [Suit]
enumFrom :: Suit -> [Suit]
$cenumFrom :: Suit -> [Suit]
fromEnum :: Suit -> Int
$cfromEnum :: Suit -> Int
toEnum :: Int -> Suit
$ctoEnum :: Int -> Suit
pred :: Suit -> Suit
$cpred :: Suit -> Suit
succ :: Suit -> Suit
$csucc :: Suit -> Suit
Enum, Suit
Suit -> Suit -> Bounded Suit
forall a. a -> a -> Bounded a
maxBound :: Suit
$cmaxBound :: Suit
minBound :: Suit
$cminBound :: Suit
Bounded, (forall x. Suit -> Rep Suit x)
-> (forall x. Rep Suit x -> Suit) -> Generic Suit
forall x. Rep Suit x -> Suit
forall x. Suit -> Rep Suit x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Suit x -> Suit
$cfrom :: forall x. Suit -> Rep Suit x
Generic)

instance FromJSON Suit
instance ToJSON Suit

{- | This function gets a char which represents card suit
and returns a 'Suit' wrapped with 'Right'.

Char should be a lowercase symbol from "hdcs" list.
Otherwise - 'Left' with err msg returns.

__Examples:__

@
parseSuit \'h\' = 'Right' 'Hearts'
parseSuit \'c\' = 'Right' 'Clubs'
parseSuit \'x\' = 'Left' "There is no card suit marked as 'x'"
@
-}
parseSuit :: Char -> Either String Suit
parseSuit :: Char -> Either String Suit
parseSuit Char
symbol = case Char
symbol Char -> String -> Maybe Int
forall a. Eq a => a -> [a] -> Maybe Int
`elemIndex` String
suitSymbols of
    Maybe Int
Nothing -> String -> Either String Suit
forall a b. a -> Either a b
Left (String -> Either String Suit) -> String -> Either String Suit
forall a b. (a -> b) -> a -> b
$ String
"There is no card suit marked as " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Char -> String
forall a. Show a => a -> String
show Char
symbol
    Just Int
index -> Suit -> Either String Suit
forall a b. b -> Either a b
Right (Int -> Suit
forall a. Enum a => Int -> a
toEnum Int
index :: Suit)
    where
        -- | Just a shortcut for all 'Suit's as a list

        allSuits :: [Suit]
        allSuits :: [Suit]
allSuits = [Suit
forall a. Bounded a => a
minBound .. Suit
forall a. Bounded a => a
maxBound] :: [Suit]

        -- | 'Suit' symbols are [hdcs].

        -- This function take each 'Suit's' first letter lowercase to form this list.

        suitSymbols :: [Char]
        suitSymbols :: String
suitSymbols = [Char -> Char
toLower (Char -> Char) -> (Suit -> Char) -> Suit -> Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Char
forall a. [a] -> a
head (String -> Char) -> (Suit -> String) -> Suit -> Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Suit -> String
forall a. Show a => a -> String
show (Suit -> Char) -> Suit -> Char
forall a b. (a -> b) -> a -> b
$ Suit
s | Suit
s <- [Suit]
allSuits]