module Hydrogen.Data (
    emptyNode
  , parseData
  , loadData
  , merge
  , Data
  , isNode
  , isNumber
  , isString
  , isVersion
  , isUUID
  , isBool
  , isDateTime
  , isDate
  , isTime
  , isLink
  , isConstant
  , getNodeMap
  , getNodeList
  , getNumber
  , getString
  , getVersion
  , getUUID
  , getBool
  , getDateTime
  , getDate
  , getTime
  , getLink
  , getConstant
  ) where

import Hydrogen.Prelude hiding (isNumber)

import Hydrogen.Syntax.Parser
import Hydrogen.Data.Parser
import Hydrogen.Data.Types

import Hydrogen.Parsing hiding (parse)

import qualified Data.Map as Map

merge :: Data -> Data -> Data
merge d1 d2 = case (d1, d2) of
    (DNode m1 l1, DNode m2 l2) -> DNode (Map.unionWith merge m1 m2) (l1 ++ l2)
    (_, dx) -> dx

emptyNode :: Data
emptyNode = DNode Map.empty []

loadData :: FilePath -> IO (Either SomethingBad Data)
loadData fp = (parseData <+< parse fp) <$> readFile fp

isNode, isNumber, isString, isVersion, isUUID, isBool,
  isDateTime, isDate, isTime, isLink, isConstant
    :: Data -> Bool

isNode = \case
    DNode _ _ -> True
    _ -> False

isNumber = \case
    DNumber _ -> True
    _ -> False

isString = \case
    DString _ -> True
    _ -> False

isVersion = \case
    DVersion _ -> True
    _ -> False

isUUID = \case
    DUUID _ -> True
    _ -> False

isBool = \case
    DBool _ -> True
    _ -> False

isDateTime = \case
    DDateTime _ -> True
    _ -> False

isDate = \case
    DDate _ -> True
    _ -> False

isTime = \case
    DTime _ -> True
    _ -> False

isLink = \case
    DLink _ -> True
    _ -> False

isConstant = \case
    DConstant _ -> True
    _ -> False

getNodeMap :: Data -> Map String Data
getNodeMap = \case
    DNode keyValueMap _ -> keyValueMap
    _ -> Map.empty

getNodeList :: Data -> [Data]
getNodeList = \case
    DNode _ xs -> xs
    _ -> []

getNumber :: Monad m => Data -> m Rational
getNumber = \case
    DNumber r -> return r
    _ -> fail "not a DNumber"

getString :: Monad m => Data -> m String
getString = \case
    DString r -> return r
    _ -> fail "not a DString"

getVersion :: Monad m => Data -> m Version
getVersion = \case
    DVersion v -> return v
    _ -> fail "not a DVersion"

getUUID :: Monad m => Data -> m UUID
getUUID = \case
    DUUID u -> return u
    _ -> fail "not a DUUID"

getBool :: Monad m => Data -> m Bool
getBool = \case
    DBool b -> return b
    _ -> fail "not a DBool"

getDateTime :: Monad m => Data -> m ZonedTime
getDateTime = \case
    DDateTime d -> return d
    _ -> fail "not a DDateTime"

getDate :: Monad m => Data -> m Day
getDate = \case
    DDate d -> return d
    _ -> fail "not a DDate"

getTime :: Monad m => Data -> m TimeOfDay
getTime = \case
    DTime d -> return d
    _ -> fail "not a DTime"

getLink :: Monad m => Data -> m String
getLink = \case
    DLink l -> return l
    _ -> fail "not a DLink"

getConstant :: Monad m => Data -> m String
getConstant = \case
    DConstant c -> return c
    _ -> fail "not a DConstant"