
// Warning: Please do not make any changes to this file.

class cVaxWebPhoneIncomingCallData
{
    constructor(sCallId, sSDP)
    {
        this.m_sCallId = sCallId;
        this.m_sSDP = sSDP;
    }
}

function getCurrentScriptDir()
{
    const currentScript = document.currentScript || (function ()
    {
        const scripts = document.getElementsByTagName('script');
        return scripts[scripts.length - 1];
    })();

    const src = currentScript.src;
    return src.substring(0, src.lastIndexOf('/') + 1);
}

function LoadScript(sFileName, hCallback)
{
    const currentScript = document.currentScript || (function ()
    {
        const scripts = document.getElementsByTagName('script');
        return scripts[scripts.length - 1];
    })();

    const basePath = currentScript.src.substring(0, currentScript.src.lastIndexOf('/') + 1);
        
    const hScript = document.createElement("script");
    hScript.src = basePath + sFileName;
    hScript.type = "text/javascript";
    hScript.onload = hCallback;

    hScript.onerror = function () {
        console.error("Failed to load script:", hScript.src);
    };

    document.head.appendChild(hScript);
}

LoadScript("./VaxWebSocket/VaxWebSocket.js", function () {
    console.log("Script loaded successfully!");
});

LoadScript("./VaxPhoneEventSIP.js", function () {
    console.log("Script loaded successfully!");
});

LoadScript("./VaxPhoneFuncSIP.js", function () {
    console.log("Script loaded successfully!");
});

LoadScript("./VaxWebRTC/VaxMediaWebRTC.js", function () {
    console.log("Script loaded successfully!");
});

LoadScript("./VaxWebRTC/VaxWebRTC.js", function () {
    console.log("Script loaded successfully!");
});

LoadScript("./VaxWebRTC/adapter.js", function () {
    console.log("Script loaded successfully!");
});

