using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using GTAPIASM;

namespace VR2
{
    public class OptCmd
    {
        public string CmdName;
        public string CmdArgs;

        public OptCmd()
        {
            CmdName = "";
            CmdArgs = "";
        }

    }

    public class VR2Manager : GTTCPCMDServer 
    {
        public List<IntPtr> m_socketList;
        public VR2Main m_vr2;

        public VR2Manager(VR2Main vr2)
            : base()
        {
            m_vr2 = vr2;
            m_socketList = new List<IntPtr>();
        }

        public void SendEvent(IntPtr hSocket, string eventName, string eventArg)
        {
            lock (m_socketList)
            {
                if (m_socketList.Count > 0)
                {
                    try
                    {
                        string sCmd = eventName + ' ' + eventArg + '\n';

                        //VRAPIASM.VRAPIEnv.Log(4, "VR2Manager Sending command: " + sCmd);

                        if (hSocket == IntPtr.Zero)
                        {
                            for (int i = 0; i < m_socketList.Count; i++)
                            {
                                Send(m_socketList[i], sCmd, sCmd.Length);
                            }
                        }
                        else
                        {
                            for (int i = 0; i < m_socketList.Count; i++)
                            {
                                if (hSocket == m_socketList[i])
                                {
                                    Send(hSocket, sCmd, sCmd.Length);
                                    break;
                                }
                            }
                        }

                        //VRAPIASM.VRAPIEnv.Log(4, "VR2Manager Sent out command: " + sCmd);
                    }
                    catch (Exception ex)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                    }
                }
            }
        }

        public override void On_ClientAccepted(IntPtr hSocket, IntPtr UserData)
        {
            //base.On_ClientAccepted(hSocket, UserData);
            lock (m_socketList)
            {
                m_socketList.Add(hSocket);
            }

        }

        public override void On_ClientClosed(IntPtr hSocket, IntPtr UserData)
        {
            //base.On_ClientClosed(hSocket, UserData);
            lock (m_socketList)
            {
                m_socketList.Remove(hSocket);
            }
        }

        public override void On_RecvCmd(IntPtr hSocket, string CmdStr, int nSize, IntPtr UserData)
        {
            //base.On_RecvCmd(hSocket, CmdStr, nSize, UserData);
            //VRAPIASM.VRAPIEnv.Log(4, "VR2Manager Received command(" + hSocket.ToString() + "): " + CmdStr);

            //char[] delimiters = new char[] { ';', ',', ' ', '|' };
            char[] delimiters = new char[] { '\n' };
            string[] members = CmdStr.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);

