-- | Enumeration of SC3 server commands.
module Sound.Sc3.Server.Command.Enum where

import Data.List {- base -}
import Data.Maybe {- base -}

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

-- | SC3 server commands are strings.
type SC3_Command = String

-- | Enumerate server command numbers.
sc3_cmd_enumeration :: [(SC3_Command, Int)]
sc3_cmd_enumeration :: [(Address_Pattern, Int)]
sc3_cmd_enumeration =
  [ (Address_Pattern
"/notify", Int
1)
  , (Address_Pattern
"/status", Int
2)
  , (Address_Pattern
"/quit", Int
3)
  , (Address_Pattern
"/cmd", Int
4)
  , -- /d = synthdef
    (Address_Pattern
"/d_recv", Int
5)
  , (Address_Pattern
"/d_load", Int
6)
  , (Address_Pattern
"/d_loadDir", Int
7)
  , (Address_Pattern
"/d_freeAll", Int
8)
  , -- /s = synth
    (Address_Pattern
"/s_new", Int
9)
  , -- /n = node
    (Address_Pattern
"/n_trace", Int
10)
  , (Address_Pattern
"/n_free", Int
11)
  , (Address_Pattern
"/n_run", Int
12)
  , (Address_Pattern
"/n_cmd", Int
13)
  , (Address_Pattern
"/n_map", Int
14)
  , (Address_Pattern
"/n_set", Int
15)
  , (Address_Pattern
"/n_setn", Int
16)
  , (Address_Pattern
"/n_fill", Int
17)
  , (Address_Pattern
"/n_before", Int
18)
  , (Address_Pattern
"/n_after", Int
19)
  , -- /u = ugen
    (Address_Pattern
"/u_cmd", Int
20)
  , -- /g = group
    (Address_Pattern
"/g_new", Int
21)
  , (Address_Pattern
"/g_head", Int
22)
  , (Address_Pattern
"/g_tail", Int
23)
  , (Address_Pattern
"/g_freeAll", Int
24)
  , -- /c = control
    (Address_Pattern
"/c_set", Int
25)
  , (Address_Pattern
"/c_setn", Int
26)
  , (Address_Pattern
"/c_fill", Int
27)
  , -- /b = buffer
    (Address_Pattern
"/b_alloc", Int
28)
  , (Address_Pattern
"/b_allocRead", Int
29)
  , (Address_Pattern
"/b_read", Int
30)
  , (Address_Pattern
"/b_write", Int
31)
  , (Address_Pattern
"/b_free", Int
32)
  , (Address_Pattern
"/b_close", Int
33)
  , (Address_Pattern
"/b_zero", Int
34)
  , (Address_Pattern
"/b_set", Int
35)
  , (Address_Pattern
"/b_setn", Int
36)
  , (Address_Pattern
"/b_fill", Int
37)
  , (Address_Pattern
"/b_gen", Int
38)
  , --
    (Address_Pattern
"/dumpOSC", Int
39)
  , -- _get
    (Address_Pattern
"/c_get", Int
40)
  , (Address_Pattern
"/c_getn", Int
41)
  , (Address_Pattern
"/b_get", Int
42)
  , (Address_Pattern
"/b_getn", Int
43)
  , (Address_Pattern
"/s_get", Int
44)
  , (Address_Pattern
"/s_getn", Int
45)
  , -- _query
    (Address_Pattern
"/n_query", Int
46)
  , (Address_Pattern
"/b_query", Int
47)
  , --
    (Address_Pattern
"/n_mapn", Int
48)
  , (Address_Pattern
"/s_noid", Int
49)
  , --
    (Address_Pattern
"/g_deepFree", Int
50)
  , (Address_Pattern
"/clearSched", Int
51)
  , --
    (Address_Pattern
"/sync", Int
52)
  , --
    (Address_Pattern
"/d_free", Int
53)
  , -- _channel
    (Address_Pattern
"/b_allocReadChannel", Int
54)
  , (Address_Pattern
"/b_readChannel", Int
55)
  , -- _tree
    (Address_Pattern
"/g_dumpTree", Int
56)
  , (Address_Pattern
"/g_queryTree", Int
57)
  , -- error
    (Address_Pattern
"/error", Int
58)
  , -- _args
    (Address_Pattern
"/s_newargs", Int
59)
  , --
    (Address_Pattern
"/n_mapa", Int
60)
  , (Address_Pattern
"/n_mapan", Int
61)
  , (Address_Pattern
"/n_order", Int
62)
  ]

