using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Collections;
using Microsoft.Win32;

namespace BulkDialer
{
    public partial class Form1 : Form
    {
        public static BulkDialerEnv env;
        SqlConnection myConn;

        public string sDBServer = "";
        public string sDBName = "dialer";
        public string sUserName = "sa";
        public string sPassword = "";

        public Queue m_JobsQueue;
        public Queue m_DoneQueue;
        public CallJob[] chan_calls;

        public Int64 m_JobID;
        public string m_sIniFile;
        public string m_sLicKey;

        public uint m_totalCalls;
        public uint m_succCalls;
        public uint m_failCalls;

        public Form1()
        {
            InitializeComponent();
            env = null;
            m_JobsQueue = new Queue();
            m_DoneQueue = new Queue();
            chan_calls = null;
            m_JobID = 0;
            m_sIniFile = "c:\\BulkDialer.ini";
            m_sLicKey = "";
            
            m_totalCalls = 0;
            m_succCalls = 0;
            m_failCalls = 0;
        }

        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Form2 dlg = new Form2();
            dlg.iniFile = m_sIniFile;
            dlg.licKey = m_sLicKey;
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                m_sIniFile = dlg.iniFile;
                m_sLicKey = dlg.licKey;

                RegistryKey regkey;
                regkey = Registry.CurrentUser.CreateSubKey("SOFTWARE\\PCBest.net\\BulkDialer");

                if (regkey == null)
                    return;
                
                regkey.SetValue("LicKey", m_sLicKey);
                regkey.SetValue("INIFile", m_sIniFile);

