    module Medium.Plain.List where

    import qualified Medium
    import qualified Medium.Temporal as Temporal

    import Haskore.General.Utility(maximum0)

    import Control.Applicative (liftA, )
    import Data.Foldable (Foldable(foldMap))
    import Data.Traversable (Traversable(sequenceA))
    import qualified Data.Traversable as Traversable

    data T a = Primitive a
             | Serial   [T a]  -- sequential composition
             | Parallel [T a]  -- parallel composition
       deriving (Show, Eq, Ord {- for use in FiniteMap -})

    instance Medium.Construct T where
       prim = Primitive

       {- If the operands are also Serials or Parallels
          the lists are joined,
          since most times the operators are used to construct lists.
          This definition works also for infinite application of (+:+). -}
       (+:+) x y = Serial   (serialToList   x ++ serialToList   y)
       (=:=) x y = Parallel (parallelToList x ++ parallelToList y)

       serial   = Serial
       parallel = Parallel

       serial1   = Serial
       parallel1 = Parallel

    instance Medium.C T where
       switchBinary f _ _ _ (Primitive     x)      = f x
       switchBinary _ g _ _ (Serial   (m:ms)) = g m (Serial   ms)
       switchBinary _ _ h _ (Parallel (m:ms)) = h m (Parallel ms)
       switchBinary _ _ _ z _ = z

       switchList f _ _ (Primitive     x) = f x
       switchList _ g _ (Serial   m) = g m
       switchList _ _ h (Parallel m) = h m

    instance Functor T where
       fmap f = Medium.foldList (Primitive . f) Serial Parallel
    --   fmap = Traversable.fmapDefault

    instance Foldable T where
       foldMap = Traversable.foldMapDefault

    instance Traversable T where
       sequenceA =
          Medium.foldList
             (liftA Primitive)
             (liftA Serial . sequenceA)
             (liftA Parallel . sequenceA)

    instance (Temporal.C a) => Temporal.C (T a) where
       dur  = Medium.foldList Temporal.dur sum maximum0
       none = Medium.prim . Temporal.none

    {- This behaves identical to Medium.Plain.Binary,
       if the top most constructor is no serial composition
       it returns a single element list. -}
    serialToList, parallelToList :: T a -> [T a]

    serialToList (Serial ns) = ns
    serialToList n           = [n]

    parallelToList (Parallel ns) = ns
    parallelToList n             = [n]