using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace CSharpSIPPhone
{
    public partial class PhoneForm : Form
    {
        public SIPPhoneCfgWrap cfgWrap;
        public bool phoneRunning;
        public MyGTAPIEnv env;

        public PhoneForm()
        {
            InitializeComponent();

            cfgWrap = new SIPPhoneCfgWrap();
            phoneRunning = false;
            env = null;
        }

        private void PhoneForm_Load(object sender, EventArgs e)
        {
            CfgForm cfg = new CfgForm(cfgWrap);
            if (cfg.ShowDialog() == DialogResult.OK)
            {
                if (phoneRunning)
                    FreeSIPServer();

                InitSIPServer();
            }
            else
            {
                if (!phoneRunning)
                    InitSIPServer();
            }

            tbSipAddr.Text = "8888@sip.pcbest.net";

            tbSpeaker.Maximum = 100;
            tbSpeaker.Minimum = 0;
            tbMicrophone.Maximum = 100;
            tbMicrophone.Minimum = 0;

            tbSpeaker.Value = Convert.ToInt32(env.GetSpeakerVolume() * 100);
            tbMicrophone.Value = Convert.ToInt32(env.GetMicVolume() * 100);
        }


        public void On_RecvConnected(int ch)
        {
            env.StopSound(); //stop the ring tone or ringback tone

            //Send_SetChanInConference(0, -1, 1)
            //Send_SetChanInConference(0, ch, 1)
            env.Send_StartDXAudio(ch); //because this is a client phone, we start DirectX audio

            //It is in timer's thread now, because we use timer to process event
            string sCodec;
            int nCodec;
            nCodec = env.GetChanAudioCodec(ch);

            sCodec = "unknown";

            switch(nCodec)
            {
                case 0:
                    sCodec = "G711-Ulaw";
                    break;
                case 3:
                    sCodec = "GSM";
                    break;
                case 4:
                    sCodec = "G723.1";
                    break;
                case 8:
                    sCodec = "G711-Alaw";
                    break;
                case 18:
                    sCodec = "G729";
                    break;
                case 98:
                    sCodec = "G716-32";
                    break;
                case 102:
                    sCodec = "Speex";
                    break;
                case 103:
                    sCodec = "iLBC-20ms";
                    break;
                case 104:
                    sCodec = "iLBC-30ms";
                    break;
            }

            btnDial.Text = "Answer";
            btnDial.Enabled = false;
            btnHungup.Enabled = true;
            btnHold.Enabled = true;
            btnTransfer.Enabled = true;
            lbLineStatus.Text = "Call Connected! " + sCodec;

            //env.Send_RecordAudio(ch, "c:\\temp\\csharpphone.mp3", 0, "", 0, 0);
        }

        public void On_RecvOfferedEx(int ch, string sCaller, string sCallee, string sDestAddr, string sViaAddr, string sFromIP, ushort nFromPort, string sOrgSIPTxt, string sReserved1, string sReserved2, string sReserved3)
        {
            tbSipAddr.Text = sCaller;
            btnDial.Text = "Answer";
            btnDial.Enabled = true;
            btnHungup.Enabled = true;
            btnHold.Enabled = false;
            btnTransfer.Enabled = false;
            lbLineStatus.Text = "New Call from " + sCaller;

            env.StopSound();
            env.PlayLocalRingSound();

            //richTextBox1.Text = sOrgSIPTxt;
        }

/*
        public void On_RecvOffered(int ch, string sCaller, string sCallee, string sDestAddr, string sViaAddr, string sFromIP, ushort nFromPort)
        {
            tbSipAddr.Text = sCaller;
            btnDial.Text = "Answer";
            btnDial.Enabled = true;
            btnHungup.Enabled = true;
            btnHold.Enabled = false;
            btnTransfer.Enabled = false;
            lbLineStatus.Text = "New Call from " + sCaller;

            env.StopSound();
            env.PlayLocalRingSound();

            //env.SetChanAudioDir(ch, 2);
        }*/

        public void On_RecvDialing(int ch, string sCaller, string sCallee)
        {
            btnDial.Text = "Dial";
            btnDial.Enabled = false;
            btnHungup.Enabled = true;
            btnHold.Enabled = false;
            btnTransfer.Enabled = false;
            lbLineStatus.Text = "Dialing";
        }

        public void On_RecvRinging(int ch)
        {
            btnDial.Text = "Dial";
            btnDial.Enabled = false;
            btnHungup.Enabled = true;
            btnHold.Enabled = false;
            btnTransfer.Enabled = false;
            lbLineStatus.Text = "Remote side ringing";

            env.StopSound();
            env.PlayRemoteRingSound();
        }

        public void On_RecvIdle(int ch, int code, string desc)
        {
            btnDial.Text = "Dial";
            btnDial.Enabled = true;
            btnHungup.Enabled = false;
            btnHold.Enabled = false;
            btnTransfer.Enabled = false;
            lbLineStatus.Text = "LINE IDLE";

            env.StopSound();

            //Send_SetChanInConference(0, -1, 0)
            //Send_SetChanInConference(0, ch, 0)
        }

        public void On_RecvRegStatus(int user_id, int status, int regtime)
        {
            lbSIPAcctStatus.Text = env.CFG_GetValue("gtsrv.sip.reg1.username", "");
            if (lbSIPAcctStatus.Text.Length > 0)
            {
                if (status == 0)
                    lbSIPAcctStatus.Text += " XXX(Not Registered)";
            }
            else
                lbSIPAcctStatus.Text = "No SIP Account";
        }

        public void On_RecvHolding(int ch, int hold_on)
        {
            GTAPIASM.GTAPIChan chan;

            chan = env.GetChannel(0);

            if (hold_on == 1)
            {
                env.Send_StopDXAudio(ch);
            }
            else
            {
                env.Send_StartDXAudio(ch);
            }

            if(chan.ch_status == GTAPIASM.GTAPI_CHANNEL_STATE.CONNECTED)
            {
                btnHold.Text = "Hold";
                btnHold.Enabled = true;
                btnTransfer.Enabled = true;
            }

            if(chan.ch_status == GTAPIASM.GTAPI_CHANNEL_STATE.HOLDING)
            {
                btnHold.Text = "Unhold";
                btnHold.Enabled = true;
                btnTransfer.Enabled = false;
            }

            if(chan.ch_status == GTAPIASM.GTAPI_CHANNEL_STATE.BE_HOLDED)
            {
                btnHold.Enabled = false;
                btnTransfer.Enabled = false;
            }
        }

        public bool InitSIPServer()
        {
            if (phoneRunning)
                return true;

            GTAPIASM.GTAPIEnv.g_MixerType = 1; //GTAPI directx API
            //GTAPIASM.GTAPIEnv.g_MixerType = 0; //C# MIXER API

            env = new MyGTAPIEnv();
            env.mainForm = this;
            env.CreateEnv();
            env.SetMainWnd(Handle);


            env.CFG_SetValue("gtsrv.sip.server.model", "0");

            if (cfgWrap.Protocol == 1) //0(UDP) is the default setting, no need to set
            {
                //here note, for this tag, 1 = UDP, 2 = TCP, and 3 = BOTH, "4" = SIP TLS(SIP Port +1)
                //"5" = SIP TLS & UDP,   "6" = SIP TLS & TCP,  "7" = SIP TLS & UDP & TCP
                env.CFG_SetValue("gtsrv.sip.protocol", "2");
            }
            else if(cfgWrap.Protocol == 2) //TLS
            {
                env.CFG_SetValue("gtsrv.sip.protocol", "5"); //TLS + UDP(default)
                //SIPs enabled. need to set private key fields
                env.CFG_SetValue("gtsrv.sip.ssl.type", "3");

                env.CFG_SetValue("gtsrv.sip.ssl.cert.file", Application.StartupPath + "\\cert.pem");
                env.CFG_SetValue("gtsrv.sip.ssl.key.file", Application.StartupPath + "\\key.pem");
            }

            env.CFG_SetValue("gtsrv.srtp.type", "1"); //SRTP type 1, auto

            //SIP IP Address you want to use on local
            //Leave it unset if you want to listen on all the network interface
            //CFG_SetValue("gtsrv.sip.ip.address", "");

            //SIP Port, default 5060
            env.CFG_SetValue("gtsrv.sip.ip.port", cfgWrap.SIPPort.ToString());

            //RTP PORT
            env.CFG_SetValue("gtsrv.sip.rtpstartrange", cfgWrap.RTPPort.ToString());
            //env.CFG_SetValue("gtsrv.sip.rtpendrange", "18800")

            //Log
            env.CFG_SetValue("gtsrv.log.level", "4");
            env.CFG_SetValue("gtsrv.log.filename",  "csharpsipphone.txt");

            //Prefered codec list
            env.CFG_SetValue("gtsrv.sip.prefered.codec", cfgWrap.AudioCodecs);
            //env.CFG_SetValue("gtsrv.sip.prefered.video.codec", "34,115,124")

            //NAT or STUN
            if (cfgWrap.StunServer.Length > 0)
            {
                env.CFG_SetValue("gtsrv.sip.stun.server", cfgWrap.StunServer);
            }
            else
            {
                env.CFG_SetValue("gtsrv.sip.use.nat.addr", cfgWrap.UseNATAddr ? "1" : "0");
            }

            //JB buffer and dirctX buffer settings, DO NOT change
            //env.CFG_SetValue("gtsrv.sip.jb.min.delay", "0")
            //env.CFG_SetValue("gtsrv.sip.jb.max.delay", "5")
            //env.CFG_SetValue("gtsrv.sip.jb.adaptive", "0")
            //env.CFG_SetValue("gtsrv.sip.jb.get.all.data", "1")
            //env.CFG_SetValue("gtsrv.sip.dx.playback.delay", "2")

            //channnel numbers, here we only use 1 channel
            env.CFG_SetValue("gtsrv.sip.boardnum.per.server", "1");
            env.CFG_SetValue("gtsrv.sip.spannum.per.board", "1");
            env.CFG_SetValue("gtsrv.sip.channum.per.span", "1");

            //define inbound and outbound channels, NOT USEFUL ANYMORE. DO NOT USE
            //env.CFG_SetValue("gtsrv.channel.inbound", "0-3");
            //env.CFG_SetValue("gtsrv.channel.outbound", "4-15");
			
			//env.CFG_SetValue("gtsrv.sip.get.totag.from.ring.for.cancel", "0");

            //Internal communication port
            env.CFG_SetValue("gtsrv.net.port", "9712"); //any port you like

            //env.CFG_SetValue("gtsrv.sip.get.totag.from.ring.for.cancel", "0");

            //conference room
            //env.CFG_SetValue("gtsrv.sip.conference.room", "1")

            //Configuration file, if you want to define parameters in a file
            //env.CFG_SetValue(GTSRV_CFG_FILENAME, "GTSimpelPhone.ini");

            //Application name, it is related to sdk licence
		    //Please contact PCBest Network(www.pcbest.net) to get licence info
            env.SetAppName("PentaCorp");
            env.CFG_SetValue("gtsrv.licence.key", "49KQK-ZMKS5-E535Q-649MF-8MXXY");
            //env.CFG_SetValue("gtsrv.lic.usb.key.driver", "f:");

            //env.CFG_SetValue("gtsrv.sip.conference.room", "1")

            //define outbound route, leave them unset if you don't know
            //env.CFG_SetValue("gtsrv.sip.outbound.via.type", "0");
            //env.CFG_SetValue("gtsrv.sip.outbound.via.proxy", "");

            //env.CFG_SetValue("gtsrv.sip.on.rtp.packet", "-1");

            //set sip client user info ***** If you want to take incoming calls, you must set this value,
            // or you can only answer calls by your IP address
            //you must get an account from sip service provider first

            if(cfgWrap.DisplayName.Length > 0 && cfgWrap.UserName.Length > 0 && cfgWrap.Domain.Length > 0 && cfgWrap.Password.Length > 0)
            {
                env.CFG_SetValue("gtsrv.sip.reg.client.num", "1");
                env.CFG_SetValue("gtsrv.sip.reg1.displayname", cfgWrap.DisplayName);
                env.CFG_SetValue("gtsrv.sip.reg1.username", cfgWrap.UserName);
                env.CFG_SetValue("gtsrv.sip.reg1.domain", cfgWrap.Domain);
                env.CFG_SetValue("gtsrv.sip.reg1.proxy", cfgWrap.Domain);
                env.CFG_SetValue("gtsrv.sip.reg1.authorization", cfgWrap.UserName);
                env.CFG_SetValue("gtsrv.sip.reg1.password", cfgWrap.Password);
                env.CFG_SetValue("gtsrv.sip.reg1.expire", "3600");
                if(cfgWrap.RegisterDomain)
                    env.CFG_SetValue("gtsrv.sip.reg1.register", "1");
                else
                    env.CFG_SetValue("gtsrv.sip.reg1.register", "0");

                if (cfgWrap.Protocol == 1) //0(UDP) is the default setting, no need to set
                {
                    env.CFG_SetValue("gtsrv.sip.reg1.prot", "1");
                }
                else if(cfgWrap.Protocol == 2) //2 TLS, the remote SIP account support TLS registration
                {
                    env.CFG_SetValue("gtsrv.sip.reg1.prot", "2"); //2 means TLS
                    env.CFG_SetValue("gtsrv.sip.reg1.srtp", "1"); //use srtp for the call
                }
            }

            if(cfgWrap.UserName.Length > 0)
                lbSIPAcctStatus.Text = env.CFG_GetValue("gtsrv.sip.reg1.username", "") + " XXX";
            else
                lbSIPAcctStatus.Text = "No SIP Account";


            if(env.StartServer())
            {
                //MessageBox.Show(env.GetLicTo());

                env.Send_GetRegStatus(0);

                lbLineStatus.Text = "IDLE";
                btnDial.Text = "Dial";
                btnDial.Enabled = true;
                btnHungup.Enabled = false;
                btnHold.Enabled = false;
                btnTransfer.Enabled = false;

                phoneRunning = true;

                timer1.Enabled = true;

                return true;
            }
            else
            {
                MessageBox.Show("StartServer Failed! Please make sure the SIP port you set is not being used by another application!");
                lbLineStatus.Text = "ERROR: START PHONE";
                btnDial.Enabled = false;
                btnHungup.Enabled = false;
                btnHold.Enabled = false;
                btnTransfer.Enabled = false;

                phoneRunning = false;

                timer1.Enabled = false;

                return false;
            }
        }

        public bool FreeSIPServer()
        {
            if (phoneRunning)
            {
                timer1.Enabled = false;
                phoneRunning = false;

                env.StopServer();
                env.DestroyEnv();
                env = null;
            }

            return true;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (phoneRunning && env != null)
                env.ProcessGTAPIEvent();
        }

        private void PhoneForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            FreeSIPServer();
        }

        private void btnDial_Click(object sender, EventArgs e)
        {
            MakeCallOut();
        }

        public void MakeCallOut()
        {
            string calledNum;
            string userDomain;
            userDomain = env.CFG_GetValue("gtsrv.sip.reg1.domain", "");

            if(btnDial.Text == "Answer")
            {
                env.Send_Answer(0);
            }
            else
            {
                if(tbSipAddr.Text.Contains("@"))
                {
                    calledNum = "<sip:" + tbSipAddr.Text + ">";
                    env.Send_Make(0, calledNum, "");
                }
                else
                {
                    if(tbSipAddr.Text.Contains("."))
                    {
                        //assume it is ip address or domain
                        calledNum = "<sip:" + tbSipAddr.Text + ">";
                        env.Send_Make(0, calledNum, "");
                    }
                    else
                    {
                        if(userDomain.Length > 0)
                        {
                            calledNum = "<sip:" + tbSipAddr.Text + "@" + userDomain + ">";
                            env.Send_Make(0, calledNum, "");
                        }
                        else
                        {
                            MessageBox.Show("Cannot reach the destionation!");
                        }
                    }
                }
            }
        }

        public void SetAudioRecording(bool r, string root_folder)
        {
            if(r)
            {
                env.CFG_SetValue("gtphone.audio.record.enabled", "1");
                env.CFG_SetValue("gtphone.audio.record.rootdir", root_folder);
            }
            else
            {
                env.CFG_SetValue("gtphone.audio.record.enabled", "0");
                env.CFG_SetValue("gtphone.audio.record.rootdir", "");
            }
        }

        public void SetSoundDevices(string play_device, string record_device)
        {
            env.CFG_SetValue("gtsrv.sip.dxsound.device.playback", play_device);
            env.CFG_SetValue("gtsrv.sip.dxsound.device.capture", record_device);
            env.Send_ResetDXAudio(0);
        }

        private void btnHungup_Click(object sender, EventArgs e)
        {
            env.Send_HangUp(0, 0, "");
        }

        private void btnHold_Click(object sender, EventArgs e)
        {
            GTAPIASM.GTAPIChan chan;
            chan = env.GetChannel(0);
            if(chan.ch_status == GTAPIASM.GTAPI_CHANNEL_STATE.CONNECTED || chan.ch_status == GTAPIASM.GTAPI_CHANNEL_STATE.HOLDING)
            {
                env.Send_Hold(0);
            }
        }

        private void btnTransfer_Click(object sender, EventArgs e)
        {
            TransToForm dlg = new TransToForm();
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                string sAddr = dlg.sTransToAddr;
                string destAddr;
                if(sAddr.Contains("@"))
                {
                    destAddr = "<sip:" + sAddr + ">";
                }
                else
                {
                    string myDomain = env.CFG_GetValue("gtsrv.sip.reg1.domain", "");
                    if(myDomain.Length == 0)
                    {
                        MessageBox.Show("Error: Cannot transfer call to this address");
                        return;
                    }
                    destAddr = "<sip:" + sAddr + "@" + myDomain + ">";
                }

                env.Send_Transfer(0, destAddr);
            }
        }

        void PressButton(string s)
        {
            GTAPIASM.GTAPIChan chan;

            chan = env.GetChannel(0);
            if(chan.ch_status == GTAPIASM.GTAPI_CHANNEL_STATE.CONNECTED)
                env.Send_PlayDTMFStr(0, s);
            else
                tbSipAddr.Text = tbSipAddr.Text + s;

            env.PlayNumTone(s[0]);
        }

        private void Button1_Click(object sender, EventArgs e)
        {
            PressButton("1");
        }

        private void Button2_Click(object sender, EventArgs e)
        {
            PressButton("2");
        }

        private void Button3_Click(object sender, EventArgs e)
        {
            PressButton("3");
        }

        private void Button4_Click(object sender, EventArgs e)
        {
            PressButton("4");
        }

        private void Button5_Click(object sender, EventArgs e)
        {
            PressButton("5");
        }

        private void Button6_Click(object sender, EventArgs e)
        {
            PressButton("6");
        }

        private void Button7_Click(object sender, EventArgs e)
        {
            PressButton("7");
        }

        private void Button8_Click(object sender, EventArgs e)
        {
            PressButton("8");
        }

        private void Button9_Click(object sender, EventArgs e)
        {
            PressButton("9");
        }

        private void Button10_Click(object sender, EventArgs e)
        {
            PressButton("*");
        }

        private void Button11_Click(object sender, EventArgs e)
        {
            PressButton("0");
        }

        private void Button12_Click(object sender, EventArgs e)
        {
            PressButton("#");
        }

        private void cbMuteSpeaker_CheckedChanged(object sender, EventArgs e)
        {
            if(cbMuteSpeaker.Checked) 
            {
                env.SetSpeakerMuteStatus(1);
            }
            else
            {
                env.SetSpeakerMuteStatus(0);
            }
        }

        private void cbMuteMicrophone_CheckedChanged(object sender, EventArgs e)
        {
            if(cbMuteMicrophone.Checked) 
            {
                env.SetMicMuteStatus(1);
            }
            else
            {
                env.SetMicMuteStatus(0);
            }
        }

        private void btnOptions_Click(object sender, EventArgs e)
        {
            CfgForm cfg = new CfgForm(cfgWrap);
            if (cfg.ShowDialog() == DialogResult.OK)
            {
                if (phoneRunning)
                    FreeSIPServer();

                InitSIPServer();
            }
            else
            {
            }
        }

        private void btnSoundDevice_Click(object sender, EventArgs e)
        {
            SoundDevice dlg = new SoundDevice();
            dlg.sSpeaker = env.CFG_GetValue("gtsrv.sip.dxsound.device.playback", "");
            dlg.sMic = env.CFG_GetValue("gtsrv.sip.dxsound.device.capture", "");
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                SetSoundDevices(dlg.sSpeaker, dlg.sMic);
            }
        }

        private void btnRecording_Click(object sender, EventArgs e)
        {
            DynamicRecordForm dlg = new DynamicRecordForm();
            dlg.bEnableRecord = env.CFG_GetValue("gtphone.audio.record.enabled", "0") == "1";
            if (dlg.bEnableRecord)
            {
                dlg.sRootFolder = env.CFG_GetValue("gtphone.audio.record.rootdir", "c:\temp");
            }

            if (dlg.ShowDialog() == DialogResult.OK)
            {
                SetAudioRecording(dlg.bEnableRecord, dlg.sRootFolder);
            }

        }

        private void tbSpeaker_Scroll(object sender, EventArgs e)
        {
            float r = tbSpeaker.Value;
            r /= 100;
            env.SetSpeakerVolume(r);
        }

        private void tbMicrophone_Scroll(object sender, EventArgs e)
        {
            float r = tbMicrophone.Value;
            r /= 100;
            env.SetMicVolume(r);
        }


    }
}
