{-# LANGUAGE Safe #-}

{-
  This module is part of Chatty.
  Copyleft (c) 2014 Marvin Cohrs

  All wrongs reversed. Sharing is an act of love, not crime.
  Please share Antisplice with everyone you like.

  Chatty is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  Chatty is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with Chatty. If not, see <http://www.gnu.org/licenses/>.
-}

-- | Provides an extended printer class that supports colours.
module Text.Chatty.Extended.Printer (ChExtendedPrinter(..),Tone(..),Colour(..),expandClr) where

import Text.Chatty.Printer

-- | Colour tone.
data Tone = Green | Red | Yellow | Blue | Black | White | Cyan | Magenta
-- | Colour brightness
data Colour = Dull Tone | Vivid Tone

-- | Typeclass for all printers that support colourized output.
class ChPrinter m => ChExtendedPrinter m where
  -- | Run the function with the given colour.
  ebracket :: Colour -> m a -> m a
  ebracket Colour
c m a
m = do Colour -> m ()
forall (m :: * -> *). ChExtendedPrinter m => Colour -> m ()
estart Colour
c; a
a <- m a
m; m ()
forall (m :: * -> *). ChExtendedPrinter m => m ()
efin; a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a
  -- | Print the string in the given colour.
  eprint :: Colour -> String -> m ()
  eprint Colour
c = Colour -> m () -> m ()
forall (m :: * -> *) a. ChExtendedPrinter m => Colour -> m a -> m a
ebracket Colour
c (m () -> m ()) -> (String -> m ()) -> String -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> m ()
forall (m :: * -> *). ChPrinter m => String -> m ()
mprint
  -- | Print the string in the given colour and terminate the line.
  eprintLn :: Colour -> String -> m ()
  eprintLn Colour
c String
s = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
eprint Colour
c String
s m () -> m () -> m ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> m ()
forall (m :: * -> *). ChPrinter m => String -> m ()
mprintLn String
""
  -- | Print the string in the given colour without masking.
  enomask :: Colour -> String -> m ()
  enomask Colour
c = Colour -> m () -> m ()
forall (m :: * -> *) a. ChExtendedPrinter m => Colour -> m a -> m a
ebracket Colour
c (m () -> m ()) -> (String -> m ()) -> String -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> m ()
forall (m :: * -> *). ChPrinter m => String -> m ()
mnomask
  -- | Print the string in the given colour without masking and terminate the line.
  enomaskLn :: Colour -> String -> m ()
  enomaskLn Colour
c String
s = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
enomask Colour
c String
s m () -> m () -> m ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> m ()
forall (m :: * -> *). ChPrinter m => String -> m ()
mprintLn String
""
  -- | Start using the specified colour.
  estart :: Colour -> m ()
  -- | Reset colour.
  efin :: m ()


takeBrace :: a -> String -> String
takeBrace a
0 (Char
'}':String
ss) = String
""
takeBrace a
n (Char
'}':String
ss) = Char
'}' Char -> String -> String
forall a. a -> [a] -> [a]
: a -> String -> String
takeBrace (a
na -> a -> a
forall a. Num a => a -> a -> a
-a
1) String
ss
takeBrace a
n (Char
'{':String
ss) = Char
'{' Char -> String -> String
forall a. a -> [a] -> [a]
: a -> String -> String
takeBrace (a
na -> a -> a
forall a. Num a => a -> a -> a
+a
1) String
ss
takeBrace a
n (Char
s:String
ss) = Char
s Char -> String -> String
forall a. a -> [a] -> [a]
: a -> String -> String
takeBrace a
n String
ss
takeBrace a
n [] = String
""

splitBrace :: String -> (String, String)
splitBrace String
ss = let nm :: String
nm = Integer -> String -> String
forall a. (Eq a, Num a) => a -> String -> String
takeBrace Integer
0 String
ss in (String
nm, Int -> String -> String
forall a. Int -> [a] -> [a]
drop (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
nm Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) String
ss)

procClr :: Colour -> String -> m ()
procClr Colour
c String
ss = let (String
nm,String
rm) = String -> (String, String)
splitBrace String
ss in Colour -> m () -> m ()
forall (m :: * -> *) a. ChExtendedPrinter m => Colour -> m a -> m a
ebracket Colour
c (String -> m ()
forall (m :: * -> *). ChExtendedPrinter m => String -> m ()
expandClr String
nm) m () -> m () -> m ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> m ()
forall (m :: * -> *). ChExtendedPrinter m => String -> m ()
expandClr String
rm

expandClr :: ChExtendedPrinter m => String -> m ()
expandClr :: String -> m ()
expandClr (Char
'%':Char
'{':Char
'V':Char
'0':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Vivid Tone
Black) String
ss
expandClr (Char
'%':Char
'{':Char
'V':Char
'1':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Vivid Tone
Red) String
ss
expandClr (Char
'%':Char
'{':Char
'V':Char
'2':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Vivid Tone
Green) String
ss
expandClr (Char
'%':Char
'{':Char
'V':Char
'3':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Vivid Tone
Yellow) String
ss
expandClr (Char
'%':Char
'{':Char
'V':Char
'4':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Vivid Tone
Blue) String
ss
expandClr (Char
'%':Char
'{':Char
'V':Char
'5':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Vivid Tone
Magenta) String
ss
expandClr (Char
'%':Char
'{':Char
'V':Char
'6':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Vivid Tone
Cyan) String
ss
expandClr (Char
'%':Char
'{':Char
'V':Char
'7':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Vivid Tone
White) String
ss
expandClr (Char
'%':Char
'{':Char
'D':Char
'0':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Dull Tone
Black) String
ss
expandClr (Char
'%':Char
'{':Char
'D':Char
'1':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Dull Tone
Red) String
ss
expandClr (Char
'%':Char
'{':Char
'D':Char
'2':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Dull Tone
Green) String
ss
expandClr (Char
'%':Char
'{':Char
'D':Char
'3':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Dull Tone
Yellow) String
ss
expandClr (Char
'%':Char
'{':Char
'D':Char
'4':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Dull Tone
Blue) String
ss
expandClr (Char
'%':Char
'{':Char
'D':Char
'5':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Dull Tone
Magenta) String
ss
expandClr (Char
'%':Char
'{':Char
'D':Char
'6':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Dull Tone
Cyan) String
ss
expandClr (Char
'%':Char
'{':Char
'D':Char
'7':Char
';':String
ss) = Colour -> String -> m ()
forall (m :: * -> *).
ChExtendedPrinter m =>
Colour -> String -> m ()
procClr (Tone -> Colour
Dull Tone
White) String
ss
expandClr (Char
s:String
ss) = String -> m ()
forall (m :: * -> *). ChPrinter m => String -> m ()
mprint [Char
s] m () -> m () -> m ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> m ()
forall (m :: * -> *). ChExtendedPrinter m => String -> m ()
expandClr String
ss
expandClr [] = () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()