module Yi.Event 
    (
     Event(..), prettyEvent,
     Key(..), Modifier(..),

     -- * Key codes
     eventToChar
    ) where

import Data.Bits
import Data.Char (chr,ord)
import Data.Monoid
import Data.List ( (!!) )
import Yi.Prelude
import Prelude ()

data Modifier = MShift | MCtrl | MMeta | MSuper | MHyper
                deriving (Show,Eq,Ord)

data Key = KEsc | KFun Int | KPrtScr | KPause | KASCII Char | KBS | KIns
         | KHome | KPageUp | KDel | KEnd | KPageDown | KNP5 | KUp | KMenu
         | KLeft | KDown | KRight | KEnter | KTab deriving (Eq,Show,Ord)

data Event = Event Key [Modifier] deriving (Eq)

instance Ord Event where
    compare (Event k1 m1) (Event k2 m2) = compare m1 m2 `mappend` compare k1 k2
    -- so, all Ctrl+char, meta+char, etc. all form a continuous range

instance Show Event where
    show = prettyEvent

prettyEvent :: Event -> String
prettyEvent (Event k mods) =
           concatMap ((++ "-") . prettyModifier) mods ++ prettyKey k
  where prettyKey (KFun i) = 'F' : show i
        prettyKey (KASCII c) = [c]
        prettyKey key = tail $ show key
        prettyModifier m = [ show m !! 1]
      


-- | Map an Event to a Char. This is used in the emacs keymap for Ctrl-Q and vim keymap 'insertSpecialChar'
eventToChar :: Event -> Char
eventToChar (Event KEnter _) = '\CR'
eventToChar (Event KEsc _)   = '\ESC'
eventToChar (Event KBS _)    = '\127'
eventToChar (Event KTab _)   = '\t'

eventToChar (Event (KASCII c) mods) = (if MMeta `elem` mods then setMeta else id) $
                                      (if MCtrl `elem` mods then ctrlLowcase else id) $
                                      c

eventToChar _ev = '?'



remapChar :: Char -> Char -> Char -> Char -> Char -> Char
remapChar a1 b1 a2 _ c
    | a1 <= c && c <= b1 = chr $ ord c - ord a1 + ord a2
    | otherwise          = c

ctrlLowcase :: Char -> Char
ctrlLowcase   = remapChar 'a'   'z'   '\^A' '\^Z'

-- set the meta bit, as if Mod1/Alt had been pressed
setMeta :: Char -> Char
setMeta c = chr (setBit (ord c) metaBit)

metaBit :: Int
metaBit = 7



