-- | Renaming functions for UGen descriptions.
module Sound.SC3.UGen.DB.Rename where

import Data.Char
import Data.List
import Sound.SC3.UGen.Name {- hsc3 -}
import Sound.SC3.UGen.DB.Record

-- | Rename parameters that conflict with /Haskell/ keywords or
-- 'Prelude' functions, or which have otherwise unwieldy names.
--
-- > map rename_input ["in","id"] == ["input","id_"]
rename_input :: String -> String
rename_input p =
    case p of
      -- keyword
      "default" -> "default_"
      "in" -> "input"
      "type" -> "type_"
      -- prelude
      "div" -> "div_"
      "drop" -> "drop_"
      "exp" -> "exp_"
      "floor" -> "floor_"
      "id" -> "id_"
      "init" -> "init_"
      "length" -> "length_"
      "min" -> "min_"
      "max" -> "max_"
      -- internal (hsc3) use
      "rate" -> "rate_"
      "label" -> "label_"
      -- unwieldy
      "channelsArray" -> "input"
      _ -> p

-- | Rename unit generators that conflict with /Haskell/ keywords or
-- 'Prelude' functions.
--
-- > map rename_ugen ["In","Out"] == ["in'","out"]
rename_ugen :: String -> String
rename_ugen nm =
    let nm' = fromSC3Name nm
    in case nm' of
         "in" -> "in'"
         _ -> nm'

-- | Case insensitive string '=='.
ci_eq :: String -> String -> Bool
ci_eq p q = let f = map toLower in f p == f q

-- | If the input name is the same as the ugen name, rename the input.
rename_eq_input :: U -> I -> String
rename_eq_input u =
    let f x = if x `ci_eq` ugen_name u then x ++ "_" else x
    in rename_input . f . input_name

i_rename :: I -> I
i_rename i = i {input_name = rename_input (input_name i)}

u_rename :: U -> U
u_rename u =
    let n' = rename_ugen (ugen_name u)
        i' = map i_rename (ugen_inputs u)
    in u {ugen_name = n',ugen_inputs = i'}

i_rename_db :: [String] -> I -> I
i_rename_db uu_nm i =
    let n = input_name i
        n' = case find (ci_eq n) uu_nm of
               Just _ -> n ++ "_"
               Nothing -> n
    in i {input_name = rename_input n'}

-- | Variant that renames inputs to avoid name coliisions with UGens.
u_rename_db :: [U] -> U -> U
u_rename_db uu u =
    let uu_nm = map ugen_name uu
        n' = rename_ugen (ugen_name u)
        i' = map (i_rename_db uu_nm) (ugen_inputs u)
    in u {ugen_name = n',ugen_inputs = i'}