{-# LANGUAGE TemplateHaskell, QuasiQuotes, FlexibleInstances, MultiParamTypeClasses, TypeSynonymInstances, FlexibleContexts, UndecidableInstances #-}

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

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

  Antisplice 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.

  Antisplice 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 Antisplice. If not, see <http://www.gnu.org/licenses/>.
-}

-- | Provides (chatty-compatible) templates for automatical instance derivation.
module Game.Antisplice.Templates where

import Language.Haskell.TH
import Text.Chatty.Templates
import Game.Antisplice.Utils.Fail
import Game.Antisplice.Utils.Run
import Game.Antisplice.Utils.Counter
import Game.Antisplice.Monad.Dungeon
import Game.Antisplice.Monad.Vocab
import Game.Antisplice.Utils.Atoms
import Control.Monad.Error.Class
import Control.Monad.Trans.Class
import Control.Monad.State.Class
import Control.Monad.IO.Class

-- | Automatically derive an instance for 'MonadRoom'
mkRoom s = [d|
    instance MonadRoom m => MonadRoom ($sx m) where
      getRoomState = lift getRoomState
      putRoomState = lift . putRoomState
  |]             
  where sx = strToType s

-- | Automatically derive an instance for 'MonadError e'
mkFail e s = [d|
    instance (MonadError $ex m,Run $sx) => MonadError $ex ($sx m) where
      throwError = lift . throwError
      catchError = error "catchError not implemented for this type."
  |]
  where sx = strToType s
        ex = strToType e

-- | Automatically derive an instance for 'MonadDungeon'
mkDungeon s = [d|
    instance MonadDungeon m => MonadDungeon ($sx m) where
      getDungeonState = lift getDungeonState
      putDungeonState = lift . putDungeonState
  |]
  where sx = strToType s

-- | Automatically derive an instance for 'MonadCounter'
mkCounter s = [d|
    instance MonadCounter m => MonadCounter ($sx m) where
      countOn = lift countOn
  |]
  where sx = strToType s

-- | Automatically derive an instance for 'MonadObject'
mkObject s = [d|
    instance MonadObject m => MonadObject ($sx m) where
      getObjectState = lift getObjectState
      putObjectState = lift . putObjectState
  |]
  where sx = strToType s

-- | Automatically derive an instance for 'MonadPlayer'
mkPlayer s = [d|
    instance MonadPlayer m => MonadPlayer ($sx m) where
      getPlayerState = lift getPlayerState
      putPlayerState = lift . putPlayerState
  |]
  where sx = strToType s

-- | Automatically derive an instance for 'MonadIO'
mkIO s = [d|
    instance MonadIO m => MonadIO ($sx m) where
      liftIO = lift . liftIO
  |]
  where sx = strToType s

-- | Automatically derive an instance for 'MonadVocab'
mkVocab s = [d|
    instance MonadVocab m => MonadVocab ($sx m) where
      lookupVocab = lift . lookupVocab
      insertVocab k = lift . insertVocab k
      vocabKnown = lift . vocabKnown
  |]
  where sx = strToType s

-- | Automatically derive an instance for 'MonadAtoms'
mkAtoms s = [d|
    instance MonadAtoms m => MonadAtoms ($sx m) where
      newAtom = lift newAtom
      putAtom k = lift . putAtom k
      getAtom = lift . getAtom
      dispAtom = lift . dispAtom
      cloneAtom = lift . cloneAtom
  |]           
  where sx = strToType s