content: module Taskell.Events.State.Modal.Detail
      ( updateField
      , finishSubtask
      , finishDescription
      , finishDue
      , showDetail
      , getCurrentItem
      , getCurrentMode
      , getCurrentSubtask
      , getField
      , setComplete
      , remove
      , insertMode
      , editDescription
      , editDue
      , newItem
      , newItemAtIndex
      , nextSubtask
      , previousSubtask
      , lastSubtask
      , subTaskAtIndex
      , up
      , down
      , newAbove
      , newBelow
      ) where
  
  import ClassyPrelude
  
  import Control.Lens ((&), (.~), (^.))
  
  import Taskell.Data.Date (timeToDisplay)
  import qualified Taskell.Data.Seq as S
  import qualified Taskell.Data.Subtask as ST (blank, name, toggle)
  import Taskell.Data.Task
      ( Task
      , addSubtask
      , addSubtaskAtIndex
      , countSubtasks
      , description
      , due
      , getSubtask
      , removeSubtask
      , setDescription
      , setDue
      , subtasks
      , updateSubtask
      )
  import Taskell.Events.State (getCurrentTask, setCurrentTask, store)
  import Taskell.Events.State.Types (State, Stateful, mode, time, timeZone)
  import Taskell.Events.State.Types.Mode
      ( DetailItem(..)
      , DetailMode(..)
      , ModalType(Detail)
      , Mode(Modal)
      )
  import Taskell.UI.Draw.Field (Field, blankField, getText, textToField)
  
  newAbove :: Stateful
  newAbove state = do
      idx <- getCurrentSubtask state
      store state >>= newItemAtIndex idx >>= subTaskAtIndex idx >>= insertMode
  
  newBelow :: Stateful
  newBelow state = do
      idx <- (+ 1) <$> getCurrentSubtask state
      store state >>= newItemAtIndex idx >>= subTaskAtIndex idx >>= insertMode
  
  updateField :: (Field -> Field) -> Stateful
  updateField fieldEvent s =
      pure $
      case s ^. mode of
          Modal (Detail detailItem (DetailInsert field)) ->
              s & mode .~ Modal (Detail detailItem (DetailInsert (fieldEvent field)))
          _ -> s
  
  finishSubtask :: Stateful
  finishSubtask state = do
      text <- getText <$> getField state
      i <- getCurrentSubtask state
      task <- updateSubtask i (ST.name .~ text) <$> getCurrentTask state
      setCurrentTask task $ state & mode .~ Modal (Detail (DetailItem i) (DetailInsert blankField))
  
  finish :: (Text -> Task -> Task) -> Stateful
  finish fn state = do
      text <- getText <$> getField state
      task <- fn text <$> getCurrentTask state
      setCurrentTask task $ state & mode .~ Modal (Detail (DetailItem 0) DetailNormal)
  
  finishDescription :: Stateful
  finishDescription = finish setDescription
  
  finishDue :: Stateful
  finishDue state = do
      let tz = state ^. timeZone
      let now = state ^. time
      text <- getText <$> getField state
      task <- setDue tz now text =<< getCurrentTask state
      setCurrentTask task $ state & mode .~ Modal (Detail (DetailItem 0) DetailNormal)
  
  showDetail :: Stateful
  showDetail s = do
      _ <- getCurrentTask s
      let i = fromMaybe 0 $ getCurrentSubtask s
      pure $ s & mode .~ Modal (Detail (DetailItem i) DetailNormal)
  
  getCurrentSubtask :: State -> Maybe Int
  getCurrentSubtask state =
      case state ^. mode of
          Modal (Detail (DetailItem i) _) -> Just i
          _ -> Nothing
  
  getCurrentItem :: State -> Maybe DetailItem
  getCurrentItem state =
      case state ^. mode of
          Modal (Detail item _) -> Just item
          _ -> Nothing
  
  getCurrentMode :: State -> Maybe DetailMode
  getCurrentMode state =
      case state ^. mode of
          Modal (Detail _ m) -> Just m
          _ -> Nothing
  
  getField :: State -> Maybe Field
  getField state =
      case state ^. mode of
          Modal (Detail _ (DetailInsert f)) -> Just f
          _ -> Nothing
  
  setComplete :: Stateful
  setComplete state = do
      i <- getCurrentSubtask state
      task <- updateSubtask i ST.toggle <$> getCurrentTask state
      setCurrentTask task state
  
  remove :: Stateful
  remove state = do
      i <- getCurrentSubtask state
      task <- removeSubtask i <$> getCurrentTask state
      state' <- setCurrentTask task state
      setIndex state' i
  
  insertMode :: Stateful
  insertMode state = do
      i <- getCurrentSubtask state
      task <- getCurrentTask state
      n <- (^. ST.name) <$> getSubtask i task
      case state ^. mode of
          Modal (Detail (DetailItem i') _) ->
              Just (state & mode .~ Modal (Detail (DetailItem i') (DetailInsert (textToField n))))
          _ -> Nothing
  
  editDescription :: Stateful
  editDescription state = do
      summ <- (^. description) <$> getCurrentTask state
      let summ' = fromMaybe "" summ
      pure $ state & mode .~ Modal (Detail DetailDescription (DetailInsert (textToField summ')))
  
  editDue :: Stateful
  editDue state = do
      day <- (^. due) <$> getCurrentTask state
      let tz = state ^. timeZone
      let day' = maybe "" (timeToDisplay tz) day
      pure $ state & mode .~ Modal (Detail DetailDate (DetailInsert (textToField day')))
  
  newItem :: Stateful
  newItem state = do
      task <- addSubtask ST.blank <$> getCurrentTask state
      setCurrentTask task state
  
  newItemAtIndex :: Int -> Stateful
  newItemAtIndex idx state = do
      task <- addSubtaskAtIndex idx ST.blank <$> getCurrentTask state
      setCurrentTask task state
  
  -- list navigation
  changeSubtask :: Int -> Stateful
  changeSubtask inc state = do
      i <- (+ inc) <$> getCurrentSubtask state
      setIndex state i
  
  nextSubtask :: Stateful
  nextSubtask = changeSubtask 1
  
  previousSubtask :: Stateful
  previousSubtask = changeSubtask (-1)
  
  subTaskAtIndex :: Int -> Stateful
  subTaskAtIndex idx state = setIndex state idx
  
  lastSubtask :: Stateful
  lastSubtask state = lastIndex state >>= setIndex state
  
  lastIndex :: State -> Maybe Int
  lastIndex state = (+ (-1)) . countSubtasks <$> getCurrentTask state
  
  setIndex :: State -> Int -> Maybe State
  setIndex state i = do
      lst <- lastIndex state
      m <- getCurrentMode state
      let newIndex
              | i > lst = lst
              | i < 0 = 0
              | otherwise = i
      return $ state & mode .~ Modal (Detail (DetailItem newIndex) m)
  
  -- moving tasks
  moveVertical :: Int -> Stateful
  moveVertical dir state = do
      task <- getCurrentTask state
      let tasks = task ^. subtasks
      i <- getCurrentSubtask state
      shifted <- S.shiftBy i dir tasks
      state' <- setCurrentTask (task & subtasks .~ shifted) state
      changeSubtask dir state'
  
  up :: Stateful
  up = moveVertical (-1)
  
  down :: Stateful
  down = moveVertical 1
  