module Music.Time.Event (
        
        Event,
        
        event,
        eventee,
        spanEvent,
        triple
  ) where
import           Control.Applicative
import           Control.Comonad
import           Control.Lens             hiding (Indexable, Level, above,
                                           below, index, inside, parts,
                                           reversed, transform, (<|), (|>))
import           Control.Monad            (join, mapM)
import           Control.Monad.Compose
import           Data.Distributive        (distribute)
import           Data.Foldable            (Foldable)
import qualified Data.Foldable            as Foldable
import           Data.Functor.Classes
import           Data.Functor.Compose
import           Data.Functor.Couple
import           Data.PairMonad
import           Data.Semigroup
import           Data.String
import           Data.Typeable
import           Data.VectorSpace
import           Data.Aeson                    (ToJSON (..), FromJSON(..))
import qualified Data.Aeson                    as JSON
import           Music.Dynamics.Literal
import           Music.Pitch.Literal
import           Music.Time.Internal.Util (dependingOn, through, tripped)
import           Music.Time.Juxtapose
import           Music.Time.Meta
newtype Event a = Event { getEvent :: Span `Couple` a }
  deriving (Eq, Ord, Typeable, Foldable, Applicative, Monad, Comonad, Traversable,
            Functor, Num, Fractional, Floating, Real, RealFrac)
instance Wrapped (Event a) where
  type Unwrapped (Event a) = (Span, a)
  _Wrapped' = iso (getCouple . getEvent) (Event . Couple)
instance Rewrapped (Event a) (Event b)
instance Transformable (Event a) where
  transform t = over eventSpan (transform t)
instance HasDuration (Event a) where
  _duration = _duration . _era
instance HasPosition (Event a) where
  _era = view eventSpan
instance IsString a => IsString (Event a) where
  fromString = pure . fromString
instance IsPitch a => IsPitch (Event a) where
  fromPitch = pure . fromPitch
instance IsInterval a => IsInterval (Event a) where
  fromInterval = pure . fromInterval
instance IsDynamics a => IsDynamics (Event a) where
  fromDynamics = pure . fromDynamics
instance (Show a, Transformable a) => Show (Event a) where
  show x = show (x^.from event) ++ "^.event"
instance ToJSON a => ToJSON (Event a) where
  
  toJSON a = JSON.object [ ("span", toJSON s), ("value", toJSON x) ]
    where
      (s, x) = a^.from event
instance FromJSON a => FromJSON (Event a) where
  parseJSON (JSON.Object x) = liftA2 (\x y -> (x,y)^.event) era value
    where
      era   = x JSON..: "span" 
      value = x JSON..: "value"
  parseJSON _ = empty
event :: Iso (Span, a) (Span, b) (Event a) (Event b)
event = from _Wrapped
eventSpan :: Lens' (Event a) Span
eventSpan = from event . _1
eventValue :: Lens (Event a) (Event b) a b
eventValue = from event . _2
eventee :: (Transformable a, Transformable b) => Lens (Event a) (Event b) a b
eventee = from event `dependingOn` (transformed)
spanEvent :: Iso' Span (Event ())
spanEvent = iso (\s -> (s,())^.event) (^.era)
triple :: Iso (Event a) (Event b) (Time, Duration, a) (Time, Duration, b)
triple = from event . bimapping onsetAndDuration id . tripped