-- | Nrt editing
module Sound.Sc3.Server.Nrt.Edit where

import Data.List {- base -}

import qualified Data.List.Ordered {- data-ordlist -}

import qualified Sound.Osc.Datum as Osc {- hosc -}
import qualified Sound.Osc.Packet as Osc {- hosc -}

import qualified Sound.Sc3.Common.Base {- hsc3 -}
import qualified Sound.Sc3.Server.Command {- hsc3 -}
import Sound.Sc3.Server.Nrt {- hsc3 -}

-- | Merge two Nrt scores.  Retains internal nrt_end messages.
nrt_merge :: Nrt -> Nrt -> Nrt
nrt_merge :: Nrt -> Nrt -> Nrt
nrt_merge (Nrt [BundleOf Message]
p) (Nrt [BundleOf Message]
q) = [BundleOf Message] -> Nrt
Nrt ([BundleOf Message] -> [BundleOf Message] -> [BundleOf Message]
forall a. Ord a => [a] -> [a] -> [a]
Data.List.Ordered.merge [BundleOf Message]
p [BundleOf Message]
q)

-- | Merge a set of Nrt.  Retains internal 'nrt_end' messages.
nrt_merge_set :: [Nrt] -> Nrt
nrt_merge_set :: [Nrt] -> Nrt
nrt_merge_set = (Nrt -> Nrt -> Nrt) -> Nrt -> [Nrt] -> Nrt
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Nrt -> Nrt -> Nrt
nrt_merge Nrt
nrt_empty

-- | The empty Nrt.
nrt_empty :: Nrt
nrt_empty :: Nrt
nrt_empty = [BundleOf Message] -> Nrt
Nrt []

-- | Add bundle at first permissable location of Nrt.
nrt_insert_pre :: Osc.BundleOf Osc.Message -> Nrt -> Nrt
nrt_insert_pre :: BundleOf Message -> Nrt -> Nrt
nrt_insert_pre BundleOf Message
p (Nrt [BundleOf Message]
q) = [BundleOf Message] -> Nrt
Nrt (BundleOf Message -> [BundleOf Message] -> [BundleOf Message]
forall a. Ord a => a -> [a] -> [a]
insert BundleOf Message
p [BundleOf Message]
q)

-- | Add bundle at last permissable location of Nrt.
nrt_insert_post :: Osc.BundleOf Osc.Message -> Nrt -> Nrt
nrt_insert_post :: BundleOf Message -> Nrt -> Nrt
nrt_insert_post BundleOf Message
p (Nrt [BundleOf Message]
q) = [BundleOf Message] -> Nrt
Nrt (BundleOf Message -> [BundleOf Message] -> [BundleOf Message]
forall a. Ord a => a -> [a] -> [a]
Sound.Sc3.Common.Base.insert_post BundleOf Message
p [BundleOf Message]
q)

-- | bundleTime of last of nrt_bundles.
nrt_end_time :: Nrt -> Osc.Time
nrt_end_time :: Nrt -> Time
nrt_end_time = BundleOf Message -> Time
forall t. BundleOf t -> Time
Osc.bundleTime (BundleOf Message -> Time)
-> (Nrt -> BundleOf Message) -> Nrt -> Time
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [BundleOf Message] -> BundleOf Message
forall a. HasCallStack => [a] -> a
last ([BundleOf Message] -> BundleOf Message)
-> (Nrt -> [BundleOf Message]) -> Nrt -> BundleOf Message
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Nrt -> [BundleOf Message]
nrt_bundles

-- | Delete any internal nrt_end messages, and require one at the final bundle.
nrt_close :: Nrt -> Nrt
nrt_close :: Nrt -> Nrt
nrt_close (Nrt [BundleOf Message]
l) =
  let is_nrt_end_msg :: Message -> Bool
is_nrt_end_msg = (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"/nrt_end") (String -> Bool) -> (Message -> String) -> Message -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Message -> String
Osc.messageAddress
      bundle_map :: (Time -> Time) -> ([t] -> [t]) -> BundleOf t -> BundleOf t
bundle_map Time -> Time
t_f [t] -> [t]
m_f (Osc.Bundle Time
t [t]
m) = Time -> [t] -> BundleOf t
forall t. Time -> [t] -> BundleOf t
Osc.Bundle (Time -> Time
t_f Time
t) ([t] -> [t]
m_f [t]
m) -- apply temporal and message functions to bundle
      rem_end_msg :: BundleOf Message -> BundleOf Message
rem_end_msg = (Time -> Time)
-> ([Message] -> [Message]) -> BundleOf Message -> BundleOf Message
forall {t} {t}.
(Time -> Time) -> ([t] -> [t]) -> BundleOf t -> BundleOf t
bundle_map Time -> Time
forall a. a -> a
id ((Message -> Bool) -> [Message] -> [Message]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (Message -> Bool) -> Message -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Message -> Bool
is_nrt_end_msg))
      req_end_msg :: BundleOf Message -> BundleOf Message
req_end_msg =
        let f :: [Message] -> [Message]
f [Message]
m =
              if (Message -> Bool) -> [Message] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Message -> Bool
is_nrt_end_msg [Message]
m
                then [Message]
m
                else [Message]
m [Message] -> [Message] -> [Message]
forall a. [a] -> [a] -> [a]
++ [Message
Sound.Sc3.Server.Command.nrt_end]
        in (Time -> Time)
-> ([Message] -> [Message]) -> BundleOf Message -> BundleOf Message
forall {t} {t}.
(Time -> Time) -> ([t] -> [t]) -> BundleOf t -> BundleOf t
bundle_map Time -> Time
forall a. a -> a
id [Message] -> [Message]
f
  in [BundleOf Message] -> Nrt
Nrt ((BundleOf Message -> BundleOf Message)
-> (BundleOf Message -> BundleOf Message)
-> [BundleOf Message]
-> [BundleOf Message]
forall a b. (a -> b) -> (a -> b) -> [a] -> [b]
Sound.Sc3.Common.Base.at_last BundleOf Message -> BundleOf Message
rem_end_msg BundleOf Message -> BundleOf Message
req_end_msg [BundleOf Message]
l)

-- | Append /q/ to /p/, assumes last timestamp at /p/ precedes first at /q/.
nrt_append :: Nrt -> Nrt -> Nrt
nrt_append :: Nrt -> Nrt -> Nrt
nrt_append (Nrt [BundleOf Message]
p) (Nrt [BundleOf Message]
q) = [BundleOf Message] -> Nrt
Nrt ([BundleOf Message]
p [BundleOf Message] -> [BundleOf Message] -> [BundleOf Message]
forall a. [a] -> [a] -> [a]
++ [BundleOf Message]
q)