{- | Lookup command number in 'sc3_cmd_enumeration'.

>>> map sc3_cmd_number ["/b_alloc","/s_new"]
[Just 28,Just 9]
-}
sc3_cmd_number :: SC3_Command -> Maybe Int
sc3_cmd_number :: Address_Pattern -> Maybe Int
sc3_cmd_number = (Address_Pattern -> [(Address_Pattern, Int)] -> Maybe Int)
-> [(Address_Pattern, Int)] -> Address_Pattern -> Maybe Int
forall a b c. (a -> b -> c) -> b -> a -> c
flip Address_Pattern -> [(Address_Pattern, Int)] -> Maybe Int
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup [(Address_Pattern, Int)]
sc3_cmd_enumeration

-- | 'isJust' of 'sc3_cmd_number'.
known_sc3_cmd :: SC3_Command -> Bool
known_sc3_cmd :: Address_Pattern -> Bool
known_sc3_cmd = Maybe Int -> Bool
forall a. Maybe a -> Bool
isJust (Maybe Int -> Bool)
-> (Address_Pattern -> Maybe Int) -> Address_Pattern -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Address_Pattern -> Maybe Int
sc3_cmd_number

-- | List of asynchronous server commands, ie. commands that reply with @/done@.
async_cmds :: [SC3_Command]
async_cmds :: [Address_Pattern]
async_cmds =
  [ Address_Pattern
"/b_alloc"
  , Address_Pattern
"/b_allocRead"
  , Address_Pattern
"/b_allocReadChannel"
  , Address_Pattern
"/b_close"
  , Address_Pattern
"/b_free"
  , Address_Pattern
"/b_read"
  , Address_Pattern
"/b_readChannel"
  , Address_Pattern
"/b_write"
  , Address_Pattern
"/b_zero"
  , Address_Pattern
"/d_load"
  , Address_Pattern
"/d_loadDir"
  , Address_Pattern
"/d_recv"
  , Address_Pattern
"/notify"
  , Address_Pattern
"/quit"
  , Address_Pattern
"/sync"
  ]

{- | 'True' if 'Message' is an asynchronous 'Message'.

> import Sound.Sc3.Server.Command.Plain
> map isAsync [b_close 0,n_set1 0 "0" 0,status] == [True,False,False]
-}
isAsync :: Osc.Message -> Bool
isAsync :: Message -> Bool
isAsync (Osc.Message Address_Pattern
a [Datum]
_) = Address_Pattern
a Address_Pattern -> [Address_Pattern] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Address_Pattern]
async_cmds

{- | Asynchronous commands are at the left.
This function should preserve the ordering of both branches.

> partition_async [b_close 0,n_set1 0 "0" 0]
-}
partition_async :: [Osc.Message] -> ([Osc.Message], [Osc.Message])
partition_async :: [Message] -> ([Message], [Message])
partition_async = (Message -> Bool) -> [Message] -> ([Message], [Message])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition Message -> Bool
isAsync

-- | Types & names for @b_info@ message fields.
b_info_fields :: [(String, String)]
b_info_fields :: [(Address_Pattern, Address_Pattern)]
b_info_fields =
  [ (Address_Pattern
"int", Address_Pattern
"buffer-id")
  , (Address_Pattern
"int", Address_Pattern
"frame-count")
  , (Address_Pattern
"int", Address_Pattern
"channels-count")
  , (Address_Pattern
"float", Address_Pattern
"sample-rate")
  ]

-- | Type, name and value descriptors for fields of @n_info@ message.
n_info_fields :: [(String, String, String)]
n_info_fields :: [(Address_Pattern, Address_Pattern, Address_Pattern)]
n_info_fields =
  [ (Address_Pattern
"int", Address_Pattern
"node-id", Address_Pattern
"")
  , (Address_Pattern
"int", Address_Pattern
"parent group-id", Address_Pattern
"-1 = nil")
  , (Address_Pattern
"int", Address_Pattern
"previous node-id", Address_Pattern
"-1 = nil")
  , (Address_Pattern
"int", Address_Pattern
"next node-id", Address_Pattern
"-1 = nil")
  , (Address_Pattern
"int", Address_Pattern
"node-type", Address_Pattern
"0 = synth,1 = group")
  , (Address_Pattern
"int", Address_Pattern
"head node-id", Address_Pattern
"-1 = nil")
  , (Address_Pattern
"int", Address_Pattern
"tail node-id", Address_Pattern
"-1 = nil")
  ]