                regkey.Close();
            }
        }

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

        public void InitSIPServer()
        {
            if (env != null) return;

            env = new BulkDialerEnv();
            env.mainForm = this;

            env.CreateEnv();
            env.SetMainWnd(Handle);

            //Configuration file, if you want to define parameters in a file
            env.CFG_SetValue("gtsrv.config.filename", m_sIniFile);

            //Application name, it is related to sdk licence
            //Please contact PCBest Network(www.pcbest.net) to get licence info
            env.SetAppName("GTBulkDialer");
            env.CFG_SetValue("gtsrv.licence.key", m_sLicKey);

            if (!env.StartServer())
            {
                MessageBox.Show("Cannot start dialer! Please check if the SIP port set in INI is used by another application.");
                env.DestroyEnv();
                env = null;
                return;
            }
            else
            {
                if (env.GetLicTo().Length > 0)
                {
                }
                else
                {
                    this.Text = "Bulk Call Dialer(unlicensed software. max call duration is limited to 3 minutes)" ;
                }
            }

            dataGridView1.RowCount = (int)env.GetChannelCount();
            dataGridView1.ColumnCount = 5;
            dataGridView1.Columns[0].Name = "Caller";
            dataGridView1.Columns[1].Name = "Callee";
            dataGridView1.Columns[2].Name = "Staus";
            dataGridView1.Columns[3].Name = "Start Time";
            dataGridView1.Columns[4].Name = "Duration";

            sDBServer = env.CFG_GetValue("bulkdialer.db.server", "");
            sDBName = env.CFG_GetValue("bulkdialer.db.name", "dialer");
            sUserName = env.CFG_GetValue("bulkdialer.db.username", "sa");
            sPassword = env.CFG_GetValue("bulkdialer.db.password", "");

            chan_calls = new CallJob[(int)env.GetChannelCount()];

            for (int i = 0; i < env.GetChannelCount(); i++)
            {
                chan_calls[i] = null;
                env.StartTimer(i, 2000);
            }

            ConnectDB();

            addJobsToolStripMenuItem.Enabled = true;
            startToolStripMenuItem.Enabled = false;
            stopToolStripMenuItem.Enabled = true;
        }

        public void FreeSIPServer()
        {
            addJobsToolStripMenuItem.Enabled = false;
            startToolStripMenuItem.Enabled = true;
            stopToolStripMenuItem.Enabled = false;

            DisconnectDB();

            if (env != null)
            {
                env.StopServer();
                env.DestroyEnv();
                env = null;
            }
        }

        public void On_RecvDTMFDone(int ch, int doneReason, string dtmfBuf)
        {
            chan_calls[ch].Surveys[0].dtmf_done = "";

            string termstr = "";
            for (int i = 0; i < chan_calls[ch].Surveys[0].dtmfs.Length; i++)
            {
                termstr += chan_calls[ch].Surveys[0].dtmfs[i];
            }

            for (int i = 0; i < dtmfBuf.Length; i++)
            {
                if (termstr.Contains(dtmfBuf[i].ToString()))
                {
                    chan_calls[ch].Surveys[0].dtmf_done += dtmfBuf[i];
                    break;
                }
            }

            env.Send_HangUp(ch, 0, "");
        }

        public void On_RecvConnected(int ch)
        {
            chan_calls[ch].BeginTime = DateTime.Now;
            string termstr = "";
            for (int i = 0; i < chan_calls[ch].Surveys[0].dtmfs.Length; i++)
            {
                termstr += chan_calls[ch].Surveys[0].dtmfs[i];
            }
            env.Send_PlayAudio(ch, chan_calls[ch].Surveys[0].voice_fn, 0, termstr, 0, 0);
        }

        public void On_RecvDialing(int ch, string sCaller, string sCallee)
        {
        
        }

        public bool SaveCall(int ch, CallJob call)
        {
            bool ret = false;
            if (IsDBConnected())
            {
                int result = 0;
                if (call.BeginTime != call.EndTime)
                {
                    result = 1;
                }
                string dtmfs = call.Surveys[0].dtmf_done;

                try
                {
                    SqlCommand catCMD = myConn.CreateCommand();
                    catCMD.CommandText = "INSERT INTO done VALUES(" + call.ID.ToString() + ", " + result.ToString() + ", '" + dtmfs + "', "; ;
                    catCMD.CommandText += "'" + GetSQLDateTime(call.InitTime) + "', '" + GetSQLDateTime(call.BeginTime) + "', '" + GetSQLDateTime(call.EndTime) + "')";
                    if (catCMD.ExecuteNonQuery() == 1)
                    {
                        ret = true;
                        m_totalCalls++;
                        if (result == 1)
                            m_succCalls++;
                        else
                            m_failCalls++;
                    }
                    else
                    {
                    }
                }
                catch (Exception)
                {
                    ret = false;
                }
            }
            return ret;
        }

        public void On_RecvIdle(int ch)
        {
            if (chan_calls[ch] != null)
            {
                chan_calls[ch].EndTime = DateTime.Now;

                if (SaveCall(ch, chan_calls[ch]))
                {
                    chan_calls[ch] = null;
                }
            }
            env.StartTimer(ch, 1000);
        }

        public void On_RecvOffered(int ch, string sCaller, string sCallee, string sDestAddr, string sViaAddr, string sFromIP, ushort nFromPort)
        {
            //no incoming calls
            env.Send_HangUp(ch, 0, "");
        }

        public void On_RecvRinging(int ch)
        {
            //should show up?
            if (env != null)
            {
                GTAPIASM.GTAPIChan chan = env.GetChannel(ch);
                if (chan != null)
                {
                    switch (chan.ch_status)
                    {
                        case GTAPIASM.GTAPI_CHANNEL_STATE.DIALING:
                            dataGridView1.Rows[ch].Cells[2].Value = "RINGING";
                            break;
                    }
                }
            }
        }

        public void On_Timer(int ch)
        {
            if (chan_calls[ch] != null)
            {
                if (SaveCall(ch, chan_calls[ch]))
                {
                    chan_calls[ch] = null;
                }
                env.StartTimer(ch, 1000);
            }
            else
            {
                if (m_JobsQueue.Count > 0)
                {
                    chan_calls[ch] = (CallJob)m_JobsQueue.Dequeue();
                    if (chan_calls[ch] != null)
                    {
                        string caller = chan_calls[ch].Caller;
                        string callee = chan_calls[ch].Callee;
                        if (caller.Length > 0)
                        {
                            if (!caller.Contains("<sip:"))
                            {
                                caller = "<sip:" + caller + "@" + env.CFG_GetValue("gtsrv.sip.reg1.domain", "") + ">";
                            }
                        }

                        if (callee.Length > 0)
                        {
                            if (!callee.Contains("<sip:"))
                            {
                                callee = "<sip:" + callee + "@" + env.CFG_GetValue("gtsrv.sip.reg1.domain", "") + ">";
                            }
                            env.Send_Make(ch, callee, caller);
                            chan_calls[ch].InitTime = DateTime.Now;
                        }
                        else
                        {
                            //not right, set the call handle to null, and timer
                            if (SaveCall(ch, chan_calls[ch]))
                            {
                                chan_calls[ch] = null;
                            }
                            env.StartTimer(ch, 1000);
                        }
                    }
                    else
                    {
                        //no jobs, come back one second later
                        env.StartTimer(ch, 1000);
                    }
                }
                else
                {
                    env.StartTimer(ch, 1000);
                }
            }
        }

        public void On_RecvRegStatus(int user_id, int status, int regtime)
        {
            user_id++;
            string tag = "gtsrv.sip.reg" + user_id.ToString() + ".username";
            if (env != null)
            {
                string username = env.CFG_GetValue(tag, "");
                if (username.Length > 0)
                {
                    if (status == 1)
                    {
                        lbSIPAcct.Text = username + " Registered!";
                    }
                    else
                    {
                        lbSIPAcct.Text = username + " Not Registered!";
                    }
                }
            }
        }

        public void On_RecvAudioPlayDone(int ch, int doneReason, string dtmfBuffer)
        {
            if (chan_calls[ch] != null)
            {
                if (doneReason == 3) //audio play done
                {
                    chan_calls[ch].ErrorCount++;
                    if (chan_calls[ch].ErrorCount == 3)
                    {
                        env.Send_HangUp(ch, 0, "");
                    }
                    else
                    {
                        string termstr = "";
                        for (int i = 0; i < chan_calls[ch].Surveys[0].dtmfs.Length; i++)
                        {
                            termstr += chan_calls[ch].Surveys[0].dtmfs[i];
                        }
                        env.Send_PlayAudio(ch, chan_calls[ch].Surveys[0].voice_fn, 0, termstr, 0, 0);
                    }
                }
            }
        }


        private void startToolStripMenuItem_Click(object sender, EventArgs e)
        {
            InitSIPServer();
        }

        private void stopToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FreeSIPServer();
        }

        public string GetConnStr()
        {
            string connStr = "Data Source=";

            if (sUserName.Length == 0)
                sUserName = "sa";

            if (sDBServer.Length == 0)
            {
                connStr += ".\\SQLEXPRESS;Initial Catalog=";
            }
            else
            {
                connStr += sDBServer + "\\SQLEXPRESS;Initial Catalog=";
            }

            if (sDBName.Length == 0)
            {
                connStr += "digilog;User Id=";
            }
            else
            {
                connStr += sDBName + ";User Id=";
            }

            connStr += sUserName + ";Password=";
            connStr += sPassword;

            return connStr;
        }

        public bool ConnectDB()
        {
            //string connStr = "Data Source=.\\SQLEXPRESS;Initial Catalog=digilog;User Id=sa;Password=12345678";
            string connStr = GetConnStr();

            myConn = new SqlConnection(connStr);
            try
            {
                myConn.Open();
            }
            catch (Exception e)
            {
                myConn = null;
                Console.WriteLine(e.ToString());
                return false;
            }

            return true;
        }

        public bool DisconnectDB()
        {
            try
            {
                myConn.Close();
            }
            catch (Exception)
            {
            }
            myConn = null;
            return true;
        }

        public bool IsDBConnected()
        {
            return myConn != null;
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            if (env != null)
            {
                if (IsDBConnected())
                {
                    try
                    {
                        GetJobs();
                        SaveJobs();
                    }
                    catch (Exception)
                    {
                    }
                }
            }
        }

        public static DateTime GetDotNetDateTime(string s)
        {
            string temp = "";
            temp += s[0];
            temp += s[1];
            temp += s[2];
            temp += s[3];
            int dtYear = Convert.ToInt32(temp);

            temp = "";
            temp += s[5];
            temp += s[6];
            int dtMonth = Convert.ToInt32(temp);

            temp = "";
            temp += s[8];
            temp += s[9];
            int dtDay = Convert.ToInt32(temp);

            temp = "";
            temp += s[11];
            temp += s[12];
            int dtHour = Convert.ToInt32(temp);

            temp = "";
            temp += s[14];
            temp += s[15];
            int dtMinute = Convert.ToInt32(temp);

            temp = "";
            temp += s[17];
            temp += s[18];
            int dtSecond = Convert.ToInt32(temp);

            DateTime dt = new DateTime(dtYear, dtMonth, dtDay, dtHour, dtMinute, dtSecond);
            return dt;
        }

        string GetSQLDateTime(DateTime dt)
        {
            string sret = "";
            sret += dt.Year.ToString() + "-" + dt.Month.ToString() + "-" + dt.Day.ToString() + " ";
            sret += dt.Hour.ToString() + ":" + dt.Minute.ToString() + ":" + dt.Second.ToString();
            return sret;
        }
        
        public void GetJobs()
        {
            SqlCommand catCMD = myConn.CreateCommand();
            string sNow = GetSQLDateTime(DateTime.Now);
            //here should add the number of query, which is only allow first 2 * env.GetChannelCount()
            uint n = 2 * env.GetChannelCount();
            catCMD.CommandText = "SELECT TOP " +n.ToString() + " * FROM jobs where starttime < '" + sNow +"'";
            Queue tempQueue = new Queue();

            SqlDataReader myReader = catCMD.ExecuteReader();

            while (myReader.Read())
            {
                CallJob call = new CallJob();
                call.ID = myReader.GetInt64(0);
                call.Caller = myReader.GetString(1);
                call.Callee = myReader.GetString(2);
                string dtmfs = myReader.GetString(3);
                string wavs = myReader.GetString(4);
                call.Surveys = new SurveyItem[1];
                call.Surveys[0] = new SurveyItem();
                call.Surveys[0].voice_fn = wavs;
                call.Surveys[0].dtmfs = dtmfs.Split(new string[] { "," }, StringSplitOptions.None);
                tempQueue.Enqueue(call);
            }

            myReader.Close();

            while (m_JobsQueue.Count < 2 * env.GetChannelCount() && tempQueue.Count > 0)
            {
                CallJob call = (CallJob)tempQueue.Dequeue();
                catCMD.CommandText = "DELETE FROM jobs where ID = " + call.ID.ToString();
                if (catCMD.ExecuteNonQuery() == 1)
                {
                    m_JobsQueue.Enqueue(call);
                }
                else
                {
                    //call is not in table any more
                    //doing nothing
                }
            }

            //too many jobs in tmep queue
            //just dequeue, and do nothing
            while (tempQueue.Count > 0)
            {
                CallJob call = (CallJob)tempQueue.Dequeue();
            }

        }

        public void SaveJobs()
        {
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

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

        private void addJobsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Form3 dlg = new Form3();
            dlg.m_JobID = ++m_JobID;
            dlg.MainDlg = this;
            if (dlg.ShowDialog() == DialogResult.OK)
            {
            }
        }

        public int InsertJob(CallJobInput job)
        {
            int ret = 0;
            if (IsDBConnected())
            {
                try
                {
                    SqlCommand catCMD = myConn.CreateCommand();
                    catCMD.CommandText = "INSERT INTO jobs VALUES(" + job.ID.ToString() + ", '";
                    catCMD.CommandText += job.Caller + "', '" + job.Callee + "', '";
                    catCMD.CommandText += job.DTMFs + "', '" + job.VoiceFiles + "', '";
                    catCMD.CommandText += GetSQLDateTime(job.dtDelivery) + "')";

                    if (catCMD.ExecuteNonQuery() == 1)
                    {
                        //MessageBox.Show("Succeed!");
                        m_JobID = job.ID;
                        ret = 1;

                        RegistryKey regkey;
                        regkey = Registry.CurrentUser.CreateSubKey("SOFTWARE\\PCBest.net\\BulkDialer");

                        if (regkey != null)
                        {
                            regkey.SetValue("JobID", m_JobID);
                            regkey.Close();
                        }
                    }
                    else
                    {
                        MessageBox.Show("Cannot insert data!");
                    }
                }
                catch (Exception e1)
                {
                    MessageBox.Show("Cannot insert data! Exceptions: " + e1.ToString());
                }
            }
            else
            {
                MessageBox.Show("Cannot connect to DB!");
            }

            return ret;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            addJobsToolStripMenuItem.Enabled = false;
            startToolStripMenuItem.Enabled = true;
            stopToolStripMenuItem.Enabled = false;

            RegistryKey regkey;
            regkey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\PCBest.net\\BulkDialer");

            if (regkey == null)
                return;

            Object obj = regkey.GetValue("JobID");
            if (obj != null)
                m_JobID = Convert.ToInt64(obj);

            obj = regkey.GetValue("INIFile");
            if (obj != null)
                m_sIniFile = (string)obj;

            obj = regkey.GetValue("LicKey");
            if (obj != null)
                m_sLicKey = (string)obj;

            regkey.Close();


        }

        private void timer3_Tick(object sender, EventArgs e)
        {
            if (env != null)
            {
                for (int i = 0; i < env.GetChannelCount(); i++)
                {
                    GTAPIASM.GTAPIChan chan = env.GetChannel(i);
                    if (chan != null)
                    {
                        TimeSpan tspan = DateTime.Now - chan.call_start_time;
                        switch (chan.ch_status)
                        {
                            case GTAPIASM.GTAPI_CHANNEL_STATE.CONNECTED:
                                dataGridView1.Rows[i].Cells[0].Value = chan.caller_num;
                                dataGridView1.Rows[i].Cells[1].Value = chan.callee_num;
                                dataGridView1.Rows[i].Cells[2].Value = "CONNECTED";
                                dataGridView1.Rows[i].Cells[3].Value = chan.call_start_time.ToString();
                                dataGridView1.Rows[i].Cells[4].Value = tspan.ToString();
                                break;
                            case GTAPIASM.GTAPI_CHANNEL_STATE.DIALING:
                                dataGridView1.Rows[i].Cells[0].Value = chan.caller_num;
                                dataGridView1.Rows[i].Cells[1].Value = chan.callee_num;
                                dataGridView1.Rows[i].Cells[2].Value = "DIALING";
                                dataGridView1.Rows[i].Cells[3].Value = "";
                                dataGridView1.Rows[i].Cells[4].Value = "";
                                break;
                            case GTAPIASM.GTAPI_CHANNEL_STATE.IDLE:
                                try
                                {
                                    string svalue = (string)dataGridView1.Rows[i].Cells[1].Value;
                                    if (svalue == null)
                                    {
                                        dataGridView1.Rows[i].Cells[0].Value = "";
                                        dataGridView1.Rows[i].Cells[1].Value = "";
                                        dataGridView1.Rows[i].Cells[2].Value = "IDLE";
                                        dataGridView1.Rows[i].Cells[3].Value = "";
                                        dataGridView1.Rows[i].Cells[4].Value = "";
                                    }
                                    else if (svalue.Length != 0)
                                    {
                                        dataGridView1.Rows[i].Cells[0].Value = "";
                                        dataGridView1.Rows[i].Cells[1].Value = "";
                                        dataGridView1.Rows[i].Cells[2].Value = "IDLE";
                                        dataGridView1.Rows[i].Cells[3].Value = "";
                                        dataGridView1.Rows[i].Cells[4].Value = "";
                                    }
                                }
                                catch (Exception ex)
                                {
                                }
                                break;
                        }
                    }
                }

                tbTotalChans.Text = env.GetChannelCount().ToString();
                tbActiveChans.Text = env.GetChannelCount().ToString();
            }

            tbQueueWait.Text = m_JobsQueue.Count.ToString();
            tbQueueDone.Text = m_DoneQueue.Count.ToString();

            tbTotalCalls.Text = m_totalCalls.ToString();
            tbSuccessCalls.Text = m_succCalls.ToString();
            tbFailedCalls.Text = m_failCalls.ToString();
        }

                
    }
}