content: module Taskell.IO.Markdown.Serializer
      ( serialize
      , MarkdownInfo(MarkdownInfo)
      ) where
  
  import ClassyPrelude
  
  import Control.Lens ((^.))
  
  import qualified Data.Text as T (splitOn)
  
  import Data.Time.Zones (TZ)
  
  import           Taskell.Data.Date    (Due, timeToOutput, timeToOutputLocal)
  import           Taskell.Data.List    (List, tasks, title)
  import           Taskell.Data.Lists   (Lists)
  import qualified Taskell.Data.Subtask as ST (Subtask, complete, name)
  import qualified Taskell.Data.Task    as T (Task, description, due, name, subtasks)
  
  import Taskell.IO.Config.Markdown (Config, descriptionOutput, dueOutput, localTimes, subtaskOutput,
                                     taskOutput, titleOutput)
  
  data MarkdownInfo = MarkdownInfo
      { mdTZ     :: TZ
      , mdConfig :: Config
      }
  
  type ReaderMarkdown = Reader MarkdownInfo
  
  -- utility functions
  askConf :: (Config -> a) -> ReaderMarkdown a
  askConf fn = fn <$> asks mdConfig
  
  strMay :: (Applicative m) => (a -> m Text) -> Maybe a -> m Text
  strMay _ Nothing   = pure ""
  strMay fn (Just a) = fn a
  
  space :: Text -> Text -> Text
  space symbol txt = symbol <> " " <> txt
  
  timeFn :: ReaderMarkdown (Due -> Text)
  timeFn = bool timeToOutput <$> (timeToOutputLocal <$> asks mdTZ) <*> askConf localTimes
  
  -- serializers
  subtaskCompleteS :: Bool -> Text
  subtaskCompleteS True  = "[x]"
  subtaskCompleteS False = "[ ]"
  
  subtaskS :: ST.Subtask -> ReaderMarkdown Text
  subtaskS st = do
      symbol <- askConf subtaskOutput
      pure $ unwords [symbol, subtaskCompleteS (st ^. ST.complete), st ^. ST.name]
  
  subtasksS :: Seq ST.Subtask -> ReaderMarkdown Text
  subtasksS sts = intercalate "\n" <$> sequence (subtaskS <$> sts)
  
  descriptionS :: Text -> ReaderMarkdown Text
  descriptionS desc = do
      symbol <- askConf descriptionOutput
      pure . intercalate "\n" $ space symbol <$> T.splitOn "\n" desc
  
  dueS :: Due -> ReaderMarkdown Text
  dueS due = do
      symbol <- askConf dueOutput
      fn <- timeFn
      pure $ space symbol (fn due)
  
  nameS :: Text -> ReaderMarkdown Text
  nameS desc = space <$> askConf taskOutput <*> pure desc
  
  taskS :: T.Task -> ReaderMarkdown Text
  taskS t =
      unlines . filter (/= "") <$>
      sequence
          [ nameS (t ^. T.name)
          , strMay dueS (t ^. T.due)
          , strMay descriptionS (t ^. T.description)
          , subtasksS (t ^. T.subtasks)
          ]
  
  listS :: List -> ReaderMarkdown Text
  listS list = do
      symbol <- askConf titleOutput
      taskString <- concat <$> sequence (taskS <$> list ^. tasks)
      pure . space symbol $ concat [list ^. title, "\n\n", taskString]
  
  -- serialize
  serialize :: Lists -> ReaderMarkdown Text
  serialize ls = intercalate "\n" <$> sequence (listS <$> ls)
  