module System.Terminal.Terminal where

import           Control.Monad.STM
import           Data.ByteString
import           Data.Text

import           System.Terminal.MonadInput
import           System.Terminal.MonadScreen (Size (..), Position (..), EraseMode (..))

-- | Types that represent terminals need to implement this class in order
--   to be driven by this library.
--
-- This library ships with two instances:
--
-- * `System.Terminal.Platform.LocalTerminal` represents the local
--   terminal wired to the process.
-- * `System.Terminal.Virtual.VirtualTerminal` is a minimal in-process
--   terminal emulator designed to be used for unit-testing terminal applications. 
class Terminal t where
  -- | The terminal identification string usually extracted from the
  --   environment variable @TERM@. Should contain values like @xterm@
  --   or @rxvt-unicode@.
  termType              :: t -> ByteString
  -- | A stream of input events. The transaction will succeed as soon as the
  --   next input event becomes available.
  --
  --   Note: Trying to read more than one event within the same transaction
  --   might be successfull, but might also lead to undesired behaviour as
  --   the transaction will block until all of its preconditions are fulfilled.
  termEvent             :: t -> STM Event
  -- | This transaction succeeds as soon as an interrupt occurs.
  --   Executing the transaction shall reset an interrupt flag maintained
  --   by a supervising background thread.
  --
  --   It is mandatory to regularly check this transaction in order to signal
  --   responsiveness to the background thread. The execution environment is otherwise
  --   advised to throw an `System.IO.Error.UserInterrupt` exception as soon as a
  --   second interrupt arrives and it sees a previous one unhandled.
  termInterrupt         :: t -> STM Interrupt
  -- | This operation shall send a command to the terminal.
  --   It shall block when the buffer exeeded its capacity
  --   and unblock as soon as space becomes available again.
  --
  --   Note: All implementations must limit the size of the output buffer or
  --   the application is at risk of running out of memory when writing much
  --   faster than the terminal can read.
  termCommand           :: t -> Command -> IO ()
  -- | This operations flushes the output buffer. Whether it blocks or
  --   not until the buffer has actually been flushed shall be undefined
  --   (there might be other buffers involved that cannot be force-flushed
  --   so it is probably better to not give any guarantees here).
  termFlush             :: t -> IO ()
  -- | This operation shall return the latest known window size without
  --   blocking.
  termGetWindowSize     :: t -> IO Size
  -- | This operation shall return the current cursor position.
  --   It may block as depending on implementation it usually requires an
  --   in-band roundtrip to the terminal. Use it wisely.
  termGetCursorPosition :: t -> IO Position

-- | The commands every terminal needs to understand.
--
-- This shall only be extended when something is missing
-- that all terminals understand. Otherwise portability will
-- be lost.
data Command
  = PutLn
  | PutText                  Text
  | SetAttribute             Attribute
  | ResetAttribute           Attribute
  | ResetAttributes
  | MoveCursorUp             Int
  | MoveCursorDown           Int
  | MoveCursorForward        Int
  | MoveCursorBackward       Int
  | ShowCursor
  | HideCursor
  | SaveCursor
  | RestoreCursor
  | GetCursorPosition
  | SetCursorPosition        Position
  | SetCursorRow             Int
  | SetCursorColumn          Int
  | InsertChars              Int
  | DeleteChars              Int
  | EraseChars               Int
  | InsertLines              Int
  | DeleteLines              Int
  | EraseInLine              EraseMode
  | EraseInDisplay           EraseMode
  | SetAutoWrap              Bool
  | SetAlternateScreenBuffer Bool
  deriving (Eq, Ord, Show)

-- | ANSI text attributes.
data Attribute
  = Bold
  | Italic
  | Underlined
  | Inverted
  | Foreground Color
  | Background Color
  deriving (Eq, Ord, Show)

-- | ANSI colors.
data Color
  = Black
  | Red
  | Green
  | Yellow
  | Blue
  | Magenta
  | Cyan
  | White
  | BrightBlack
  | BrightRed
  | BrightGreen
  | BrightYellow
  | BrightBlue
  | BrightMagenta
  | BrightCyan
  | BrightWhite
  deriving (Eq, Ord, Show)