{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}

module Celtchar.Novel.Structure where

import Data.Yaml
import GHC.Generics
import Data.Maybe (maybe)

class HasDependencies c where
  getDeps :: c -> [FilePath]

data Language = French | English
  deriving (Generic)

data Document = Document FilePath
  deriving (Generic, Show)

instance HasDependencies Document where
  getDeps (Document fp) = [fp]

instance FromJSON Document where
    parseJSON v = Document <$> parseJSON v

data Chapter = Chapter { chapterTitle :: Maybe String
                       , documents    :: [Document]
                       }
  deriving (Generic, Show)

instance HasDependencies Chapter where
  getDeps (Chapter _ docs) = docs >>= getDeps

instance FromJSON Chapter where
    parseJSON (Object v) = Chapter <$> v .:? "title"
                                   <*> v .: "documents"

data Part = Part { partTitle :: String
                 , chapters  :: [Chapter]
                 }
  deriving (Generic, Show)

instance FromJSON Part where
    parseJSON (Object v) = Part <$> v .: "title"
                                <*> v .: "chapters"

instance HasDependencies Part where
  getDeps (Part _ chaps) = chaps >>= getDeps

data Manuscript = Manuscript [Part]
  deriving (Generic, Show)

instance HasDependencies Manuscript where
  getDeps (Manuscript parts) = parts >>= getDeps

instance FromJSON Manuscript where
    parseJSON v = Manuscript <$> parseJSON v

instance FromJSON Language where
    parseJSON (String "english") = pure English
    parseJSON (String "french")  = pure French
    parseJSON _                  = fail "unknown language"

instance Show Language where
    show English = "english"
    show French  = "french"

data Novel = Novel { author      :: String
                   , language    :: Language
                   , novelTitle  :: String
                   , frontmatter :: Maybe [Chapter]
                   , manuscript  :: Manuscript
                   , appendix    :: Maybe [Chapter]
                   }
  deriving (Generic, Show)

instance HasDependencies Novel where
  getDeps (Novel _ _ _ mfrontmatter man mappendix) =
    (frontmatter >>= getDeps)
      `mappend` (getDeps man)
      `mappend` (appendix >>= getDeps)
    where frontmatter = maybe [] id mfrontmatter
          appendix = maybe [] id mappendix

instance FromJSON Novel where
    parseJSON (Object v) = Novel <$> v .: "author"
                                 <*> v .: "language"
                                 <*> v .: "title"
                                 <*> v .:? "frontmatter"
                                 <*> v .: "manuscript"
                                 <*> v .:? "appendix"

getNovelStructure :: FilePath -> IO (Either String Novel)
getNovelStructure conf = do
  ec <- decodeFileEither conf
  case ec of
    Right novel ->
      pure (Right novel)
    Left ex -> do
      pure (Left $ prettyPrintParseException ex)