using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SATO.MLComponent;

namespace SampleCode
{
    public partial class SampleForm : Form
    {
        private MLComponent MLComponent;        
        bool Minimized = false;
        bool isBTManual = false;

        object BTarrayVar;
        public SampleForm(string action)
        {
            InitializeComponent();
            MLComponent = new MLComponent();
            cbInterfaces.SelectedIndex = 0;
            cbProtocol.SelectedIndex = 0; //Default to Status3
            btnDisconnect.Enabled = false;

            if (action.ToLower() == "minimized")
                Minimized = true;
        }

        private void SampleForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            MLComponent.ClosePort();
        }

        private void SampleForm_Load(object sender, EventArgs e)
        {
            this.Text = "Sample Form for "+MLComponent.Version;

        }

        private void SampleForm_Resize(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {

            }
        }

        private void SampleForm_Shown(object sender, EventArgs e)
        {
            if (Minimized)
                WindowState = FormWindowState.Minimized;
        }

        private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Show();
            this.WindowState = FormWindowState.Normal;
            notifyIcon.Visible = false;
        }

        private static Dictionary<string, char> ControlCharList()
        {
            Dictionary<string, char> ctr = new Dictionary<string, char>();
            ctr.Add("[NUL]", '\u0000');
            ctr.Add("[SOH]", '\u0001');
            ctr.Add("[STX]", '\u0002');
            ctr.Add("[ETX]", '\u0003');
            ctr.Add("[EOT]", '\u0004');
            ctr.Add("[ENQ]", '\u0005');
            ctr.Add("[ACK]", '\u0006');
            ctr.Add("[BEL]", '\u0007');
            ctr.Add("[BS]", '\u0008');
            ctr.Add("[HT]", '\u0009');
            ctr.Add("[LF]", '\u000A');
            ctr.Add("[VT]", '\u000B');
            ctr.Add("[FF]", '\u000C');
            ctr.Add("[CR]", '\u000D');
            ctr.Add("[SO]", '\u000E');
            ctr.Add("[SI]", '\u000F');
            ctr.Add("[DLE]", '\u0010');
            ctr.Add("[DC1]", '\u0011');
            ctr.Add("[DC2]", '\u0012');
            ctr.Add("[DC3]", '\u0013');
            ctr.Add("[DC4]", '\u0014');
            ctr.Add("[NAK]", '\u0015');
            ctr.Add("[SYN]", '\u0016');
            ctr.Add("[ETB]", '\u0017');
            ctr.Add("[CAN]", '\u0018');
            ctr.Add("[EM]", '\u0019');
            ctr.Add("[SUB]", '\u001A');
            ctr.Add("[ESC]", '\u001B');
            ctr.Add("[FS]", '\u001C');
            ctr.Add("[GS]", '\u001D');
            ctr.Add("[RS]", '\u001E');
            ctr.Add("[US]", '\u001F');
            ctr.Add("[DEL]", '\u007F');
            return ctr;
        }

        private string ControlCharConvert(string data)
        {
            Dictionary<char, string> chrList = ControlCharList().ToDictionary(x => x.Value, x => x.Key);
            foreach (char key in chrList.Keys)
            {
                data = data.Replace(key.ToString(), chrList[key]);
            }
            return data;
        }

        private string ControlCharReplace(string data)
        {
            Dictionary<string, char> chrList = ControlCharList();
            foreach (string key in chrList.Keys)
            {
                data = data.Replace(key, chrList[key].ToString());
            }
            return data;
        }

        private void btnClearSend_Click(object sender, EventArgs e)
        {
            txtSend.Text = "";
            rtxtRecv.Text = "";
            txtTotalRecvBytes.Text = "0";
            txtSend.Focus();
        }

        
        private void btnSend_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(txtSend.Text)) return;

            MouseWait = true;
            try
            {
                byte[] cmddata = Encoding.Default.GetBytes(ControlCharReplace(txtSend.Text));

                if (cbInterfaces.SelectedIndex > -1)
                {
                    try
                    {
                        int Result;
                        if (cbInterfaces.SelectedIndex == 4) //Driver: command only able to run after closeport
                        {
                            MLComponent.SendRawData(1, ref cmddata, 0, "");
                            Result = MLComponent.ClosePort();//Close the driver port after sending command
                            if (Result != 0)
                            {
                                MessageBox.Show("Disconnect error no:" + Result.ToString(), "Disconnect Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                MouseWait = false;
                                return;                                
                            }
                            else
                            {
                                btnConnect.Enabled = true;
                                btnDisconnect.Enabled = false;
                                //If close port success, open port again to continue sending command
                                Result = MLComponent.OpenPort(1);
                                if (Result != 0)
                                {
                                    MessageBox.Show("Connect error no:" + Result.ToString(), "Connect Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                    MouseWait = false;
                                    return;
                                }
                                else
                                {
                                    btnConnect.Enabled = false;
                                    btnDisconnect.Enabled = true;
                                }
                            }
                        }
                        else
                        {
                            MLComponent.SendRawData(1, ref cmddata, 0, "");
                        }                        
                    }
                    catch (MLComponentException ex)
                    {
                        MessageBox.Show("SendRawDataError No." + ex.Number.ToString() + ": " + ex.Message);
                        MouseWait = false;
                        return;
                    }                                     
                }
                else
                {
                    MessageBox.Show("Please select an interface from drop down list");

                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            MouseWait = false;            
        }
        
        
        private void btnLoadFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog1 = new OpenFileDialog();

            openFileDialog1.RestoreDirectory = false;
            openFileDialog1.Filter = "Command file (*.txt,*.prn)|*.txt;*.prn|All files (*.*)|*.*";
            openFileDialog1.FilterIndex = 0;

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    if (System.IO.File.Exists(openFileDialog1.FileName))
                    {
                        byte[] cmddata = System.IO.File.ReadAllBytes(openFileDialog1.FileName);
                        MouseWait = true;
                        try
                        {
                            string str = Encoding.Default.GetString(cmddata);
                            txtSend.Text = ControlCharConvert(str);
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message);
                        }
                        MouseWait = false;
                    }
                    else
                    {
                        MessageBox.Show("Error: file not found.");
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error: " + ex.Message);
                }
            }           
        }
        

        private void btnQuery_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(txtSend.Text)) return;

            MouseWait = true;
            try
            {
                object Result = null;
                rtxtRecv.Text = "";
                txtTotalRecvBytes.Text = "0";
                byte[] cmddata = Encoding.Default.GetBytes(ControlCharReplace(txtSend.Text));
                string endChar = ((char)0x03).ToString();

                try
                {
                    Result = MLComponent.SendRawData(1, ref cmddata, 0, endChar); //Fix to return result in bytearray
                }
                catch (MLComponentException ex)
                {
                    MessageBox.Show("SendRawDataError No." + ex.Number.ToString()+": "+ ex.Message);
                    MouseWait = false;
                    return;
                }

                if (Result != null)
                {
                    MessageBox.Show("SendRawData Success");
                    if (Result is string)
                    {
                        string RecvData = Convert.ToString(Result);
                        MessageBox.Show("Result = " + RecvData);
                    }
                    else if (Result is byte[])
                    {
                        byte[] RecvByte = (byte[])(Result);
                        AppendRecvText(RecvByte, true);
                    }
                }
                else
                {
                    MessageBox.Show("SendRawData failed.");
                    MouseWait = false;
                    return;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            MouseWait = false;
        }
        
        private void btnExport_Click(object sender, EventArgs e)
        {
            string contents = ControlCharReplace(rtxtRecv.Text);
            if (!string.IsNullOrEmpty(contents))
            {
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.RestoreDirectory = false;
                saveFileDialog.Title = "Browse Files";
                saveFileDialog.Filter = "Command file (*.prn)|*.prn|All files (*.*)|*.*";
                saveFileDialog.CheckFileExists = false;
                saveFileDialog.CheckPathExists = true;
                saveFileDialog.FilterIndex = 0;

                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                {
                    System.IO.File.WriteAllText(saveFileDialog.FileName, contents.Substring(0, contents.Length -2));
                }
            }
            else
            {
                MessageBox.Show(this, "No data to be saved");
            }
        }

        private void cbInterfaces_SelectedIndexChanged(object sender, EventArgs e)
        {
            btnQuery.Enabled = true;
            groupBox2.Enabled = true;
            cbProtocol.Enabled = true;
            btnGetStatus.Show();
            cbProtocol.Items.Clear();
            cbBluetooth.Items.Clear();

            switch (cbInterfaces.SelectedIndex)
            {
                case 0:
                    panelSocket.Show();
                    panelSocket.BringToFront();
                    panelUSB.Hide();
                    pnlDriver.Hide();
                    panelBluetooth.Hide();
                    txtTimeout.Enabled = true;                    
                    cbProtocol.Items.Add("Status3");
                    cbProtocol.Items.Add("Status4");
                    txtIP.Clear();
                    break;
                case 1:
                    panelUSB.Show();
                    panelUSB.BringToFront();
                    panelSocket.Hide();
                    pnlDriver.Hide();
                    panelBluetooth.Hide();
                    txtTimeout.Enabled = true;
                    cbProtocol.Items.Add("Status3");
                    cbProtocol.Items.Add("Status4");
                    break;
                case 2:
                    panelUSB.Hide();
                    panelSocket.Hide();
                    pnlDriver.Hide();
                    panelBluetooth.Show();
                    panelBluetooth.BringToFront();                    
                    lblPIN.Hide();
                    txtPIN.Hide();
                    btnPair.Hide();
                    txtTimeout.Enabled = true;
                    cbProtocol.Items.Add("Status3");
                    cbProtocol.Items.Add("Status4");
                    break;                   
                case 3:
                    panelUSB.Hide();
                    panelSocket.Hide();
                    pnlDriver.Hide();
                    panelBluetooth.Hide();
                    txtTimeout.Enabled = true;
                    cbProtocol.Items.Add("Status4");
                    break;
                case 4:
                    panelUSB.Hide();
                    panelSocket.Hide();
                    pnlDriver.Show();
                    panelBluetooth.Hide();
                    btnGetStatus.Hide();
                    pnlDriver.BringToFront();
                    btnQuery.Enabled = false;
                    groupBox2.Enabled = false;
                    txtTimeout.Enabled = false;
                    cbProtocol.Enabled = false;
                    break;
            }

            if (cbProtocol.Items.Count > 0)
            {
                cbProtocol.SelectedIndex = 0;
            }
        }

        private void txtSend_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter && chkAutoSend.Checked)
            {
                e.SuppressKeyPress = true; //To remove ending \n due to enter key
                btnSend.PerformClick();
                System.Threading.Thread.Sleep(500);
                btnClear.PerformClick();
            }
        }

        private bool MouseWait
        {
            set
            {
                if (value)
                    Cursor = Cursors.WaitCursor;
                else
                    Cursor = Cursors.Default; 
            }
        }
        private void SetInterface()
        {
            try
            {
                MLComponent.Timeout = Int32.Parse(txtTimeout.Text);
                if (MLComponent.Timeout <= 5)
                    MLComponent.Timeout = 5;

                switch (cbInterfaces.SelectedIndex)
                {
                    case 0: //Socket LAN
                        MLComponent.Setting = "LAN:" + txtIP.Text + "," + txtPort.Text;
                        break;
                    case 1: //COM
                        MLComponent.Setting = txtComPort.Text + ":" + txtBaudRate.Text + "," + txtComParam.Text;
                        break;
                    case 2: //Bluetooth
                        if (isBTManual)
                        {
                            MLComponent.Setting = "BT:" + txtBluetooth.Text;
                        }
                        else
                        {
                            MLComponent.Setting = "BT:" + cbBluetooth.Text;
                        }
                        break;
                    case 3: //USB
                        MLComponent.Setting = "USB:";
                        break;
                    case 4: //Driver
                        MLComponent.Setting = "DRV:" + txtDriver.Text;
                        break;
                    default:
                        MessageBox.Show("Error : Invalid Interface Selection!");
                        break;
                }

                if (cbInterfaces.SelectedIndex == 4) return; //Driver: protocol setting not applicable

                switch (cbProtocol.SelectedItem.ToString())
                {
                    case "Status3": 
                        MLComponent.Protocol = Protocols.Status3;
                        break;
                    case "Status4":
                        MLComponent.Protocol = Protocols.Status4;
                        break;
                    default:
                        MLComponent.Protocol = Protocols.Status3;
                        cbProtocol.SelectedIndex = 0; //Default to Status3
                        break;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void AppendRecvText(byte[] data, bool empty)
        {
            if (InvokeRequired)
            {
                this.Invoke(new Action<byte[],bool>(AppendRecvText), new object[] { data,empty });
                return;
            }
            if (empty)
                rtxtRecv.Text = "";

            rtxtRecv.WordWrap = true;

            string smsg = ControlCharConvert(Encoding.Default.GetString(data));
            
            rtxtRecv.AppendText(smsg + Environment.NewLine);
            txtTotalRecvBytes.Text = data.Length.ToString();
        }       
        private void txtTimeout_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar))
            {
                e.Handled = true;
            }
        }
        private void btnConnect_Click(object sender, EventArgs e)
        {
            //
            try
            {
                SetInterface();
                int Result = MLComponent.OpenPort(1);
                if (Result != 0)
                {
                    MessageBox.Show("Connect error no:" + Result.ToString(), "Connect Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    MessageBox.Show("Connect Success", "Connect", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    btnConnect.Enabled = false;
                    btnDisconnect.Enabled = true;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message);
            }
            
        }
        private void btnDisconnect_Click(object sender, EventArgs e)
        {
            try
            {
                int Result = 0;

                Result = MLComponent.ClosePort();

                if (Result != 0)
                {
                    MessageBox.Show("ClosePort failed.", "Disconnect Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    MessageBox.Show("Disconnect Success", "Disconnect", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    btnConnect.Enabled = true;
                    btnDisconnect.Enabled = false;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message);
            }
            
        }
        private void btnGetStatus_Click(object sender, EventArgs e)
        {
            string Status = "";

            try
            {
                int Result = MLComponent.GetStatus(ref Status);

                if (Result != 0)
                {

                    MessageBox.Show("GetStatus failed.Error Code:" + Result);
                }
                else
                {
                    MessageBox.Show("PrinterStatus = " + Status.Substring(2, 1));
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message);
            }
        }
        private void btnSearch_Click(object sender, EventArgs e)
        {           
            isBTManual = false;
            BTInterfaceControl();
                        
            BTarrayVar = null;
            MouseWait = true;

            int SearchTime = 3;

            try
            {
                BTarrayVar = MLComponent.EnumerateBluetoothDevices(SearchTime);
            }
            catch (MLComponentException ex)
            {
                MessageBox.Show("EnumerateBluetoothDevices Error No." + ex.Number.ToString() + ": " + ex.Message);
                MouseWait = false;
                return;
            }

            object[,] DevArray = ((object[,])(BTarrayVar));
            for (int n = DevArray.GetLowerBound(0); (n <= DevArray.GetUpperBound(0)); n++)
            {
                string address = ((string)(DevArray[n, 0]));
                string name = ((string)(DevArray[n, 1]));
                string isauth = ((string)(DevArray[n, 2]));
                cbBluetooth.Items.Add(address);
            }
            MouseWait = false;
        }

        private void btnPair_Click(object sender, EventArgs e)
        {
            int Result;
            string Address;
            if (isBTManual)
            {
                Address = txtBluetooth.Text;
            }
            else
            {
                Address = cbBluetooth.Text;
            }
            
            string PIN = txtPIN.Text;
            int SearchTime = 3;

            Result = MLComponent.AuthenticateBluetoothDevice(Address, PIN, SearchTime);
            if ((Result != 0))
            {
                MessageBox.Show("Bluetooth pairing failed.", "Bluetooth Pairing", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else
            {
                MessageBox.Show("Bluetooth pairing success.", "Bluetooth Pairing", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void cbBluetooth_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (BTarrayVar == null || (BTarrayVar as object[,]).Length == 0) return;

            object[,] DevArray = BTarrayVar as object[,];
            if (DevArray[cbBluetooth.SelectedIndex, 2].ToString() == "False")//Not paired before; Show PIN to proceed with pair process
            {
                lblPIN.Show();
                txtPIN.Show();
                btnPair.Show();
            }
            else
            {
                lblPIN.Hide();
                txtPIN.Hide();
                btnPair.Hide();
            }
        }

        private void BTInterfaceControl()
        {
            if(isBTManual)
            {
                txtBluetooth.Visible = true;
                lblPIN.Visible = true;
                txtPIN.Visible = true;
                btnPair.Visible = true;
                cbBluetooth.Visible = false;
                txtBluetooth.Clear();
            }
            else
            {
                txtBluetooth.Visible = false;
                cbBluetooth.Visible = true;                
                lblPIN.Visible = false;
                txtPIN.Visible = false;
                btnPair.Visible = false;
                cbBluetooth.Items.Clear();
            }
        }

        private void btnManual_Click(object sender, EventArgs e)
        {
            isBTManual = true;
            BTInterfaceControl();
        }
    }
}
