content: -- | a replay recording system.
  module Recorder (
    Recorder(..),
    initialRecorder,
    RecorderMode(..),
    encode2,
    decode,
    ) where
  
  import           Game
  import           Graphics.UI.GLUT
  import           Monadius
  import           Util
  
  data Recorder = Recorder{
        keybuf           :: [[Key]],
        preEncodedKeyBuf :: [Int],
        mode             :: RecorderMode,
        gameBody         :: Monadius,
        age              :: Int,
        isQuitRequested  :: Bool}
  
  data RecorderMode = Play | Playback | Record
                      deriving (Eq,Show)
  
  instance Game Recorder where
    update = updateRecorder
    render = renderRecorder
    isGameover = recorderIsGameover
  
  encode2 :: [Int] -> String
  encode2 = show . reverse
  
  encodeKeySet :: [Key] -> Int
  encodeKeySet keys = sum $ map (\i->if (importantKeys!!i) `elem` keys then 2^i else 0) [0..(length importantKeys-1)]
  
  decode :: String -> [[Key]]
  decode str = map decodeKeySet (read str :: [Int])
  
  decodeKeySet :: Int -> [Key]
  decodeKeySet num = extract num importantKeys where
    extract 0 _     = []
    extract _ []    = []
    extract i (c:cs) = (if i `mod` 2 == 1 then [c] else []) ++ extract (i `div` 2) cs
  
  importantKeys :: [Key]
  importantKeys = [shotButton,missileButton,powerUpButton,upButton,downButton,leftButton,rightButton,selfDestructButton]
  
  initialRecorder :: RecorderMode -> [[Key]] -> Monadius -> Recorder
  initialRecorder initialMode keyss initialGame = Recorder{
    keybuf = if initialMode == Playback then keyss ++ repeat [] else [],
    preEncodedKeyBuf = [],
    mode = initialMode,
    gameBody = initialGame,
    age=0,
    isQuitRequested = False }
  
  updateRecorder::[Key]->Recorder->Recorder
  updateRecorder keys me = me{
    --keybuf = (if mode me == Record then (++ [keys]) else id) $ keybuf me,
    preEncodedKeyBuf = (if mode me == Record then (encodeKeySet keys:) else id) $ preEncodedKeyBuf me,
    gameBody = (if mode me /= Playback then update keys else update (keybuf me!!age me)) $ gameBody me,
    age = age me + 1,
    isQuitRequested = (mode me == Playback && (selfDestructButton `elem` keys || Char ' ' `elem` keys)) || isQuitRequested me
  }
  
  renderRecorder :: Recorder -> IO ()
  renderRecorder me = do
    (putDebugStrLn.show.mode) me
    if age me==0 || mode me /= Record then return () else preservingMatrix $ do
      translate (Vector3 300 (-230) (0::GLdouble))
      scale 0.1 0.1 (0.1 :: GLdouble)
      color (Color3 0.4  0.4 (0.4 :: GLdouble))
      renderString Roman $ show $ (head.preEncodedKeyBuf) me
  
    render $ gameBody me
  
  recorderIsGameover :: Recorder -> Bool
  recorderIsGameover me = (isGameover . gameBody) me || isQuitRequested me
  
  
  
  
  
  