content: module Taskell.Data.Lists where
  
  import ClassyPrelude
  
  import Control.Lens  ((^.))
  import Data.Sequence as S (adjust', deleteAt, update, (!?), (|>))
  
  import qualified Taskell.Data.List as L (List, Update, append, clearDue, count, due, empty, extract,
                                           prepend, searchFor)
  import qualified Taskell.Data.Seq  as S
  import qualified Taskell.Data.Task as T (Task, due)
  import           Taskell.Types     (ListIndex (ListIndex), Pointer, TaskIndex (TaskIndex))
  
  type Lists = Seq L.List
  
  type Update = Lists -> Lists
  
  data ListPosition
      = Top
      | Bottom
  
  initial :: Lists
  initial = fromList []
  
  updateLists :: Int -> L.List -> Update
  updateLists = S.update
  
  count :: Int -> Lists -> Int
  count idx tasks = maybe 0 L.count (tasks !? idx)
  
  due :: Lists -> Seq (Pointer, T.Task)
  due lists = sortOn ((^. T.due) . snd) dues
    where
      format x lst = (\(y, t) -> ((ListIndex x, y), t)) <$> L.due lst
      dues = concat $ format S.<#> lists
  
  clearDue :: Pointer -> Update
  clearDue (idx, tsk) = updateFn idx (L.clearDue tsk)
  
  updateFn :: ListIndex -> L.Update -> Update
  updateFn (ListIndex idx) fn = adjust' fn idx
  
  get :: Lists -> Int -> Maybe L.List
  get = (!?)
  
  changeList :: ListPosition -> Pointer -> Lists -> Int -> Maybe Lists
  changeList pos (ListIndex list, TaskIndex idx) tasks dir = do
      let next = list + dir
      let fn =
              case pos of
                  Top    -> L.prepend
                  Bottom -> L.append
      (from, task) <- L.extract idx =<< tasks !? list -- extract current task
      to <- fn task <$> tasks !? next -- get next list and append task
      pure . updateLists next to $ updateLists list from tasks -- update lists
  
  newList :: Text -> Update
  newList title = (|> L.empty title)
  
  delete :: Int -> Update
  delete = deleteAt
  
  exists :: Int -> Lists -> Bool
  exists idx tasks = isJust $ tasks !? idx
  
  shiftBy :: Int -> Int -> Lists -> Maybe Lists
  shiftBy = S.shiftBy
  
  search :: Text -> Update
  search text = (L.searchFor text <$>)
  
  appendToLast :: T.Task -> Update
  appendToLast task lists =
      fromMaybe lists $ do
          let idx = length lists - 1
          list <- L.append task <$> lists !? idx
          pure $ updateLists idx list lists
  
  analyse :: Text -> Lists -> Text
  analyse filepath lists =
      concat
          [ filepath
          , "\n"
          , "Lists: "
          , tshow $ length lists
          , "\n"
          , "Tasks: "
          , tshow $ foldl' (+) 0 (L.count <$> lists)
          ]
  