    module Sound.MIDI.Writer.Status (
       module Sound.MIDI.Writer.Status,
       lift,
       ) where

    -- import qualified Sound.MIDI.Writer.Basic as Writer

    import Sound.MIDI.Parser.Status (Channel)

    import qualified Data.Monoid.State       as State
    import qualified Data.Monoid.Reader      as Reader
    import qualified Data.Monoid.Transformer as Trans
    import Data.Monoid.Transformer (lift, )

    import Data.Monoid (Monoid, mempty, mappend, mconcat, )
    import Sound.MIDI.Monoid (genAppend, genConcat, )

    type Status = Maybe (Int,Channel)

    {- |
    The ReaderT Bool handles
    whether running status should be respected (True) or ignored (False).
    -}
    newtype T writer =
       Cons {decons :: Reader.T Bool (State.T (Maybe Status) writer)}

    instance Monoid writer => Monoid (T writer) where
       mempty = Cons $ mempty
       mappend = genAppend Cons decons
       mconcat = genConcat Cons decons

    {- |
    Given a writer that emits a status, generate a stateful writer,
    that decides whether to run the status emittor.
    -}
    change :: (Monoid writer) => Status -> writer -> T writer
    change x emit =
       Cons $
       Reader.Cons $ \b ->
       State.Cons $ \my ->
          let mx = Just x
          in  (if not b || mx/=my then emit else mempty, mx)

    clear :: (Monoid writer) => T writer
    clear = Cons $ lift $ State.put Nothing

    instance Trans.C T where
       lift = fromWriter

    fromWriter :: (Monoid writer) => writer -> T writer
    fromWriter = Cons . lift . lift

    toWriter :: (Monoid writer) => Bool -> T writer -> writer
    toWriter withStatus =
       State.evaluate Nothing . flip Reader.run withStatus . decons

    toWriterWithStatus :: (Monoid writer) => T writer -> writer
    toWriterWithStatus = toWriter True

    toWriterWithoutStatus :: (Monoid writer) => T writer -> writer
    toWriterWithoutStatus = toWriter False