    -- | Data types for OSC messages, bundles and packets.
    module Sound.OSC.Packet where

    import Data.List {- base -}

    import Sound.OSC.Datum {- hosc3 -}
    import Sound.OSC.Time {- hosc3 -}

    -- * Message

    -- | OSC address pattern.  This is strictly an ASCII value, however it
    --   is very common to pattern match on addresses and matching on
    --   'C.ByteString' requires @OverloadedStrings@.
    type Address_Pattern = String

    -- | An OSC message, an 'Address_Pattern' and a sequence of 'Datum'.
    data Message = Message {Message -> Address_Pattern
    messageAddress :: Address_Pattern
                           ,Message -> [Datum]
    messageDatum :: [Datum]}
                   deriving (Message -> Message -> Bool
    (Message -> Message -> Bool)
    -> (Message -> Message -> Bool) -> Eq Message
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Message -> Message -> Bool
    $c/= :: Message -> Message -> Bool
    == :: Message -> Message -> Bool
    $c== :: Message -> Message -> Bool
    Eq,ReadPrec [Message]
    ReadPrec Message
    Int -> ReadS Message
    ReadS [Message]
    (Int -> ReadS Message)
    -> ReadS [Message]
    -> ReadPrec Message
    -> ReadPrec [Message]
    -> Read Message
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    readListPrec :: ReadPrec [Message]
    $creadListPrec :: ReadPrec [Message]
    readPrec :: ReadPrec Message
    $creadPrec :: ReadPrec Message
    readList :: ReadS [Message]
    $creadList :: ReadS [Message]
    readsPrec :: Int -> ReadS Message
    $creadsPrec :: Int -> ReadS Message
    Read,Int -> Message -> ShowS
    [Message] -> ShowS
    Message -> Address_Pattern
    (Int -> Message -> ShowS)
    -> (Message -> Address_Pattern)
    -> ([Message] -> ShowS)
    -> Show Message
    forall a.
    (Int -> a -> ShowS)
    -> (a -> Address_Pattern) -> ([a] -> ShowS) -> Show a
    showList :: [Message] -> ShowS
    $cshowList :: [Message] -> ShowS
    show :: Message -> Address_Pattern
    $cshow :: Message -> Address_Pattern
    showsPrec :: Int -> Message -> ShowS
    $cshowsPrec :: Int -> Message -> ShowS
    Show)

    -- | 'Message' constructor.  It is an 'error' if the 'Address_Pattern'
    -- doesn't conform to the OSC specification.
    message :: Address_Pattern -> [Datum] -> Message
    message :: Address_Pattern -> [Datum] -> Message
    message a :: Address_Pattern
    a xs :: [Datum]
    xs =
        case Address_Pattern
    a of
          '/':_ -> Address_Pattern -> [Datum] -> Message
    Message Address_Pattern
    a [Datum]
    xs
          _ -> Address_Pattern -> Message
    forall a. HasCallStack => Address_Pattern -> a
    error "message: ill-formed address pattern"

    -- * Bundle

    -- | An OSC bundle, a 'Time' and a sequence of 'Message's.
    data Bundle = Bundle {Bundle -> Time
    bundleTime :: Time
                         ,Bundle -> [Message]
    bundleMessages :: [Message]}
                  deriving (Bundle -> Bundle -> Bool
    (Bundle -> Bundle -> Bool)
    -> (Bundle -> Bundle -> Bool) -> Eq Bundle
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Bundle -> Bundle -> Bool
    $c/= :: Bundle -> Bundle -> Bool
    == :: Bundle -> Bundle -> Bool
    $c== :: Bundle -> Bundle -> Bool
    Eq,ReadPrec [Bundle]
    ReadPrec Bundle
    Int -> ReadS Bundle
    ReadS [Bundle]
    (Int -> ReadS Bundle)
    -> ReadS [Bundle]
    -> ReadPrec Bundle
    -> ReadPrec [Bundle]
    -> Read Bundle
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    readListPrec :: ReadPrec [Bundle]
    $creadListPrec :: ReadPrec [Bundle]
    readPrec :: ReadPrec Bundle
    $creadPrec :: ReadPrec Bundle
    readList :: ReadS [Bundle]
    $creadList :: ReadS [Bundle]
    readsPrec :: Int -> ReadS Bundle
    $creadsPrec :: Int -> ReadS Bundle
    Read,Int -> Bundle -> ShowS
    [Bundle] -> ShowS
    Bundle -> Address_Pattern
    (Int -> Bundle -> ShowS)
    -> (Bundle -> Address_Pattern)
    -> ([Bundle] -> ShowS)
    -> Show Bundle
    forall a.
    (Int -> a -> ShowS)
    -> (a -> Address_Pattern) -> ([a] -> ShowS) -> Show a
    showList :: [Bundle] -> ShowS
    $cshowList :: [Bundle] -> ShowS
    show :: Bundle -> Address_Pattern
    $cshow :: Bundle -> Address_Pattern
    showsPrec :: Int -> Bundle -> ShowS
    $cshowsPrec :: Int -> Bundle -> ShowS
    Show)

    -- | OSC 'Bundle's can be ordered (time ascending).
    instance Ord Bundle where
        compare :: Bundle -> Bundle -> Ordering
    compare (Bundle a :: Time
    a _) (Bundle b :: Time
    b _) = Time -> Time -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare Time
    a Time
    b

    -- | 'Bundle' constructor. It is an 'error' if the 'Message' list is
    -- empty.
    bundle :: Time -> [Message] -> Bundle
    bundle :: Time -> [Message] -> Bundle
    bundle t :: Time
    t xs :: [Message]
    xs =
        case [Message]
    xs of
          [] -> Address_Pattern -> Bundle
    forall a. HasCallStack => Address_Pattern -> a
    error "bundle: empty?"
          _ -> Time -> [Message] -> Bundle
    Bundle Time
    t [Message]
    xs

    -- * Packet

    -- | An OSC 'Packet' is either a 'Message' or a 'Bundle'.
    data Packet = Packet_Message {Packet -> Message
    packetMessage :: Message}
                | Packet_Bundle {Packet -> Bundle
    packetBundle :: Bundle}
                  deriving (Packet -> Packet -> Bool
    (Packet -> Packet -> Bool)
    -> (Packet -> Packet -> Bool) -> Eq Packet
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Packet -> Packet -> Bool
    $c/= :: Packet -> Packet -> Bool
    == :: Packet -> Packet -> Bool
    $c== :: Packet -> Packet -> Bool
    Eq,ReadPrec [Packet]
    ReadPrec Packet
    Int -> ReadS Packet
    ReadS [Packet]
    (Int -> ReadS Packet)
    -> ReadS [Packet]
    -> ReadPrec Packet
    -> ReadPrec [Packet]
    -> Read Packet
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    readListPrec :: ReadPrec [Packet]
    $creadListPrec :: ReadPrec [Packet]
    readPrec :: ReadPrec Packet
    $creadPrec :: ReadPrec Packet
    readList :: ReadS [Packet]
    $creadList :: ReadS [Packet]
    readsPrec :: Int -> ReadS Packet
    $creadsPrec :: Int -> ReadS Packet
    Read,Int -> Packet -> ShowS
    [Packet] -> ShowS
    Packet -> Address_Pattern
    (Int -> Packet -> ShowS)
    -> (Packet -> Address_Pattern)
    -> ([Packet] -> ShowS)
    -> Show Packet
    forall a.
    (Int -> a -> ShowS)
    -> (a -> Address_Pattern) -> ([a] -> ShowS) -> Show a
    showList :: [Packet] -> ShowS
    $cshowList :: [Packet] -> ShowS
    show :: Packet -> Address_Pattern
    $cshow :: Packet -> Address_Pattern
    showsPrec :: Int -> Packet -> ShowS
    $cshowsPrec :: Int -> Packet -> ShowS
    Show)

    -- | 'Packet_Bundle' of 'bundle'.
    p_bundle :: Time -> [Message] -> Packet
    p_bundle :: Time -> [Message] -> Packet
    p_bundle t :: Time
    t = Bundle -> Packet
    Packet_Bundle (Bundle -> Packet) -> ([Message] -> Bundle) -> [Message] -> Packet
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Time -> [Message] -> Bundle
    bundle Time
    t

    -- | 'Packet_Message' of 'message'.
    p_message :: Address_Pattern -> [Datum] -> Packet
    p_message :: Address_Pattern -> [Datum] -> Packet
    p_message a :: Address_Pattern
    a = Message -> Packet
    Packet_Message (Message -> Packet) -> ([Datum] -> Message) -> [Datum] -> Packet
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Address_Pattern -> [Datum] -> Message
    message Address_Pattern
    a

    -- | The 'Time' of 'Packet', if the 'Packet' is a 'Message' this is
    -- 'immediately'.
    packetTime :: Packet -> Time
    packetTime :: Packet -> Time
    packetTime = (Message -> Time) -> (Bundle -> Time) -> Packet -> Time
    forall a. (Message -> a) -> (Bundle -> a) -> Packet -> a
    at_packet (Time -> Message -> Time
    forall a b. a -> b -> a
    const Time
    immediately) Bundle -> Time
    bundleTime

    -- | Retrieve the set of 'Message's from a 'Packet'.
    packetMessages :: Packet -> [Message]
    packetMessages :: Packet -> [Message]
    packetMessages = (Message -> [Message])
    -> (Bundle -> [Message]) -> Packet -> [Message]
    forall a. (Message -> a) -> (Bundle -> a) -> Packet -> a
    at_packet Message -> [Message]
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bundle -> [Message]
    bundleMessages

    -- | If 'Packet' is a 'Message' add 'immediately' timestamp, else 'id'.
    packet_to_bundle :: Packet -> Bundle
    packet_to_bundle :: Packet -> Bundle
    packet_to_bundle = (Message -> Bundle) -> (Bundle -> Bundle) -> Packet -> Bundle
    forall a. (Message -> a) -> (Bundle -> a) -> Packet -> a
    at_packet (\m :: Message
    m -> Time -> [Message] -> Bundle
    Bundle Time
    immediately [Message
    m]) Bundle -> Bundle
    forall a. a -> a
    id

    -- | If 'Packet' is a 'Message' or a 'Bundle' with an /immediate/ time
    -- tag and with one element, return the 'Message', else 'Nothing'.
    packet_to_message :: Packet -> Maybe Message
    packet_to_message :: Packet -> Maybe Message
    packet_to_message p :: Packet
    p =
        case Packet
    p of
          Packet_Bundle b :: Bundle
    b ->
              case Bundle
    b of
                Bundle t :: Time
    t [m :: Message
    m] -> if Time
    t Time -> Time -> Bool
    forall a. Eq a => a -> a -> Bool
    == Time
    immediately then Message -> Maybe Message
    forall a. a -> Maybe a
    Just Message
    m else Maybe Message
    forall a. Maybe a
    Nothing
                _ -> Maybe Message
    forall a. Maybe a
    Nothing
          Packet_Message m :: Message
    m -> Message -> Maybe Message
    forall a. a -> Maybe a
    Just Message
    m

    -- | Is 'Packet' immediate, ie. a 'Bundle' with timestamp
    -- 'immediately', or a plain Message.
    packet_is_immediate :: Packet -> Bool
    packet_is_immediate :: Packet -> Bool
    packet_is_immediate = (Time -> Time -> Bool
    forall a. Eq a => a -> a -> Bool
    == Time
    immediately) (Time -> Bool) -> (Packet -> Time) -> Packet -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Packet -> Time
    packetTime

    -- | Variant of 'either' for 'Packet'.
    at_packet :: (Message -> a) -> (Bundle -> a) -> Packet -> a
    at_packet :: (Message -> a) -> (Bundle -> a) -> Packet -> a
    at_packet f :: Message -> a
    f g :: Bundle -> a
    g p :: Packet
    p =
        case Packet
    p of
          Packet_Message m :: Message
    m -> Message -> a
    f Message
    m
          Packet_Bundle b :: Bundle
    b -> Bundle -> a
    g Bundle
    b

    -- * Address Query

    -- | Does 'Message' have the specified 'Address_Pattern'.
    message_has_address :: Address_Pattern -> Message -> Bool
    message_has_address :: Address_Pattern -> Message -> Bool
    message_has_address x :: Address_Pattern
    x = (Address_Pattern -> Address_Pattern -> Bool
    forall a. Eq a => a -> a -> Bool
    == Address_Pattern
    x) (Address_Pattern -> Bool)
    -> (Message -> Address_Pattern) -> Message -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Message -> Address_Pattern
    messageAddress

    -- | Do any of the 'Message's at 'Bundle' have the specified
    -- 'Address_Pattern'.
    bundle_has_address :: Address_Pattern -> Bundle -> Bool
    bundle_has_address :: Address_Pattern -> Bundle -> Bool
    bundle_has_address x :: Address_Pattern
    x = (Message -> Bool) -> [Message] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Address_Pattern -> Message -> Bool
    message_has_address Address_Pattern
    x) ([Message] -> Bool) -> (Bundle -> [Message]) -> Bundle -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Bundle -> [Message]
    bundleMessages

    -- | Does 'Packet' have the specified 'Address_Pattern', ie.
    -- 'message_has_address' or 'bundle_has_address'.
    packet_has_address :: Address_Pattern -> Packet -> Bool
    packet_has_address :: Address_Pattern -> Packet -> Bool
    packet_has_address x :: Address_Pattern
    x =
        (Message -> Bool) -> (Bundle -> Bool) -> Packet -> Bool
    forall a. (Message -> a) -> (Bundle -> a) -> Packet -> a
    at_packet (Address_Pattern -> Message -> Bool
    message_has_address Address_Pattern
    x)
                  (Address_Pattern -> Bundle -> Bool
    bundle_has_address Address_Pattern
    x)

    -- * Pretty printing

    -- | Pretty printer for 'Message'.
    messagePP :: FP_Precision -> Message -> String
    messagePP :: FP_Precision -> Message -> Address_Pattern
    messagePP p :: FP_Precision
    p (Message a :: Address_Pattern
    a d :: [Datum]
    d) =
        let d' :: [Address_Pattern]
    d' = (Datum -> Address_Pattern) -> [Datum] -> [Address_Pattern]
    forall a b. (a -> b) -> [a] -> [b]
    map (FP_Precision -> Datum -> Address_Pattern
    datumPP FP_Precision
    p) [Datum]
    d
        in [Address_Pattern] -> Address_Pattern
    unwords ("#message" Address_Pattern -> [Address_Pattern] -> [Address_Pattern]
    forall a. a -> [a] -> [a]
    : Address_Pattern
    a Address_Pattern -> [Address_Pattern] -> [Address_Pattern]
    forall a. a -> [a] -> [a]
    : [Address_Pattern]
    d')

    -- | Pretty printer for 'Bundle'.
    bundlePP :: FP_Precision -> Bundle -> String
    bundlePP :: FP_Precision -> Bundle -> Address_Pattern
    bundlePP p :: FP_Precision
    p (Bundle t :: Time
    t m :: [Message]
    m) =
        let m' :: [Address_Pattern]
    m' = Address_Pattern -> [Address_Pattern] -> [Address_Pattern]
    forall a. a -> [a] -> [a]
    intersperse ";" ((Message -> Address_Pattern) -> [Message] -> [Address_Pattern]
    forall a b. (a -> b) -> [a] -> [b]
    map (FP_Precision -> Message -> Address_Pattern
    messagePP FP_Precision
    p) [Message]
    m)
        in [Address_Pattern] -> Address_Pattern
    unwords ("#bundle" Address_Pattern -> [Address_Pattern] -> [Address_Pattern]
    forall a. a -> [a] -> [a]
    : FP_Precision -> Time -> Address_Pattern
    timePP FP_Precision
    p Time
    t Address_Pattern -> [Address_Pattern] -> [Address_Pattern]
    forall a. a -> [a] -> [a]
    : [Address_Pattern]
    m')

    -- | Pretty printer for 'Packet'.
    packetPP :: FP_Precision -> Packet -> String
    packetPP :: FP_Precision -> Packet -> Address_Pattern
    packetPP p :: FP_Precision
    p pkt :: Packet
    pkt =
        case Packet
    pkt of
          Packet_Message m :: Message
    m -> FP_Precision -> Message -> Address_Pattern
    messagePP FP_Precision
    p Message
    m
          Packet_Bundle b :: Bundle
    b -> FP_Precision -> Bundle -> Address_Pattern
    bundlePP FP_Precision
    p Bundle
    b