packages feed

imprevu-0.1.0: src/Imprevu/Types.hs

{-# LANGUAGE CPP                       #-}
{-# LANGUAGE DataKinds                 #-}
{-# LANGUAGE DeriveDataTypeable        #-}
{-# LANGUAGE DeriveGeneric             #-}
{-# LANGUAGE EmptyDataDecls            #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleInstances         #-}
{-# LANGUAGE GADTs                     #-}
{-# LANGUAGE KindSignatures            #-}
{-# LANGUAGE MultiParamTypeClasses     #-}
{-# LANGUAGE ScopedTypeVariables       #-}
{-# LANGUAGE StandaloneDeriving        #-}
{-# LANGUAGE TemplateHaskell           #-}
{-# LANGUAGE DeriveGeneric             #-}
{-# LANGUAGE RankNTypes                #-}
{-# LANGUAGE TypeFamilies              #-}
{-# LANGUAGE FlexibleContexts          #-}

-- | This module contains the type definitions necessary to build a Nomic rule.
module Imprevu.Types where

import           Control.Applicative hiding (Const)
import           Control.Lens
import           Control.Shortcut
import           Control.Monad
import           Data.Typeable
import           GHC.Generics

-- * Event

-- | Composable events
data EventM n a where
   SumEvent       :: EventM n a -> EventM n a -> EventM n a                        -- The first event to fire will be returned
   AppEvent       :: EventM n (a -> b) -> EventM n a -> EventM n b                 -- Both events should fire, and then the result is returned
   PureEvent      :: a -> EventM n a                                         -- Create a fake event. The result is useable with no delay.
   EmptyEvent     :: EventM n a                                              -- An event that is never fired.
   BindEvent      :: EventM n a -> (a -> EventM n b) -> EventM n b                 -- A First event should fire, then a second event is constructed
   ShortcutEvents :: [EventM n a] -> ([Maybe a] -> Bool) -> EventM n [Maybe a]  -- Return the intermediate results as soon as the function evaluates to True, dismissing the events that hasn't fired yet
   SignalEvent    :: (Eq s, Typeable s, Show s, Typeable a, Show a) => Signal s a -> EventM n a                                  -- Embed a single Signal as an EventM
   LiftEvent      :: n a -> EventM n a                                       -- create an event containing the result of the monad evaluation
   deriving Typeable

instance Functor (EventM n) where
   fmap f a = pure f <*> a

instance Applicative (EventM n) where
   pure = PureEvent
   (<*>) = AppEvent

instance Alternative (EventM n) where
   (<|>) = SumEvent
   empty = EmptyEvent

instance Monad (EventM n) where
   (>>=) = BindEvent
   return = PureEvent

instance MonadPlus (EventM n) where
   mplus = SumEvent
   mzero = EmptyEvent

instance Shortcutable (EventM n) where
   shortcut = ShortcutEvents

type ClientNumber = Int

data Signal s a where
  Signal :: s -> Signal s a

deriving instance (Show s, Show a) => Show (Signal s a)
deriving instance (Eq s) => Eq (Signal s a)
deriving instance (Typeable s, Typeable a) => Typeable (Signal s a)

data Input = Input InputField ClientNumber
   deriving (Show, Read, Eq, Ord, Typeable, Generic)

-- | Input forms as programmed by the user
data InputField = Text     String
                | TextArea String
                | Button   String
                | Radio    String [(Int, String)]
                | Checkbox String [(Int, String)]
                deriving (Show, Read, Eq, Ord, Typeable, Generic)

-- data sent back by the form fields
data InputData = RadioData    Int
               | CheckboxData [Int]
               | TextData     String
               | TextAreaData String
               | ButtonData
               deriving (Show, Read, Eq, Ord, Typeable)

-- | Type agnostic base signal
data SomeSignal = forall a s. (Typeable a, Typeable s, Show a, Show s) => SomeSignal (Signal s a)

deriving instance Show SomeSignal

-- | Type agnostic result data
data SomeData = forall e. (Typeable e, Show e) => SomeData e

deriving instance Show SomeData



-- * EventInfoN

type EventNumber = Int
type EventName = String

-- EventInfoN holds all infos on an active event
data EventInfoN n = forall a. (Typeable a, Show a) =>
   EventInfo {_eventNumber :: EventNumber,
              event        :: EventM n a,
              handler      :: (EventNumber, a) -> n (),
              _evStatus    :: Status,
              _env         :: [SignalOccurence]}

instance Eq (EventInfoN n) where
   (EventInfo {_eventNumber=e1}) == (EventInfo {_eventNumber=e2}) = e1 == e2

instance Ord (EventInfoN n) where
   (EventInfo {_eventNumber=e1}) <= (EventInfo {_eventNumber=e2}) = e1 <= e2

instance Show (EventInfoN n) where
   show (EventInfo en _ _ s envi) =
      "event num: " ++ (show en) ++
      ", envs: " ++ (show envi) ++
      ", status: " ++ (show s)

eventNumber :: Lens' (EventInfoN n) EventNumber
eventNumber f (EventInfo e ev h evs env) = fmap (\e' -> (EventInfo e' ev h evs env)) (f e)

evStatus :: Lens' (EventInfoN n) Status
evStatus f (EventInfo e ev h evs env) = fmap (\evs' -> (EventInfo e ev h evs' env)) (f evs)

env :: Lens' (EventInfoN n) [SignalOccurence]
env f (EventInfo e ev h evs env) = fmap (\env' -> (EventInfo e ev h evs env')) (f env)

-- status of an event
data Status = SActive | SDeleted deriving (Eq, Show)

-- data and addres from an occurence of a signal
data SignalOccurence = SignalOccurence {_signalOccData    :: SignalData,
                                        _signalOccAddress :: SignalAddress}

deriving instance Show SignalOccurence

-- result data from a signal
data SignalData = forall s a. (Typeable s, Typeable a, Show s, Show a, Eq s) =>
   SignalData {signal     :: Signal s a,
               signalData :: a}

instance Show SignalData where
  show (SignalData s sd) = show s ++ " " ++ (show sd)

-- SignalAddress is a representation of the address of a signal in the event tree
type SignalAddress = [SignalAddressElem]
data SignalAddressElem = SumR | SumL | AppR | AppL | BindR | BindL | Shortcut deriving (Show, Read, Ord, Eq, Generic)

makeLenses ''SignalOccurence