implementation module Incidone.Integration.Asterisk

import iTasks
import Incidone.Configuration
import Incidone.OP.Conversions
import Incidone.OP.SDSs
import Incidone.OP.CommunicationManagementTasks
import Incidone.Util.TaskPatterns
import Text, Data.Either
import qualified Data.Map as DM
import Data.Map.GenJSON

:: AsteriskEvent :== Map String String // Simple key/value mapping

syncAsteriskAMI :: Task ()
syncAsteriskAMI = withShared ([],False,[],False) (\channel -> (sync channel -&&- consume channel) @! ())
where
    sync channel
        =   get asteriskLinkConfig
        >>- \{AsteriskConfig|host,port,username,password} ->
            set ([],False,[authEvent username password],False) channel
        >>| syncNetworkChannel host port "\r\n\r\n" decodeAsteriskEvent encodeAsteriskEvent channel

    consume channel
        =   consumeNetworkStream processEvents channel

    processEvents events
        = allTasks [processEvent m \\ m <- events | isAsteriskEventType ["Dial","Newstate","Hangup"] m] @! ()

    processEvent event
        = case ('DM'.get "Event" event) of
            (Just "Dial") = case 'DM'.get "SubEvent" event of
                (Just "Begin")  = reportPhoneCallBegin CallerIDNum UniqueID @! ()
                (Just "End")    = maybe (return ()) (\id -> reportPhoneCallEnd (Right id)) UniqueID
                _               = return ()
            (Just "Newstate") = case 'DM'.get "ChannelStateDesc" event of
                (Just "Up")     = maybe (return ()) (\id -> reportPhoneCallConnected (Right id)) Uniqueid
                _               = return ()
            _
                = return ()
    where
        CallerIDNum = 'DM'.get "CallerIDNum" event
        UniqueID    = 'DM'.get "UniqueID" event
        Uniqueid    = 'DM'.get "Uniqueid" event

    authEvent username password
        = 'DM'.fromList [("Action","Login"),("Username",username),("Secret",password)]

    originateEvent fromExt toExt context
        = 'DM'.fromList [("Action","Originate"),("Channel","SIP/"+++fromExt),("Exten",toExt),("Priority","1"),("Context",context)]

encodeAsteriskEvent :: AsteriskEvent -> String
encodeAsteriskEvent event = join "\r\n" [k +++ ": " +++ v \\ (k,v) <- 'DM'.toList event] +++ "\r\n\r\n"

decodeAsteriskEvent :: String -> AsteriskEvent
decodeAsteriskEvent enc = foldr addLine 'DM'.newMap (split "\r\n" enc)
where
    addLine line msg = case split ":" line of
        [key,value] = 'DM'.put (trim key) (trim value) msg
        _           = msg

isAsteriskEventType :: [String] AsteriskEvent -> Bool
isAsteriskEventType types msg =  maybe False (\type -> isMember type types) ('DM'.get "Event" msg)

initiateAsteriskChannel :: CommunicationNo -> Task ()
initiateAsteriskChannel communicationNo
    //Set status to pending
    =   upd (\c -> {Communication|c & status = Just Pending}) (sdsFocus communicationNo communicationByNo)
    @!  ()

destroyAsteriskChannel :: CommunicationNo -> Task ()
destroyAsteriskChannel communicationNo
    =   upd (\c -> {Communication|c & status = Nothing}) (sdsFocus communicationNo communicationByNo)
    @!  ()


