{-# LANGUAGE FlexibleInstances #-}

module Chatty.Commands where

import Chatty.Printer
import Chatty.Scanner
import Chatty.Interactor
import Chatty.Finalizer
import Chatty.Expansion
import Control.Monad
import Control.Monad.Trans.Class
import Control.Monad.IO.Class
import System.IO
import System.Directory
import System.Posix.Files

cat :: (MonadScanner m, MonadPrinter m, MonadIO m,Functor m,MonadFinalizer m) => [String] -> m ()
cat [] = mscanL >>= mprint
cat [f] = cat [] .<. f
cat (f:fs) = cat [f] >> cat fs

tac :: (MonadFinalizer m,MonadScanner m, MonadPrinter m, MonadIO m,Functor m) => [String] -> m ()
tac [] = mscanL >>= (mprint . unlines . reverse . lines)
tac fs = cat fs .|. tac []

tee :: (MonadScanner m, MonadPrinter m, MonadIO m, Functor m) => String -> m ()
tee f = do
  s <- mscanL
  mprint s .>. f
  mprint s

echo :: (MonadPrinter m,MonadExpand m) => String => m ()
echo = mprintLn <=< expand

data WcMode = CountChars | CountLines | CountWords

wc :: (MonadScanner m, MonadPrinter m, MonadIO m, Functor m) => WcMode -> m ()
wc CountChars = mscanL >>= (mprint . show . length) >> mprint "\n"
wc CountLines = mscanL >>= (mprint . show . length . lines) >> mprint "\n"
wc CountWords = mscanL >>= (mprint . show . length . words) >> mprint "\n"

cd :: MonadIO m => String -> m ()
cd = liftIO . setCurrentDirectory

pwd :: (MonadIO m,MonadPrinter m) => m ()
pwd = liftIO getCurrentDirectory >>= mprintLn

ls :: (MonadIO m,MonadPrinter m) => [String] -> m ()
ls [] = liftIO (getDirectoryContents ".") >>= (mprint . unlines)
ls [p] = do
  fs <- liftIO $ getFileStatus p
  when (isDirectory fs) $
    liftIO (getDirectoryContents p) >>= (mprint . unlines)
  when (isRegularFile fs) $
    mprintLn p
ls (p:ps) = ls [p] >> ls ps
  
head :: (MonadScanner m,MonadPrinter m,MonadIO m,Functor m) => Int -> m ()
head n = mscanL >>= (mprint . unlines . take n . lines)

tail :: (MonadScanner m,MonadPrinter m,MonadIO m,Functor m) => Int -> m ()
tail n = mscanL >>= (mprint . unlines . reverse . take n . reverse . lines)