            try
            {
                for (int i = 0; i < members.Length; i++)
                {
                    string sCmd = members[i];
                    sCmd = sCmd.TrimStart(' ');
                    sCmd = sCmd.TrimEnd('\n', ' ');
                    int nIndex = sCmd.IndexOf(' ');
                    if (nIndex > 0)
                    {
                        OptCmd cmd = new OptCmd();

                        cmd.CmdName = sCmd.Substring(0, nIndex);
                        cmd.CmdArgs = sCmd.Substring(nIndex + 1);

                        ProcessOptCmd(hSocket, cmd);
                    }
                }
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
            }
        }

        public override void On_SendCmd(IntPtr hSocket, string CmdStr, int nSize, IntPtr UserData)
        {
            //base.On_SendCmd(hSocket, CmdStr, nSize, UserData);
        }

        public override void On_Exception(IntPtr hSocket, IntPtr UserData)
        {
            //base.On_Exception(hSocket, UserData);
            lock (m_socketList)
            {
                m_socketList.Remove(hSocket);
            }
        }

        public void ProcessOptCmd(IntPtr hSocket, OptCmd cmd)
        {
            string sArg;

            //VRAPIASM.VRAPIEnv.Log(4, "VR2Manager::ProcessOptCmd(" + hSocket.ToString() + "): " + cmd.CmdName + " " + cmd.CmdArgs);

            if (string.Compare(cmd.CmdName, "GetStatus", true) == 0)
            {
                char[] delimiters = new char[] { ';', ',', ' ', '|' };
                string[] members = cmd.CmdArgs.Split(delimiters, StringSplitOptions.None);
                if (members.Length > 0)
                {
                    if (members[0].ToLower() == "all")
                    {
                        //SendEvent("StatusAll", "");
                    }
                    else if (members[0].ToLower() == "general")
                    {
                        sArg = m_vr2.MaxChanNum.ToString() + "|";
                        sArg += VRAPIASM.VRAPIEnv.GetTotalCallCount().ToString() + "|";
                        sArg += VRAPIASM.VRAPIEnv.GetSuccessfulCallCount().ToString() + "|";
                        for(int i=0; i<m_vr2.MaxChanNum; i++)
                            sArg += VRAPIASM.VRAPIEnv.GetChanStatus(i).ToString() + "|";
                        SendEvent(hSocket, "StatusGeneral", sArg);
                    }
                    else if (members[0].ToLower() == "channel")
                    {
                        if (members.Length > 1)
                        {
                            int chanIdx = -1;

                            try
                            {
                                chanIdx = Convert.ToInt32(members[1]);

                                if (chanIdx >= 0 && chanIdx < m_vr2.MaxChanNum)
                                {
                                    sArg = chanIdx.ToString() + "|";
                                    sArg += m_vr2.Channels[chanIdx].CallerIP + "|";
                                    sArg += m_vr2.Channels[chanIdx].CallerID + "|";
                                    sArg += m_vr2.Channels[chanIdx].CalleeIP + "|";
                                    sArg += m_vr2.Channels[chanIdx].CalleeID + "|";
                                    sArg += VR2.VR2Main.GetSQLDateTime(m_vr2.Channels[chanIdx].InitTime) + "|";
                                    sArg += VR2.VR2Main.GetSQLDateTime(m_vr2.Channels[chanIdx].ConnectTime) + "|";
                                    sArg += VR2.VR2Main.GetSQLDateTime(m_vr2.Channels[chanIdx].EndTime) + "|";
                                    sArg += m_vr2.Channels[chanIdx].UniqueID + "|";
                                    sArg += m_vr2.Channels[chanIdx].AudioFile + "|";
                                    sArg += m_vr2.Channels[chanIdx].AudioFileNum.ToString() + "|";
                                    sArg += m_vr2.Channels[chanIdx].Reason.ToString() + "|";
                                    sArg += m_vr2.Channels[chanIdx].CallDir.ToString() + "|";

                                    if(m_vr2.Channels[chanIdx].CallConnected)
                                        sArg += "1|";
                                    else
                                        sArg += "0|";

                                    //sArg += m_vr2.Channels[chanIdx].ChanStatus.ToString() + "|";
                                    //It is more accurate to use 
                                    sArg += VRAPIASM.VRAPIEnv.GetChanStatus(chanIdx).ToString() + "|";

                                    sArg += m_vr2.Channels[chanIdx].DTMFStr + "|";

                                    SendEvent(hSocket, "StatusChannel", sArg);

                                    //VRAPIASM.VRAPIEnv.Log(4, "VR2Manager::ProcessOptCmd(" + hSocket.ToString() + "): Sent back -> StatusChannel " + sArg);

                                }

                            }
                            catch (Exception)
                            {
                            }
                        }
                    }
                }
            }
            else if (string.Compare(cmd.CmdName, "StopRecording", true) == 0)
            {   
                char[] delimiters = new char[] { ';', ',', ' ', '|' };
                string[] members = cmd.CmdArgs.Split(delimiters, StringSplitOptions.None);
                if (members.Length > 0)
                {
                    int chanIdx = Convert.ToInt32(members[0]);

                    VRAPIASM.VRAPIEnv.StopChanRecording(chanIdx);
                }
            }
            else if (string.Compare(cmd.CmdName, "StartRecording", true) == 0)
            {
                char[] delimiters = new char[] { ';', ',', ' ', '|' };
                string[] members = cmd.CmdArgs.Split(delimiters, StringSplitOptions.None);
                if (members.Length > 0)
                {
                    int chanIdx = Convert.ToInt32(members[0]);

                    if (members.Length > 1)
                        VRAPIASM.VRAPIEnv.RestartChanRecording(chanIdx, members[1]);
                    else
                        VRAPIASM.VRAPIEnv.RestartChanRecording(chanIdx, "");
                }
            }
        }

    }

    public class VR2Client : GTTCPCMDClient
    {
        public IntPtr m_hSocket;

        public VR2Client()
            : base()
        {
            m_hSocket = IntPtr.Zero;
        }

        public override void On_ClientAccepted(IntPtr hSocket, IntPtr UserData)
        {
            //base.On_ClientAccepted(hSocket, UserData);
            m_hSocket = hSocket;
            ServerConnected(true);
        }

        public override void On_ClientClosed(IntPtr hSocket, IntPtr UserData)
        {
            //base.On_ClientClosed(hSocket, UserData);
            m_hSocket = IntPtr.Zero;
            ServerConnected(false);
        }

        public override void On_RecvCmd(IntPtr hSocket, string CmdStr, int nSize, IntPtr UserData)
        {
            //base.On_RecvCmd(hSocket, CmdStr, nSize, UserData);
            //char[] delimiters = new char[] { ';', ',', ' ', '|' };
            char[] delimiters = new char[] { '\n' };
            string[] members = CmdStr.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);

            try
            {
                for (int i = 0; i < members.Length; i++)
                {
                    string sCmd = members[i];
                    sCmd = sCmd.TrimStart(' ');
                    sCmd = sCmd.TrimEnd('\n', ' ');
                    int nIndex = sCmd.IndexOf(' ');
                    if (nIndex > 0)
                    {
                        ProcessServerCmd(sCmd.Substring(0, nIndex), sCmd.Substring(nIndex + 1));
                    }
                }
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
            }
        }

        public virtual void OnCallOffered(int ChanIndex, string CallerIP, string CallerID, string CalleeIP, string CalleeID, uint CallTime, string UniqueID, string AudioFile, int CallDir)
        {
        }

        public virtual void OnCallConnected(int ChanIndex, string CallerIP, string CallerID, string CalleeIP, string CalleeID, uint InitTime, uint ConnectTime, string UniqueID, string AudioFile, int CallDir)
        {
        }

        public virtual void OnCallIdle(int ChanIndex, string CallerIP, string CallerID, string CalleeIP, string CalleeID, uint InitTime, uint ConnectTime, uint EndTime, string UniqueID, string AudioFile, int AudioFileNum, int Reason, int CallDir, string DTMFStr)
        {
        }

        public virtual void OnCallDTMF(int ChanIndex, string KeyPressed, string DTMFStr)
        {
        }

        public virtual void OnCallInfo(int ChanIndex, string CallerIP, string CallerID, string CalleeIP, string CalleeID, string UniqueID, string AudioFile, int CallDir)
        {
        }

        public virtual void ServerConnected(bool bConnected)
        {
        }

        public virtual void OnStatusGeneral(string[] members)
        {
            if (members.Length > 0)
            {
                //first arg is total number of channels
            }
            if (members.Length > 1)
            {
                //second arg is total number of channels which is available(not offline)
            }
        }

        public virtual void OnStatusChannel(VR2Channel chan)
        {
        }

        public virtual void LogoutText(string logInfo)
        {
        }

        public virtual void CDRRawData(string cdr)
        {
        }

        public void GetStatus(string staName)
        {
            string sCmd = "GetStatus " + staName;
            SendOutCmd(sCmd);
        }

        public void StopRecording(int ch)
        {
            string sCmd = "StopRecording " + ch.ToString();
            SendOutCmd(sCmd);
        }

        public void StartRecording(int ch, string filename)
        {
            string sCmd = "StartRecording " + ch.ToString();

            if (filename.Length > 0)
            {
                sCmd += " ";
                sCmd += filename;
            }

            SendOutCmd(sCmd);
        }

        public void SendOutCmd(string sCmd)
        {
            sCmd += "\n";
            if (m_hSocket != IntPtr.Zero)
            {
                Send(m_hSocket, sCmd, sCmd.Length);
                //LogoutText("Send out: " + sCmd);
            }
        }

        public void ProcessServerCmd(string cmdName, string cmdArgs)
        {
            //LogoutText(cmdName + " " + cmdArgs);

            char[] delimiters = new char[] { '|' };
            string[] members = cmdArgs.Split(delimiters, StringSplitOptions.None);

            try
            {
                if (cmdName == "CallOffered")
                {
                    OnCallOffered(Convert.ToInt32(members[0]), members[1], members[2], members[3], members[4], Convert.ToUInt32(members[5]), members[6], members[7], Convert.ToInt32(members[8]));
                    return;
                }
                if (cmdName == "CallConnected")
                {
                    OnCallConnected(Convert.ToInt32(members[0]), members[1], members[2], members[3], members[4], Convert.ToUInt32(members[5]), Convert.ToUInt32(members[6]), members[7], members[8], Convert.ToInt32(members[9]));
                    return;
                }
                if (cmdName == "CallIdle")
                {
                    OnCallIdle(Convert.ToInt32(members[0]), members[1], members[2], members[3], members[4], Convert.ToUInt32(members[5]), Convert.ToUInt32(members[6]), Convert.ToUInt32(members[7]), members[8], members[9], Convert.ToInt32(members[10]), Convert.ToInt32(members[11]), Convert.ToInt32(members[12]), members[13]);
                    return;
                }
                if (cmdName == "CallDTMF")
                {
                    OnCallDTMF(Convert.ToInt32(members[0]), members[1], members[2]);
                    return;
                }
                if (cmdName == "CallInfo")
                {
                    OnCallInfo(Convert.ToInt32(members[0]), members[1], members[2], members[3], members[4], members[5], members[6], Convert.ToInt32(members[7]));
                    return;
                }

                if (cmdName == "CDRRawData")
                {
                    CDRRawData(members[0]);
                }

                if (cmdName == "StatusGeneral")
                {
                    OnStatusGeneral(members);
                    return;
                }

                if (cmdName == "StatusChannel")
                {
                    VR2Channel chan = new VR2Channel();

                    LogoutText(cmdName + " " + cmdArgs + " members count " + members.Length.ToString());

                    if (members.Length >= 15)
                    {
                        chan.ChanIndex = Convert.ToInt32(members[0]);
                        chan.CallerIP = members[1];
                        chan.CallerID = members[2];
                        chan.CalleeIP = members[3];
                        chan.CalleeID = members[4];
                        try
                        {
                            chan.InitTime = VR2.VR2Main.GetDotNetDateTime(members[5]);
                        }
                        catch (Exception)
                        {
                        }
                        try
                        {
                            chan.ConnectTime = VR2.VR2Main.GetDotNetDateTime(members[6]);
                        }
                        catch (Exception)
                        {
                        }

                        try
                        {
                            chan.EndTime = VR2.VR2Main.GetDotNetDateTime(members[7]);
                        }
                        catch (Exception)
                        {
                        }
                        chan.UniqueID = members[8];
                        chan.AudioFile = members[9];
                        try{
                            chan.AudioFileNum = Convert.ToInt32(members[10]);
                        }
                        catch (Exception)
                        {
                        }

                        try{
                            chan.Reason = Convert.ToInt32(members[11]);
                        }
                        catch (Exception)
                        {
                        }

                        try
                        {
                            chan.CallDir = Convert.ToInt32(members[12]);
                        }
                        catch (Exception)
                        {
                        }

                        try
                        {
                            chan.CallConnected = Convert.ToInt32(members[13]) == 1;
                        }
                        catch (Exception)
                        {
                        } 
                        
                        try
                        {
                            chan.ChanStatus = Convert.ToInt32(members[14]);
                        }
                        catch (Exception)
                        {
                        }

                        chan.DTMFStr = members[15];
                    }

                    if (chan.ChanIndex >= 0)
                        OnStatusChannel(chan);

                    return;
                }
            }
            catch (Exception ex)
            {
                LogoutText(ex.ToString());
            }
        }
    }
}
