{-# LANGUAGE DeriveFunctor         #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Network.DO.IP.Commands where

import           Control.Comonad.Trans.Cofree
import           Control.Monad.Trans.Free
import           Data.IP
import           Network.DO.Pairing
import           Network.DO.Types
import           Prelude                      as P

-- functor for DO DSL
data IPCommands a = ListFloatingIPs ([FloatingIP] -> a)
                  | CreateIP FloatingIPTarget (Result FloatingIP -> a)
                  | DeleteIP IP (Maybe String -> a)
                  | ActionIP IP IPAction (Result (ActionResult IPActionType) -> a)
          deriving (Functor)

-- free transformer to embed effects
type IPCommandsT = FreeT IPCommands

-- smart constructors
listFloatingIPs :: IPCommands [FloatingIP]
listFloatingIPs = ListFloatingIPs P.id

createFloatingIP :: FloatingIPTarget -> IPCommands (Result FloatingIP)
createFloatingIP target = CreateIP target P.id

deleteFloatingIP :: IP -> IPCommands (Maybe String)
deleteFloatingIP ip = DeleteIP ip P.id

floatingIPAction :: IP -> IPAction -> IPCommands (Result (ActionResult IPActionType))
floatingIPAction ip action = ActionIP ip action P.id

-- dual type, for creating interpreters
data CoIPCommands m k =
  CoIPCommands { listFloatingIPsH  :: (m [FloatingIP], k)
               , createFloatingIPH :: FloatingIPTarget -> (m (Result FloatingIP), k)
               , deleteIPH         :: IP -> (m (Maybe String), k)
               , actionIPH         :: IP -> IPAction -> (m (Result (ActionResult IPActionType)), k)
               } deriving Functor

-- Cofree closure of CoIPCommands functor
type CoIPCommandsT m = CofreeT (CoIPCommands m)

-- pair DSL with interpreter within some monadic context
instance (Monad m) => PairingM (CoIPCommands m) IPCommands m where
  pairM f (CoIPCommands ks _ _ _)    (ListFloatingIPs k)   = pairM f ks k
  pairM f (CoIPCommands _  tgt _ _)  (CreateIP i k)        = pairM f (tgt i) k
  pairM f (CoIPCommands _  _  del _) (DeleteIP i k)        = pairM f (del i) k
  pairM f (CoIPCommands _  _  _ act) (ActionIP i a k)      = pairM f (act i a) k