{-|
Module      : $Header$
Description : A trick for explicit recursion/update
Copyright   : (c) David Janin, Simon Archipoff, 2016
License     : see the LICENSE file in the distribution
Maintainer  : janin@labri.fr
Stability   : experimental

The key class to allow on-the-fly updates of recursive tile definitions.
No possible realtime tile programming without it.

-}

{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}

{-# LANGUAGE MultiParamTypeClasses,
             FlexibleInstances #-}
             
module Reactive.Updatable where

import Reactive.Input
--------------------
-- * Class Updatable
--------------------

-- | Type of updates
type UpdateData d iv = (d->d, InQList d iv -> InQList d iv)


-- | Type p can be update via type v
class Updatable p d iv where
      update :: UpdateData d iv -> p -> p


-- | On-the fly updates of inputs
instance Updatable (InQList d iv) d iv where
     update  (f,nq) (InQList al (IDQ d q)) = InQList (fmap (\(d1,v1) -> (f d1,v1)) al) (IDQ (f d) $ update (f,nq) q)
     update  (_,_) InQEnd = InQEnd
     update  (_,nq) InQUndef = nq InQUndef


-- | No update needed
instance Updatable Integer d iv where
  update _ = id

-- | No update needed
instance Updatable Bool d iv where
  update _ = id

-- | No update needed
instance Updatable Int d iv where
  update _ = id

-- | No update needed
instance Updatable Rational d iv where
  update _ = id

-- | No update needed
instance Updatable Char d iv where
  update _ = id

-- | No update needed
instance Updatable () d iv where
  update _ = id

-- | Closure under Maybe
instance Updatable p d iv => Updatable (Maybe p) d iv where
  update _ Nothing = Nothing
  update u (Just p) = Just (update u p)

-- | Closure under list functor
instance  Updatable p d iv => Updatable [p] d iv where
  update u l = map (update u) l


-- | Closure under binary Cartesian product 
instance  (Updatable p1 d iv, Updatable p2 d iv) => Updatable (p1,p2) d iv where
  update u (p1,p2) = (update u p1, update u p2)

-- | Closure under ternary Cartesian product 
instance  (Updatable p1 d iv, Updatable p2 d iv, Updatable p3 d iv) => Updatable (p1,p2,p3) d iv where
  update u (p1,p2,p3) = (update u p1, update u p2,update u p3)

-- | Closure under fourary Cartesian product 
instance  (Updatable p1 d iv, Updatable p2 d iv, Updatable p3 d iv, Updatable p4 d iv) => Updatable (p1,p2,p3,p4) d iv where
  update u (p1,p2,p3,p4) = (update u p1, update u p2, update u p3, update u p4)

-- | Closure under binary disjoint sum
instance (Updatable p1 d iv, Updatable p2 d iv) => Updatable (Either p1 p2) d iv where
  update u (Left p1) = Left (update u p1)
  update u (Right p2) = Right (update u p2)


-- | Closure under exponentiation
instance  Updatable p d iv => Updatable (p -> q) d iv where
  update u f = f -- \p -> f (update u p)