function cVaxWebPhoneLib()
{
    const CALL_NORMAL_LINE_NO = 0;
    const CALL_CONSULT_LINE_NO = 1;

    let m_aIncomingNewCall = [];

    var m_objVaxFuncSIP = new cVaxPhoneFuncSIP();
    var m_objVaxEventSIP = new cVaxPhoneEventSIP();
        
    var m_objVaxSocketWeb = new cVaxWebSocket();
    var m_objVaxMediaWebRTC = new cVaxMediaWebRTC();

    var m_aVaxWebRTC = null;
    var m_aBusyLine = null;

    var m_bRecvVideoWebRTC = true;

    var m_hVideoPreviewOut = null;
    var m_hVideoMediaOut = null;
    var m_hVideoMediaRec = null;

    var m_hCameraVideoElement = null;
    var m_hScreenVideoElement = null;

    var m_hProcVideoMediaDrawFrame = null;

    var m_sActiveAudioInputDeviceId = '';
    var m_sActiveAudioOutputDeviceId = '';
    var m_sActiveVideoDeviceId = '';

    /////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////

    let m_aEventOnTryingToConnectServerWebRTC = [];
    let m_aEventOnFailedToConnectServerWebRTC = [];
    let m_aEventOnSuccessToConnectServerWebRTC = [];
    let m_aEventOnConnectionClosedServerWebRTC = [];

    let m_aEventOnAttachedAudioSendWebRTC = [];
    let m_aEventOnAttachedAudioRecvWebRTC = [];
    let m_aEventOnAttachedVideoSendWebRTC = [];
    let m_aEventOnAttachedVideoRecvWebRTC = [];

    let m_aEventOnInitialized = [];
    let m_aEventOnUnInitialized = [];

    let m_aEventOnVoiceMailMsg = [];
    let m_aEventOnAudioSessionLost = [];

    let m_aEventOnAddCallHistory = [];
    let m_aEventOnVaxErrorMsg = [];

    /////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////

    let m_aEventConnectingToRegister = [];
    let m_aEventTryingToRegister = [];
    let m_aEventFailedToRegister = [];
    let m_aEventSuccessToRegister = [];
        
    let m_aEventConnectingToReRegister = [];
    let m_aEventTryingToReRegister = [];
    let m_aEventFailedToReRegister = [];
    let m_aEventSuccessToReRegister = [];
        
    let m_aEventTryingToUnRegister = [];
    let m_aEventFailedToUnRegister = [];
    let m_aEventSuccessToUnRegister = [];

    /////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////

    let m_aEventOnHungupCall = [];
    let m_aEventOnDigitDTMF = [];
    let m_aEventOnCallClosed = [];

    /////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////

    let m_aEventOnDialCallStarted = [];
    let m_aEventOnDialingCall = [];

    let m_aEventOnDialCallFailed = [];
    let m_aEventOnDialCallConnected = [];

    let m_aEventOnDialCallRingToneStarted = [];
    let m_aEventOnDialCallRingToneEnded = [];

    let m_aEventOnDialCallBusyToneStarted = [];
    let m_aEventOnDialCallBusyToneEnded = [];
    
    /////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////

    let m_aEventOnIncomingCallStarted = [];
    let m_aEventOnIncomingCallEnded = [];

    let m_aEventOnIncomingCallAccepted = [];
    let m_aEventOnIncomingCallRejected = [];

    let m_aEventOnIncomingCallConnected = [];

    let m_aEventOnIncomingCallRingToneStarted = [];
    let m_aEventOnIncomingCallRingToneEnded = [];

    let m_aEventOnIncomingRefreshCallStarted = [];
    let m_aEventOnIncomingRefreshCallEnded = [];

    /////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////

    let m_aEventOnTryingToHold = [];
    let m_aEventOnFailedToHold = [];
    let m_aEventOnSuccessToHold = [];

    let m_aEventOnTryingToUnHold = [];
    let m_aEventOnFailedToUnHold = [];
    let m_aEventOnSuccessToUnHold = [];

    /////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////

    let m_aEventOnChatContactStatus = [];
    let m_aEventOnChatRecvMsgText = [];
    let m_aEventOnChatSendMsgTextSuccess = [];
    let m_aEventOnChatSendMsgTextFailed = [];
    let m_aEventOnChatSendMsgTypingSuccess = [];
    let m_aEventOnChatSendMsgTypingFailed = [];
    let m_aEventOnChatRecvMsgTypingStarted = [];
    let m_aEventOnChatRecvMsgTypingEnded = [];

    /////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////

    let m_aEventBusyLampSubscribeFailed = [];
    let m_aEventBusyLampSubscribeSuccess = [];
    let m_aEventBusyLampContactStatus = [];

    /////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////

    let m_aEventOnTransferCallClosed = [];
    let m_aEventOnTransferCallFailed = [];
    let m_aEventOnTransferCallAccepted = [];
            
    /////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////

    var m_sDisplayName = '';
    var m_sUserName = '';

    var m_sAuthLogin = '';
    var m_sAuthPwd = '';

    var m_sDomainRealm = '';
    var m_sServerAddr = '';
    var m_nServerPort = 0;
    var m_bRegister = false;

    var m_bBusyToneStarted = false;

    var m_sWebSocketServerAddr = '';
    var m_nTypeDTMF = -1;
               
    /////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////
        
    this.OnLoadPage = function ()
    {
        m_aVaxWebRTC = new Array(2);

        m_aVaxWebRTC[CALL_NORMAL_LINE_NO] = new cVaxWebRTC();
        m_aVaxWebRTC[CALL_CONSULT_LINE_NO] = new cVaxWebRTC();

        m_aBusyLine = new Array(2);

        m_aBusyLine[CALL_NORMAL_LINE_NO] = false;
        m_aBusyLine[CALL_CONSULT_LINE_NO] = false;

        m_aVaxWebRTC[CALL_NORMAL_LINE_NO].SetEvent(OnAttachedAudioRecvWebRTC, OnAttachedVideoRecvWebRTC);
        m_aVaxWebRTC[CALL_CONSULT_LINE_NO].SetEvent(OnAttachedAudioRecvWebRTC, OnAttachedVideoRecvWebRTC);

        m_objVaxSocketWeb.SetEventWebSocket(OnTryingToConnectServerWebRTC, OnFailedToConnectServerWebRTC, OnSuccessToConnectServerWebRTC, OnRecvDataServerWebRTC, OnConnectionClosedServerWebRTC);
        
        m_objVaxFuncSIP.SetEvent(OnSendDataServerWebRTC);

        m_objVaxEventSIP.SetEventMainSIP(OnInitialized, OnVoiceMailMsg, OnAudioSessionLost, OnAddCallHistory, OnVaxErrorMsg);

        m_objVaxEventSIP.SetEventRegister(OnConnectingToRegister, OnTryingToRegister, OnFailedToRegister, OnSuccessToRegister, OnConnectingToReRegister,
                                          OnTryingToReRegister, OnFailedToReRegister, OnSuccessToReRegister, OnTryingToUnRegister, OnFailedToUnRegister,
                                          OnSuccessToUnRegister);


        m_objVaxEventSIP.SetEventCall(OnHungupCall, OnDigitDTMF);
                
        m_objVaxEventSIP.SetEventDialCall(OnDialCallStarted, OnDialingCall, OnDialCallFailed, OnDialCallConnected, OnDialCallRingToneStarted, OnDialCallRingToneEnded,
                                          OnDialCallBusyToneStarted, null);

        m_objVaxEventSIP.SetEventIncomingCall(OnIncomingCallStarted, OnIncomingCallEnded, OnIncomingCallConnected, OnIncomingCallRingToneStarted, OnIncomingCallRingToneEnded,
                                              OnIncomingRefreshCallStarted, OnIncomingRefreshCallEnded);

        m_objVaxEventSIP.SetEventHold(OnTryingToHold, OnFailedToHold, OnSuccessToHold, OnTryingToUnHold, OnFailedToUnHold, OnSuccessToUnHold);


        m_objVaxEventSIP.SetEventChat(OnChatContactStatus, OnChatRecvMsgText, OnChatSendMsgTextFailed, OnChatSendMsgTextSuccess,
            OnChatSendMsgTypingFailed, OnChatSendMsgTypingSuccess, OnChatRecvMsgTypingStart, OnChatRecvMsgTypingStop);

        m_objVaxEventSIP.SetEventBusyLamp(OnBusyLampSubscribeFailed, OnBusyLampSubscribeSuccess, OnBusyLampContactStatus);

        m_objVaxEventSIP.SetEventTransferCall(OnTransferCallFailed, OnTransferCallAccepted);

    }

    /////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////

    function OnInitialized()
    {
        m_aIncomingNewCall = [];

        if (m_bRegister)
        {
            m_objVaxFuncSIP.RegisterToProxy(1800);
        }

        m_bRecvVideoWebRTC = true;
                
        m_aEventOnInitialized.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnUnInitialized()
    {
        m_aIncomingNewCall = [];

        m_aEventOnUnInitialized.forEach(hEvent => {
            if (hEvent != null) hEvent();
            });
    }
        
    /////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////

    this.IsConnectedToServerWebRTC = function ()
    {
        return m_objVaxSocketWeb.IsConnectedToServerWebRTC();
    }

    /////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////

    this.VaxOnline = function (sDisplayName, sUserName, sAuthLogin, sAuthPwd, sDomainRealm, sServerAddr, nServerPort, bRegister, sWebSocketServerURL, sWebSocketServerAddr)
    {
        m_aBusyLine[CALL_NORMAL_LINE_NO] = false;
        m_aBusyLine[CALL_CONSULT_LINE_NO] = false;

        m_sDisplayName = sDisplayName;
        m_sUserName = sUserName;

        m_sAuthLogin = sAuthLogin;
        m_sAuthPwd = sAuthPwd;

        m_sDomainRealm = sDomainRealm;
        m_sServerAddr = sServerAddr;
        m_nServerPort = nServerPort;

        m_bRegister = bRegister;
        m_sWebSocketServerAddr = sWebSocketServerAddr;

        m_objVaxSocketWeb.ConnectServerWebRTC(sWebSocketServerURL);
    }

    this.VaxOffline = function ()
    {
        m_objVaxFuncSIP.UnRegisterToProxy();

        m_objVaxMediaWebRTC.DeactivateMediaAudio();
        
        m_aBusyLine[CALL_NORMAL_LINE_NO] = false;
        m_aBusyLine[CALL_CONSULT_LINE_NO] = false;
                
        OnDialCallBusyToneEnded();

        OnUnInitialized();
    }

    this.VaxUnInitialize = function ()
    {
        m_aBusyLine[CALL_NORMAL_LINE_NO] = false;
        m_aBusyLine[CALL_CONSULT_LINE_NO] = false;

        m_objVaxFuncSIP.UnInitialize();

        OnDialCallBusyToneEnded();
    }
        
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    async function ActivateMediaAudioOutput(nLineNo)
    {
        return await m_objVaxMediaWebRTC.OpenMediaAudioOutputWebRTC(nLineNo, m_sActiveAudioOutputDeviceId);
    }

    async function ActivateMediaAudioInput()
    {
        await m_objVaxMediaWebRTC.ActivateMediaAudioInputWebRTC(m_sActiveAudioInputDeviceId);

        var hAudioInputStream = m_objVaxMediaWebRTC.GetMediaAudioInputStream();

        if (hAudioInputStream != null)
            OnAttachedAudioSendWebRTC(hAudioInputStream);
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    function OnVideoMediaDrawFrame()
    {
        if (m_hProcVideoMediaDrawFrame == null)
            return;
                
        m_hProcVideoMediaDrawFrame(m_hCameraVideoElement, m_hScreenVideoElement);

        requestAnimationFrame(OnVideoMediaDrawFrame);
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    //const screenTrack = screenStream.getVideoTracks()[0];
    //const screenSettings = screenTrack.getSettings();
    //m_hCanvas.width = screenSettings.width || 1280;
    //m_hCanvas.height = screenSettings.height || 720;

    this.ActivateMediaCamera = async function (hProcVideoMediaDrawFrame, hVideoMediaRec, hVideoMediaOut)
    {
        this.DeactivateMediaCamera();

        m_hProcVideoMediaDrawFrame = hProcVideoMediaDrawFrame;
        m_bRecvVideoWebRTC = true;

        m_hVideoMediaRec = hVideoMediaRec;
        m_hVideoMediaOut = hVideoMediaOut;

        let hCameraStream = await m_objVaxMediaWebRTC.ActivateCameraWebRTC(m_sActiveVideoDeviceId, null);
        if (hCameraStream == null) return;

        m_hCameraVideoElement = document.createElement("video");
        m_hCameraVideoElement.srcObject = hCameraStream;
                
        await Promise.all([
            m_hCameraVideoElement.play()
        ]);

        OnVideoMediaDrawFrame();
                
        OnAttachedVideoSendWebRTC(hCameraStream);
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    this.ActivateMediaScreen = async function (hProcVideoMediaDrawFrame, hVideoMediaRec, hVideoMediaOut)
    {
        this.DeactivateMediaScreen();

        m_hProcVideoMediaDrawFrame = hProcVideoMediaDrawFrame;
        m_bRecvVideoWebRTC = true;

        m_hVideoMediaRec = hVideoMediaRec;
        m_hVideoMediaOut = hVideoMediaOut;

        let hScreenStream = await m_objVaxMediaWebRTC.ActivateScreenWebRTC();
        if (hScreenStream == null) return;

        m_hScreenVideoElement = document.createElement("video");
        m_hScreenVideoElement.srcObject = hScreenStream;

        await Promise.all([
            m_hScreenVideoElement.play()
        ]);

        OnVideoMediaDrawFrame();

        OnAttachedVideoSendWebRTC(hCameraStream);
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    this.DeactivateMediaCamera = function ()
    {
        if (m_hCameraVideoElement == null)
            return;

        m_objVaxMediaWebRTC.DeactivateMediaCamera()

        m_hCameraVideoElement = null;

        if (m_hCameraVideoElement == null && m_hScreenVideoElement == null)
        {
            m_bRecvVideoWebRTC = false;

            m_hVideoMediaRec = null;
            m_hVideoMediaOut = null;
        }
    }

    this.DeactivateMediaScreen = async function ()
    {
        if (m_hScreenVideoElement == null)
            return;

        m_objVaxMediaWebRTC.DeactivateMediaScreen()

        m_hScreenVideoElement = null;

        if (m_hCameraVideoElement == null && m_hScreenVideoElement == null)
        {
            m_bRecvVideoWebRTC = false;

            m_hVideoMediaRec = null;
            m_hVideoMediaOut = null;
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    this.DialCall = async function (sCallerName, sCallerId, sDialNo)
    {
        if (m_aBusyLine[CALL_NORMAL_LINE_NO] == true)
        {
            return;
        }

        m_aBusyLine[CALL_NORMAL_LINE_NO] = true;

        await ActivateMediaAudioInput();
                                               
        var hAudioInputStream = m_objVaxMediaWebRTC.GetMediaAudioInputStream();
        var hLocalVideoStream = m_hVideoMediaRec;

        var hAudioMediaOut = await ActivateMediaAudioOutput(CALL_NORMAL_LINE_NO);
                       
        m_aVaxWebRTC[CALL_NORMAL_LINE_NO].CreateOfferWebRTC(CALL_NORMAL_LINE_NO, sCallerName, sCallerId, sDialNo, hAudioInputStream, hLocalVideoStream, hAudioMediaOut, m_hVideoMediaOut, m_bRecvVideoWebRTC, OnOfferCreateSuccessWebRTC);
    }

    this.DisconnectCall = function ()
    {
        m_aBusyLine[CALL_NORMAL_LINE_NO] = false;
        m_objVaxFuncSIP.DisconnectCall(CALL_NORMAL_LINE_NO);

        OnDialCallBusyToneEnded();

        OnCallClosed(CALL_NORMAL_LINE_NO);
    }
       
    this.AcceptCall = async function (sCallId)
    {
        if (m_aBusyLine[CALL_NORMAL_LINE_NO] == true)
        {
            console.log("Line is already busy.");
            return;
        }

        m_aBusyLine[CALL_NORMAL_LINE_NO] = true;

        await ActivateMediaAudioInput();
        
        var hAudioInputStream = m_objVaxMediaWebRTC.GetMediaAudioInputStream();
        var hLocalVideoStream = m_hVideoMediaRec;

        var hAudioMediaOut = await ActivateMediaAudioOutput(CALL_NORMAL_LINE_NO);

        let objCallData = m_aIncomingNewCall.find(objCallData => objCallData.m_sCallId === sCallId);
        if (objCallData == null) return;
                
        m_aVaxWebRTC[CALL_NORMAL_LINE_NO].CreateAnswerWebRTC(CALL_NORMAL_LINE_NO, objCallData.m_sSDP, objCallData.m_sCallId, hAudioInputStream, hLocalVideoStream, hAudioMediaOut, m_hVideoMediaOut, m_bRecvVideoWebRTC, OnAnswerCreateSuccessWebRTC);

        OnIncomingCallAccepted(sCallId);
    }

    this.RejectCall = function (sCallId)
    {
        m_objVaxFuncSIP.RejectCall(sCallId);
        OnIncomingCallRejected(sCallId);
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    this.HoldCall = function ()
    {
        m_objVaxFuncSIP.HoldCall(CALL_NORMAL_LINE_NO);
    }

    this.UnHoldCall = function ()
    {
        m_objVaxFuncSIP.UnHoldCall(CALL_NORMAL_LINE_NO);
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    this.TransferConsultDialCall = async function (sCallerName, sCallerId, sDialNo)
    {
        if (m_aBusyLine[CALL_CONSULT_LINE_NO] == true)
        {
            console.log("Line is already busy.");
            return;
        }

        m_aBusyLine[CALL_CONSULT_LINE_NO] = true;

        m_objVaxFuncSIP.HoldCall(CALL_NORMAL_LINE_NO);

        var hAudioInputStream = m_objVaxMediaWebRTC.GetMediaAudioInputStream();
        var hAudioMediaOut = await ActivateMediaAudioOutput(CALL_CONSULT_LINE_NO);
        
        m_aVaxWebRTC[CALL_CONSULT_LINE_NO].CreateOfferWebRTC(CALL_CONSULT_LINE_NO, sCallerName, sCallerId, sDialNo, hAudioInputStream, null, hAudioMediaOut, null, false, OnOfferCreateSuccessWebRTC);
    }

    this.TransferConsultDisconnectCall = function ()
    {
        m_aBusyLine[CALL_CONSULT_LINE_NO] = false;
        m_objVaxFuncSIP.DisconnectCall(CALL_CONSULT_LINE_NO);
    }

    this.TransferConsultHoldCall = function ()
    {
        m_objVaxFuncSIP.HoldCall(CALL_CONSULT_LINE_NO);
    }

    this.TransferConsultUnHoldCall = function ()
    {
        m_objVaxFuncSIP.UnHoldCall(CALL_CONSULT_LINE_NO);
    }

    this.TransferConsultJoinCall = function ()
    {
        m_objVaxFuncSIP.TransferCallConsult(CALL_CONSULT_LINE_NO, CALL_NORMAL_LINE_NO);
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    this.TransferCallBlind = function (sToUserName)
    {
        m_objVaxFuncSIP.TransferCallBlind(CALL_NORMAL_LINE_NO, sToUserName);
    }
        
    this.DigitDTMF = function (sDigit)
    {
        m_objVaxFuncSIP.DigitDTMF(CALL_NORMAL_LINE_NO, sDigit, m_nTypeDTMF);
    }

    this.ForceDigitDTMF = function (nTypeId, bEnable)
    {
        if (bEnable)
            m_nTypeDTMF = nTypeId;
        else
            nTypeId = -1;
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    this.DonotDisturb = function (bEnable)
    {
        m_objVaxFuncSIP.DonotDisturb(bEnable);
    }

    this.MuteMic = function (bMute)
    {
        m_objVaxMediaWebRTC.MuteMediaWebRTC(bMute);
    }
   
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    this.ChatAddContact = function (sUserName, bPresence)
    {
        m_objVaxFuncSIP.ChatAddContact(sUserName, bPresence);
    }

    this.ChatRemoveContact = function (sUserName)
    {
        m_objVaxFuncSIP.ChatRemoveContact(sUserName);
    }

    this.ChatSendMessageTyping = function (sUserName)
    {
        m_objVaxFuncSIP.ChatSendMessageTyping(sUserName, 0);
    }

    this.ChatSendMessageText = function (sUserName, sMsgText)
    {
        m_objVaxFuncSIP.ChatSendMessageText(sUserName, sMsgText, 101, 0);
    }
  
    this.ChatSetMyStatus = function (nStatusId)
    {
        m_objVaxFuncSIP.ChatSetMyStatus(nStatusId);
    }

    this.ChatSubscribeContactAll = function ()
    {
        m_objVaxFuncSIP.ChatSubscribeContactAll();
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    this.BusyLampAddContact = function (sUserName)
    {
        m_objVaxFuncSIP.BusyLampAddContact(sUserName);
    }

    this.BusyLampRemoveContact = function (sUserName)
    {
        m_objVaxFuncSIP.BusyLampRemoveContact(sUserName);
    }

    this.BusyLampSubscribeContactAll = function ()
    {
        m_objVaxFuncSIP.BusyLampSubscribeContactAll();
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    this.ForwardCall = function (bEnable, sToUserName)
    {
        m_objVaxFuncSIP.ForwardCall(bEnable, sToUserName);
    }
                           
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
   
    function OnOfferCreateSuccessWebRTC(nLineNo, sSDP, sCallerName, sCallerId, sDialNo)
    {
        m_objVaxFuncSIP.DialCall(nLineNo, sSDP, sCallerName, sCallerId, sDialNo);
    }
            
    function OnAnswerCreateSuccessWebRTC(nLineNo, sSDP, sCallId)
    {
        m_objVaxFuncSIP.AcceptCall(nLineNo, sSDP, sCallId);
    }
        
    /////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////
        
    function OnIncomingRefreshCallEnded(nLineNo, sSDP)
    {
        m_aVaxWebRTC[nLineNo].SetAnswerRemoteWebRTC(sSDP);
    }

    async function OnIncomingRefreshCallStarted(nLineNo, sAudioFlowType, sVideoFlowType, sSDP)
    {
        m_aVaxWebRTC[nLineNo].CloseConnection();
        m_aVaxWebRTC[nLineNo] = null;

        m_aVaxWebRTC[nLineNo] = new cVaxWebRTC();

        var hAudioInputStream = m_objVaxMediaWebRTC.GetMediaAudioInputStream();
        var hLocalVideoStream = m_hVideoMediaRec;

        var hAudioMediaOut = await ActivateMediaAudioOutput(nLineNo);
        
        var bRecvVideo = m_bRecvVideoWebRTC;

        if (sVideoFlowType == "inactive" || nLineNo == CALL_CONSULT_LINE_NO)
        {
            bRecvVideo = false;
            hLocalVideoStream = null;
        }

        if (sSDP.length == 0)
            m_aVaxWebRTC[nLineNo].CreateOfferWebRTC(nLineNo, "OnIncomingRefreshCallStarted", "", "", hAudioInputStream, hLocalVideoStream, hAudioMediaOut, m_hVideoMediaOut, bRecvVideo, OnOfferCreateSuccessWebRTC);
        else
            m_aVaxWebRTC[nLineNo].CreateAnswerWebRTC(nLineNo, sSDP, "OnIncomingRefreshCallStarted", hAudioInputStream, hLocalVideoStream, hAudioMediaOut, m_hVideoMediaOut, bRecvVideo, OnAnswerCreateSuccessWebRTC);
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    function OnOfferCreateSuccessWebRTC(nLineNo, sSDP, sCallerName, sCallerId, sDialNo)
    {
        if (sCallerName == 'OnIncomingRefreshCallStarted')
        {
            m_objVaxFuncSIP.AcceptRefreshCall(nLineNo, sSDP);
            return;
        }

        m_objVaxFuncSIP.DialCall(nLineNo, sSDP, sCallerName, sCallerId, sDialNo);
    }

    function OnAnswerCreateSuccessWebRTC(nLineNo, sSDP, sCallId)
    {
        if (sCallId == 'OnIncomingRefreshCallStarted')
        {
            m_objVaxFuncSIP.AcceptRefreshCall(nLineNo, sSDP);
            return;
        }

        m_objVaxFuncSIP.AcceptCall(nLineNo, sSDP, sCallId);
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    this.PlayMediaStartFile = function (sFileName, bLoop)
    {
        return m_objVaxMediaWebRTC.PlayMediaStartFile(m_sActiveAudioOutputDeviceId, sFileName, bLoop);
    }

    this.PlayMediaStopFile = function (hAudio)
    {
        return m_objVaxMediaWebRTC.PlayMediaStopFile(hAudio);
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////

    this.GetAudioInputDeviceList = async function (aListName, aListID, vDefault)
    {
        await m_objVaxMediaWebRTC.GetAudioInputDeviceList(aListName, aListID, vDefault);
    }

    this.GetAudioOutputDeviceList = async function (aListName, aListID, vDefault)
    {
        await m_objVaxMediaWebRTC.GetAudioOutputDeviceList(aListName, aListID, vDefault);
    }

    this.GetVideDeviceList = async function (aListName, aListID, vDefault)
    {
        await m_objVaxMediaWebRTC.GetVideDeviceList(aListName, aListID, vDefault);
    }

    this.AttachDetectMediaChange = function (hProcMediaChanged)
    {
        m_objVaxMediaWebRTC.AttachDetectMediaChange(hProcMediaChanged);
    }

    this.SetActiveAudioInputDevice = function (sDeviceName, sDeviceId)
    {
        m_sActiveAudioInputDeviceId = sDeviceId;
    }

    this.SetActiveAudioOutputDevice = function (sDeviceName, sDeviceId)
    {
        m_sActiveAudioOutputDeviceId = sDeviceId;
    }

    this.SetActiveVideoDevice = function (sDeviceName, sDeviceId)
    {
        m_sActiveVideoDeviceId = sDeviceId;
    }

    this.ChangeAudioOutputDevice = async function (sDeviceId)
    {
        m_sActiveAudioOutputDeviceId = sDeviceId;

        await m_objVaxMediaWebRTC.ChangeAudioOutputDevice(CALL_NORMAL_LINE_NO, sDeviceId);
        await m_objVaxMediaWebRTC.ChangeAudioOutputDevice(CALL_CONSULT_LINE_NO, sDeviceId);
    }

    this.ChangeAudioInputDevice = async function (sDeviceId)
    {
        if (m_objVaxMediaWebRTC.GetMediaAudioInputStream() == null)
            return;

        m_sActiveAudioInputDeviceId = sDeviceId;

        await ActivateMediaAudioInput();
        
        var hAudioInputStream = m_objVaxMediaWebRTC.GetMediaAudioInputStream();
                
        m_aVaxWebRTC[CALL_NORMAL_LINE_NO].ChangeMediaAudioInputWebRTC(hAudioInputStream);
        m_aVaxWebRTC[CALL_CONSULT_LINE_NO].ChangeMediaAudioInputWebRTC(hAudioInputStream);
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
        
    this.SetEventServerWebRTC = function (hEventOnTryingToConnect, hEventOnFailedToConnect, hEventOnSuccessToConnect, hEventOnConnectionClosed)
    {
        m_aEventOnTryingToConnectServerWebRTC.push(hEventOnTryingToConnect);
        m_aEventOnFailedToConnectServerWebRTC.push(hEventOnFailedToConnect);
        m_aEventOnSuccessToConnectServerWebRTC.push(hEventOnSuccessToConnect);
        m_aEventOnConnectionClosedServerWebRTC.push(hEventOnConnectionClosed);
    }

    function OnTryingToConnectServerWebRTC() {
        m_aEventOnTryingToConnectServerWebRTC.forEach(hEvent => {
            if (hEvent) hEvent();
        });
    }

    function OnFailedToConnectServerWebRTC() {
        m_aEventOnFailedToConnectServerWebRTC.forEach(hEvent => {
            if (hEvent) hEvent();
        });
    }

    function OnSuccessToConnectServerWebRTC()
    {
        m_objVaxFuncSIP.Initialize(m_sDisplayName, m_sUserName, m_sAuthLogin, m_sAuthPwd, m_sDomainRealm, m_sServerAddr, m_nServerPort, m_sWebSocketServerAddr);

        m_aEventOnSuccessToConnectServerWebRTC.forEach(hEvent => {
            if (hEvent) hEvent();
        });
    }
    
    function OnRecvDataServerWebRTC(sData)
    {
        m_objVaxEventSIP.OnWebSocketRecv(sData);
    }

    function OnConnectionClosedServerWebRTC() {
        m_aEventOnConnectionClosedServerWebRTC.forEach(hEvent => {
            if (hEvent) hEvent();
        });
    }

    function OnSendDataServerWebRTC(sData) {
        m_objVaxSocketWeb.SendToServerWebRTC(sData);
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////

    this.SetEventMediaWebRTC = function (hEventOnAttachedAudioSendWebRTC, hEventOnAttachedAudioRecvWebRTC, hEventOnAttachedVideoSendWebRTC, hEventOnAttachedVideoRecvWebRTC)
    {
        m_aEventOnAttachedAudioSendWebRTC.push(hEventOnAttachedAudioSendWebRTC);
        m_aEventOnAttachedAudioRecvWebRTC.push(hEventOnAttachedAudioRecvWebRTC);
        m_aEventOnAttachedVideoSendWebRTC.push(hEventOnAttachedVideoSendWebRTC);
        m_aEventOnAttachedVideoRecvWebRTC.push(hEventOnAttachedVideoRecvWebRTC);
    }

    function OnAttachedAudioSendWebRTC(hStream) {
        m_aEventOnAttachedAudioSendWebRTC.forEach(hEvent => {
            if (hEvent) hEvent(hStream);
        });
    }

    function OnAttachedAudioRecvWebRTC(hStream) {
        m_aEventOnAttachedAudioRecvWebRTC.forEach(hEvent => {
            if (hEvent) hEvent(hStream);
        });
    }

    function OnAttachedVideoSendWebRTC(hStream) {
        m_aEventOnAttachedVideoSendWebRTC.forEach(hEvent => {
            if (hEvent) hEvent(hStream);
        });
    }

    function OnAttachedVideoRecvWebRTC(hStream) {
        m_aEventOnAttachedVideoRecvWebRTC.forEach(hEvent => {
            if (hEvent) hEvent(hStream);
        });
    }
    
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////

    this.SetEventMainSIP = function (
        hEventOnInitialized,
        hEventOnUnInitialized,
        hEventOnVoiceMailMsg,
        hEventOnAudioSessionLost,
        hEventOnAddCallHistory,
        hEventOnVaxErrorMsg
    )
    {
        m_aEventOnInitialized.push(hEventOnInitialized);
        m_aEventOnUnInitialized.push(hEventOnUnInitialized);

        m_aEventOnVoiceMailMsg.push(hEventOnVoiceMailMsg);
        m_aEventOnAudioSessionLost.push(hEventOnAudioSessionLost);

        m_aEventOnAddCallHistory.push(hEventOnAddCallHistory);
        m_aEventOnVaxErrorMsg.push(hEventOnVaxErrorMsg);
    }
        
    function OnVoiceMailMsg(bIsMsgWaiting, nNewMsgCount, nOldMsgCount, nNewUrgentMsgCount, nOldUrgentMsgCount, sMsgAccount) {
        m_aEventOnVoiceMailMsg.forEach(hEvent => {
            if (hEvent) hEvent(bIsMsgWaiting, nNewMsgCount, nOldMsgCount, nNewUrgentMsgCount, nOldUrgentMsgCount, sMsgAccount);
        });
    }

    function OnAudioSessionLost(nLineNo) {
        m_aEventOnAudioSessionLost.forEach(hEvent => {
            if (hEvent) hEvent(nLineNo);
        });
    }

    function OnAddCallHistory(bOutboundCallType, sCallerName, sCallerId, sDialNo, nStartTime, nEndTime, nDuration, nDayNo, nHistoryTypeId) {
        m_aEventOnAddCallHistory.forEach(hEvent => {
            if (hEvent) hEvent(bOutboundCallType, sCallerName, sCallerId, sDialNo, nStartTime, nEndTime, nDuration, nDayNo, nHistoryTypeId);
        });
    }

    function OnVaxErrorMsg(sFuncName, sErrorMsg, nErrorCode) {
        m_aEventOnVaxErrorMsg.forEach(hEvent => {
            if (hEvent) hEvent(sFuncName, sErrorMsg, nErrorCode);
        });
    }


    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////

    this.SetEventRegister = function (hEventConnectingToRegister, hEventTryingToRegister, hEventFailedToRegister, hEventSuccessToRegister, hEventConnectingToReRegister, hEventTryingToReRegister, hEventFailedToReRegister, hEventSuccessToReRegister, hEventTryingToUnRegister, hEventFailedToUnRegister, hEventSuccessToUnRegister)
    {
        m_aEventConnectingToRegister.push(hEventConnectingToRegister);
        m_aEventTryingToRegister.push(hEventTryingToRegister);
        m_aEventFailedToRegister.push(hEventFailedToRegister);
        m_aEventSuccessToRegister.push(hEventSuccessToRegister);

        m_aEventConnectingToReRegister.push(hEventConnectingToReRegister);
        m_aEventTryingToReRegister.push(hEventTryingToReRegister);
        m_aEventFailedToReRegister.push(hEventFailedToReRegister);
        m_aEventSuccessToReRegister.push(hEventSuccessToReRegister);

        m_aEventTryingToUnRegister.push(hEventTryingToUnRegister);
        m_aEventFailedToUnRegister.push(hEventFailedToUnRegister);
        m_aEventSuccessToUnRegister.push(hEventSuccessToUnRegister);
    }

    function OnConnectingToRegister()
    {
        m_aEventConnectingToRegister.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnTryingToRegister()
    {
        m_aEventTryingToRegister.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnFailedToRegister(nStatusCode, sReasonPhrase) {
        m_aEventFailedToRegister.forEach(hEvent => {
            if (hEvent != null) hEvent(nStatusCode, sReasonPhrase);
        });
    }

    function OnSuccessToRegister()
    {
        m_aEventSuccessToRegister.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }
        
    function OnConnectingToReRegister()
    {
        m_aEventConnectingToReRegister.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnTryingToReRegister(){
        m_aEventTryingToReRegister.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnFailedToReRegister(nStatusCode, sReasonPhrase) {
        m_aEventFailedToReRegister.forEach(hEvent => {
            if (hEvent != null) hEvent(nStatusCode, sReasonPhrase);
        });
    }

    function OnSuccessToReRegister() {
        m_aEventSuccessToReRegister.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }
        
    function OnTryingToUnRegister() {
        m_aEventTryingToUnRegister.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnFailedToUnRegister() {
        m_aEventFailedToUnRegister.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnSuccessToUnRegister()
    {
        m_objVaxSocketWeb.DisconnectServerWebRTC();

        m_aEventSuccessToUnRegister.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }
        
    /////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////

    this.SetEventCall = function (hEventOnDigitDTMF, hEventOnHungupCall, hEventOnCallClosed)
    {
        m_aEventOnHungupCall.push(hEventOnHungupCall);
        m_aEventOnDigitDTMF.push(hEventOnDigitDTMF);
        m_aEventOnCallClosed.push(hEventOnCallClosed);
    };

    function OnHungupCall(nLineNo)
    {
        if (nLineNo == CALL_NORMAL_LINE_NO)
        {
            m_aEventOnHungupCall.forEach(hEvent => {
                if (hEvent != null) hEvent();
            });
        }
                
        OnCallClosed(nLineNo);
    }

    function OnDigitDTMF(nLineNo, sDigit) {
        m_aEventOnDigitDTMF.forEach(hEvent => {
            if (hEvent != null) hEvent(nLineNo, sDigit);
        });
    }
        
    function OnCallClosed(nLineNo)
    {
        m_aBusyLine[nLineNo] = false;

        m_aVaxWebRTC[nLineNo].CloseConnection();

        if (nLineNo == CALL_NORMAL_LINE_NO)
        {
            m_objVaxMediaWebRTC.DeactivateMediaAudio();

            m_aEventOnCallClosed.forEach(hEvent => {
                if (hEvent != null) hEvent();
            });
        }
        else if (nLineNo == CALL_CONSULT_LINE_NO)
        {
            OnTransferCallClosed();
            m_objVaxMediaWebRTC.CloseMediaAudioOutputWebRTC(nLineNo);
        }
    }

    /////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////

    this.SetEventDialCall = function (
        hEventOnDialCallStarted,
        hEventOnDialingCall,
        hEventOnDialCallFailed,
        hEventOnDialCallConnected,
        hEventOnDialCallRingToneStarted,
        hEventOnDialCallRingToneEnded,
        hEventOnDialCallBusyToneStarted,
        hEventOnDialCallBusyToneEnded
    )
    {
        m_aEventOnDialCallStarted.push(hEventOnDialCallStarted);
        m_aEventOnDialingCall.push(hEventOnDialingCall);

        m_aEventOnDialCallFailed.push(hEventOnDialCallFailed);
        m_aEventOnDialCallConnected.push(hEventOnDialCallConnected);

        m_aEventOnDialCallRingToneStarted.push(hEventOnDialCallRingToneStarted);
        m_aEventOnDialCallRingToneEnded.push(hEventOnDialCallRingToneEnded);

        m_aEventOnDialCallBusyToneStarted.push(hEventOnDialCallBusyToneStarted);
        m_aEventOnDialCallBusyToneEnded.push(hEventOnDialCallBusyToneEnded);
    };

        
    function OnDialCallStarted(nLineNo, sCallerName, sCallerId, sDialNo) {

        m_aEventOnDialCallStarted.forEach(hEvent => {
            if (hEvent != null) hEvent(sCallerName, sCallerId, sDialNo);
        });
    }

    function OnDialingCall(nLineNo, nStatusCode, sReasonPhrase) {
        m_aEventOnDialingCall.forEach(hEvent => {
            if (hEvent != null) hEvent(nStatusCode, sReasonPhrase);
        });
    }

    function OnDialCallFailed(nLineNo, nStatusCode, sReasonPhrase, sContact)
    {
        m_aBusyLine[nLineNo] = false;

        m_aEventOnDialCallFailed.forEach(hEvent => {
            if (hEvent != null) hEvent(nStatusCode, sReasonPhrase, sContact);
        });
    }

    function OnDialCallConnected(nLineNo, sSDP, sToRTPIP, nToRTPPort)
    {
        if (sSDP.length != 0)
            m_aVaxWebRTC[nLineNo].SetAnswerRemoteWebRTC(sSDP);
        
        m_aEventOnDialCallConnected.forEach(hEvent => {
            if (hEvent != null) hEvent(nLineNo, sSDP);
        });
    }

    function OnDialCallRingToneStarted() {
        m_aEventOnDialCallRingToneStarted.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnDialCallRingToneEnded() {
        m_aEventOnDialCallRingToneEnded.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnDialCallBusyToneStarted()
    {
        if (m_bBusyToneStarted == true)
            return;

        m_bBusyToneStarted = true;

        m_aEventOnDialCallBusyToneStarted.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnDialCallBusyToneEnded()
    {
        if (m_bBusyToneStarted == false)
            return;

        m_bBusyToneStarted = false;

        m_aEventOnDialCallBusyToneEnded.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }
    
    /////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////

    this.SetEventIncomingCall = function (
        hEventOnIncomingCallStarted,
        hEventOnIncomingCallEnded,
        hEventOnIncomingCallAccepted,
        hEventOnIncomingCallRejected,
        hEventOnIncomingCallConnected,
        hEventOnIncomingCallRingToneStarted,
        hEventOnIncomingCallRingToneEnded,
        hEventOnIncomingRefreshCallStarted,
        hEventOnIncomingRefreshCallEnded
    ) {
        m_aEventOnIncomingCallStarted.push(hEventOnIncomingCallStarted);
        m_aEventOnIncomingCallEnded.push(hEventOnIncomingCallEnded);

        m_aEventOnIncomingCallAccepted.push(hEventOnIncomingCallAccepted);
        m_aEventOnIncomingCallRejected.push(hEventOnIncomingCallRejected);

        m_aEventOnIncomingCallConnected.push(hEventOnIncomingCallConnected);

        m_aEventOnIncomingCallRingToneStarted.push(hEventOnIncomingCallRingToneStarted);
        m_aEventOnIncomingCallRingToneEnded.push(hEventOnIncomingCallRingToneEnded);

        m_aEventOnIncomingRefreshCallStarted.push(hEventOnIncomingRefreshCallStarted);
        m_aEventOnIncomingRefreshCallEnded.push(hEventOnIncomingRefreshCallEnded);
    };

    function OnIncomingCallStarted(sSDP, sCallId, sCallerName, sCallerId, sDialNo, sFromURI, sToURI)
    {
        let nIndex = m_aIncomingNewCall.findIndex(objCallData => objCallData.m_sCallId === sCallId);
        if (nIndex !== -1) return;

        m_aIncomingNewCall.push(new cVaxWebPhoneIncomingCallData(sCallId, sSDP));

        m_aEventOnIncomingCallStarted.forEach(hEvent => {
            if (hEvent != null) hEvent(sCallId, sCallerName, sCallerId, sDialNo);
        });
    }
        
    function OnIncomingCallEnded(sCallId)
    {
        let nIndex = m_aIncomingNewCall.findIndex(objCallData => objCallData.m_sCallId === sCallId);
        if (nIndex !== -1) m_aIncomingNewCall.splice(nIndex, 1);
        
        m_aEventOnIncomingCallEnded.forEach(hEvent => {
            if (hEvent != null) hEvent(sCallId);
        });
    }

    function OnIncomingCallAccepted(sCallId)
    {
        let nIndex = m_aIncomingNewCall.findIndex(objCallData => objCallData.m_sCallId === sCallId);
        if (nIndex !== -1) m_aIncomingNewCall.splice(nIndex, 1);

        m_aEventOnIncomingCallAccepted.forEach(hEvent => {
            if (hEvent != null) hEvent(sCallId);
        });
    }

    function OnIncomingCallRejected(sCallId)
    {
        let nIndex = m_aIncomingNewCall.findIndex(objCallData => objCallData.m_sCallId === sCallId);
        if (nIndex !== -1) m_aIncomingNewCall.splice(nIndex, 1);

        m_aEventOnIncomingCallAccepted.forEach(hEvent => {
            if (hEvent != null) hEvent(sCallId);
        });
    }

    function OnIncomingCallConnected(nLineNo, sToRTPIP, nToRTPPort)
    {
        m_aEventOnIncomingCallConnected.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }
        
    function OnIncomingCallRingToneStarted(sCallId) {
        m_aEventOnIncomingCallRingToneStarted.forEach(hEvent => {
            if (hEvent != null) hEvent(sCallId);
        });
    }

    function OnIncomingCallRingToneEnded(sCallId) {
        m_aEventOnIncomingCallRingToneEnded.forEach(hEvent => {
            if (hEvent != null) hEvent(sCallId);
        });
    }

    function OnIncomingRefreshCallStarted(nLineNo, sAudioFlowType, sVideoFlowType, sSDP) {
        m_aEventOnIncomingRefreshCallStarted.forEach(hEvent => {
            if (hEvent != null) hEvent(nLineNo, sAudioFlowType, sVideoFlowType, sSDP);
        });
    }

    function OnIncomingRefreshCallEnded(nLineNo, sSDP) {
        m_aEventOnIncomingRefreshCallEnded.forEach(hEvent => {
            if (hEvent != null) hEvent(nLineNo, sSDP);
        });
    }

    /////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////
       
    this.SetEventHold = function (
        hEventOnTryingToHold,
        hEventOnFailedToHold,
        hEventOnSuccessToHold,
        hEventOnTryingToUnHold,
        hEventOnFailedToUnHold,
        hEventOnSuccessToUnHold
    ) {
        m_aEventOnTryingToHold.push(hEventOnTryingToHold);
        m_aEventOnFailedToHold.push(hEventOnFailedToHold);
        m_aEventOnSuccessToHold.push(hEventOnSuccessToHold);
        m_aEventOnTryingToUnHold.push(hEventOnTryingToUnHold);
        m_aEventOnFailedToUnHold.push(hEventOnFailedToUnHold);
        m_aEventOnSuccessToUnHold.push(hEventOnSuccessToUnHold);
    };

    function OnTryingToHold(nLineNo) {
        m_aEventOnTryingToHold.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnFailedToHold(nLineNo) {
        m_aEventOnFailedToHold.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnSuccessToHold(nLineNo) {
        m_aEventOnSuccessToHold.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnTryingToUnHold(nLineNo) {
        m_aEventOnTryingToUnHold.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnFailedToUnHold(nLineNo) {
        m_aEventOnFailedToUnHold.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnSuccessToUnHold(nLineNo) {
        m_aEventOnSuccessToUnHold.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    /////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////

    this.SetEventChat = function (
        hEventOnChatContactStatus,
        hEventOnChatRecvMsgText,
        hEventOnChatSendMsgTextFailed,
        hEventOnChatSendMsgTextSuccess,
        hEventOnChatSendMsgTypingFailed,
        hEventOnChatSendMsgTypingSuccess,
        hEventOnChatRecvMsgTypingStarted,
        hEventOnChatRecvMsgTypingEnded
    ) {
        m_aEventOnChatContactStatus.push(hEventOnChatContactStatus);
        m_aEventOnChatRecvMsgText.push(hEventOnChatRecvMsgText);

        m_aEventOnChatSendMsgTextFailed.push(hEventOnChatSendMsgTextFailed);
        m_aEventOnChatSendMsgTextSuccess.push(hEventOnChatSendMsgTextSuccess);
        
        m_aEventOnChatSendMsgTypingFailed.push(hEventOnChatSendMsgTypingFailed);
        m_aEventOnChatSendMsgTypingSuccess.push(hEventOnChatSendMsgTypingSuccess);
        
        m_aEventOnChatRecvMsgTypingStarted.push(hEventOnChatRecvMsgTypingStarted);
        m_aEventOnChatRecvMsgTypingEnded.push(hEventOnChatRecvMsgTypingEnded);
    };

    function OnChatContactStatus(sUserName, nStatusId) {
        m_aEventOnChatContactStatus.forEach(hEvent => {
            if (hEvent != null) hEvent(sUserName, nStatusId);
        });
    }

    function OnChatRecvMsgText(sUserName, sMsgText, bIsChatContact) {
        m_aEventOnChatRecvMsgText.forEach(hEvent => {
            if (hEvent != null) hEvent(sUserName, sMsgText, bIsChatContact);
        });
    }

    function OnChatSendMsgTextFailed(sUserName, nStatusCode, sReasonPhrase, sMsgText, nUserValue32bit) {
        m_aEventOnChatSendMsgTextFailed.forEach(hEvent => {
            if (hEvent != null) hEvent(sUserName, nStatusCode, sReasonPhrase, sMsgText);
        });
    }

    function OnChatSendMsgTextSuccess(sUserName, sMsgText, nUserValue32bit) {
        m_aEventOnChatSendMsgTextSuccess.forEach(hEvent => {
            if (hEvent != null) hEvent(sUserName, sMsgText);
        });
    }
        
    function OnChatSendMsgTypingFailed(sUserName, nStatusCode, sReasonPhrase, nUserValue32bit) {
        m_aEventOnChatSendMsgTypingFailed.forEach(hEvent => {
            if (hEvent != null) hEvent(sUserName, nStatusCode, sReasonPhrase);
        });
    }

    function OnChatSendMsgTypingSuccess(sUserName, nUserValue32bit) {
        m_aEventOnChatSendMsgTypingSuccess.forEach(hEvent => {
            if (hEvent != null) hEvent(sUserName);
        });
    }

    function OnChatRecvMsgTypingStart(sUserName) {
        m_aEventOnChatRecvMsgTypingStarted.forEach(hEvent => {
            if (hEvent != null) hEvent(sUserName);
        });
    }

    function OnChatRecvMsgTypingStop(sUserName) {
        m_aEventOnChatRecvMsgTypingEnded.forEach(hEvent => {
            if (hEvent != null) hEvent(sUserName);
        });
    }


    /////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////

    this.SetEventBusyLamp = function (
        hEventBusyLampSubscribeFailed,
        hEventBusyLampSubscribeSuccess,
        hEventBusyLampContactStatus
    ) {
        m_aEventBusyLampSubscribeFailed.push(hEventBusyLampSubscribeFailed);
        m_aEventBusyLampSubscribeSuccess.push(hEventBusyLampSubscribeSuccess);
        m_aEventBusyLampContactStatus.push(hEventBusyLampContactStatus);
    };

    function OnBusyLampSubscribeFailed(sUserName, nStatusCode, sReasonPhrase) {
        m_aEventBusyLampSubscribeFailed.forEach(hEvent => {
            if (hEvent != null) hEvent(sUserName, nStatusCode, sReasonPhrase);
        });
    }

    function OnBusyLampSubscribeSuccess(sUserName) {
        m_aEventBusyLampSubscribeSuccess.forEach(hEvent => {
            if (hEvent != null) hEvent(sUserName);
        });
    }

    function OnBusyLampContactStatus(sUserName, nStatusId) {
        m_aEventBusyLampContactStatus.forEach(hEvent => {
            if (hEvent != null) hEvent(sUserName, nStatusId);
        });
    }

    /////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////

    this.SetEventTransferCall = function (
        hEventOnTransferCallClosed,
        hEventOnTransferCallFailed,
        hEventOnTransferCallAccepted
    )
    {
        m_aEventOnTransferCallClosed.push(hEventOnTransferCallClosed);
        m_aEventOnTransferCallFailed.push(hEventOnTransferCallFailed);
        m_aEventOnTransferCallAccepted.push(hEventOnTransferCallAccepted);
    };

    function OnTransferCallClosed() {
        m_aEventOnTransferCallClosed.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }

    function OnTransferCallFailed(nLineNo, nStatusCode, sReasonPhrase) {
        m_aEventOnTransferCallFailed.forEach(hEvent => {
            if (hEvent != null) hEvent(nStatusCode, sReasonPhrase);
        });
    }

    function OnTransferCallAccepted(nLineNo) {
        m_aEventOnTransferCallAccepted.forEach(hEvent => {
            if (hEvent != null) hEvent();
        });
    }


    /////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////

}