{-# LANGUAGE OverloadedStrings #-}
module Dustme where

import           Control.Concurrent       (newEmptyMVar, takeMVar)
import           Control.Concurrent.Async (async, cancel, race)
import           Control.DeepSeq          (force)
import           Control.Exception        (bracket, evaluate)
import qualified Data.Text                as T
import qualified Data.Text.IO             as TIO
import           Dustme.Renderer
import           Dustme.Search
import           Dustme.TTY               (withTTY)
import           Dustme.Types
import           System.IO

dustme config = do
  hSetBuffering stdout NoBuffering
  input <- T.lines <$> TIO.getContents
  let applyOp' = applyOp input
  withTTY "/dev/tty0" (setup applyOp' (map mkTrivialMatch input))

mkTrivialMatch = Match 10000 1 0

setup applyOp' initMatch tty = go 0 initMatch (Search "") emptyCache
  where
    getCommand = takeMVar (ttyGetCommand tty)

    go :: Int -> SearchResult -> Search -> SearchCache -> IO ()
    go    index  matches'         search    cache = do
      let matches = case search of
            (Search "") -> initMatch
            _ -> matches'

      -- the idea here is that that ttyGetCommand can always take
      -- priority over printing. This means that if we type a bunch
      -- of keys in in quick succession, the UI will remain responsive.
      r <- race (evaluate $ force matches) getCommand
      s <- case r of
             Left matches' -> renderSearch tty index matches search >> getCommand
             Right x -> return x

      case s of
        Accept  -> TIO.putStrLn (matchText $ matches !! index)
        Up      -> go (clamp (length matches) (index-1)) matches search cache
        Down    -> go (clamp (length matches) (index+1)) matches search cache
        Edit op ->
          let (newsearch,newcandidates) = applyOp'  op  search matches
              (searchResult, newcache) =
                getResults newcandidates cache newsearch
          in go 0 searchResult newsearch newcache

clamp hi i
 | i < 0     = 0
 | i >= hi   = hi - 1
 | otherwise = i