module Database exposing (Database, decode, get, getAll) import Card exposing (CardData, CardDetails, CardPerformanceData, CardType(..), ManaColor(..), Power(..), parseManaCost) import Dict exposing (Dict) import Json.Decode as Decode exposing (Decoder, decodeString) import Json.Decode.Pipeline exposing (optional, required) import Tuple exposing (pair) type Database = Database (Dict String CardData) get : String -> Database -> Maybe CardData get name (Database db) = Dict.get name db getAll : Database -> List CardData getAll (Database db) = Dict.values db decode : String -> Result String ( String, Maybe Database ) decode setData = let decoder : Decoder ( String, Maybe Database ) decoder = Decode.map2 pair (Decode.field "code" Decode.string) (Decode.field "data" (Decode.nullable (Decode.map2 createDatabase (Decode.field "ratings" decodePerformanceData) (Decode.field "cards" decodeSetData) ) ) ) in decodeString decoder setData |> Result.mapError Decode.errorToString createDatabase : Dict String CardPerformanceData -> Dict String CardDetails -> Database createDatabase performanceData detailsData = Dict.merge (\_ _ cardData -> cardData) (\name performance details -> Dict.insert name (CardData details performance)) (\_ _ cardData -> cardData) performanceData detailsData Dict.empty |> Database decodePerformanceData : Decoder (Dict String CardPerformanceData) decodePerformanceData = Decode.list decodeCardPerformance |> Decode.map Dict.fromList |> Decode.map (Debug.log "perf") decodeSetData : Decoder (Dict String CardDetails) decodeSetData = Decode.list decodeCardDetails |> Decode.map Dict.fromList decodeCardPerformance : Decoder ( String, CardPerformanceData ) decodeCardPerformance = Decode.map2 pair (Decode.field "Name" Decode.string) (Decode.succeed CardPerformanceData |> required "# Seen" decodeIntString |> required "# Picked" decodeIntString |> required "ATA" decodeMaybeFloatString |> required "ALSA" decodeMaybeFloatString |> required "GIH WR" decodeMaybePercentageString |> required "IWD" decodeImprovementWhenDrawn ) decodeImprovementWhenDrawn : Decoder (Maybe Float) decodeImprovementWhenDrawn = Decode.string |> Decode.andThen (\s -> if s == "" then Decode.succeed Nothing else case String.toFloat (String.replace "pp" "" s) of Just i -> Decode.succeed (Just i) Nothing -> Decode.succeed Nothing ) decodeIntString : Decoder Int decodeIntString = Decode.string |> Decode.andThen (\s -> case String.toInt s of Just i -> Decode.succeed i Nothing -> Decode.fail "Invalid integer" ) decodeMaybeFloatString : Decoder (Maybe Float) decodeMaybeFloatString = Decode.string |> Decode.andThen (\s -> if s == "" then Decode.succeed Nothing else case String.toFloat s of Just i -> Decode.succeed (Just i) Nothing -> Decode.succeed Nothing ) decodeMaybePercentageString : Decoder (Maybe Float) decodeMaybePercentageString = Decode.string |> Decode.andThen (\s -> if s == "" then Decode.succeed Nothing else case String.toFloat (String.replace "%" "" s) of Just i -> Decode.succeed (Just (i / 100)) Nothing -> Decode.succeed Nothing ) decodeCardDetails : Decoder ( String, CardDetails ) decodeCardDetails = Decode.map2 pair (Decode.field "name" Decode.string) (Decode.succeed CardDetails |> required "name" Decode.string |> required "cmc" Decode.int |> required "type_line" decodeCardType |> required "type_line" Decode.string |> optional "oracle_text" (Decode.nullable Decode.string) Nothing |> optional "power" (Decode.nullable decodePower) Nothing |> optional "toughness" (Decode.nullable decodePower) Nothing |> required "colors" (Decode.list decodeManaColor) |> required "mana_cost" (Decode.string |> Decode.andThen (\s -> case parseManaCost s of Just m -> Decode.succeed (Just m) Nothing -> Decode.succeed Nothing ) ) |> required "image_uris" (Decode.field "large" Decode.string) ) decodePower : Decoder Power decodePower = Decode.string |> Decode.andThen (\s -> if s == "*" then Decode.succeed VariablePower else case String.toInt s of Just i -> Decode.succeed (ConstantPower i) Nothing -> Decode.fail "Invalid integer" ) decodeManaColor : Decoder ManaColor decodeManaColor = Decode.string |> Decode.andThen (\c -> case c of "R" -> Decode.succeed Red "U" -> Decode.succeed Blue "G" -> Decode.succeed Green "W" -> Decode.succeed White "B" -> Decode.succeed Black "C" -> Decode.succeed Colorless _ -> Decode.fail "Invalid mana color" ) decodeCardType : Decoder CardType decodeCardType = Decode.string |> Decode.map (\c -> if String.contains "Creature" c then Creature else if String.contains "Instant" c then Instant else if String.contains "Sorcery" c then Sorcery else if String.contains "Enchantment" c then Enchantment else if String.contains "Artifact" c then Artifact else if String.contains "Planeswalker" c then Planeswalker else if String.contains "Land" c then Land else Other )