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;
using ModbusLibrary;
using System.IO;

namespace ModbusControl
{
    public partial class Hlavni : Form
    {
        public Hlavni()
        {
            InitializeComponent();
        }
        ModbusClient FClient = null;
        ModbusServer FServer = null;
        Boolean[] FDiscreteInputs = null;
        Boolean[] FCoils = null;
        UInt16[] FInputRegisters = null;
        UInt16[] FHoldingRegisters = null;
        Boolean FLastCommunicationError = true;
        Boolean FCanAnswer = true;

        private void btnConnect_Click(object sender, EventArgs e)
        {
            FClient = new ModbusClient(tbIP.Text, 502);
            FClient.OnError += new EventHandler(ClientErrorEvent);
            FLastCommunicationError = false;
            FClient.ConnectClient();
            if (FLastCommunicationError == false)
            {
                btnDisconnect.Enabled = true;
                btnConnect.Enabled = false;
                tbIP.Enabled = false;
                btnRead.Enabled = true;
                btnWrite.Enabled = true;
                lblConnected.Text = "Connnected.";
            }
        }

        private void btnDisconnect_Click(object sender, EventArgs e)
        {
            FClient.DisconnectClient();
            GC.Collect();
            btnConnect.Enabled = true;
            btnDisconnect.Enabled = false;
            tbIP.Enabled = true;
            btnRead.Enabled = false;
            btnWrite.Enabled = false;
            FLastCommunicationError = true;
            lblConnected.Text = "Not connnected.";
        }

        private void btnEstablish_Click(object sender, EventArgs e)
        {
            FServer = new ModbusServer(Convert.ToUInt16(tbDiscreteInputsCount.Text), Convert.ToUInt16(tbCoilsCount.Text),
                Convert.ToUInt16(tbInputRegistersCount.Text), Convert.ToUInt16(tbHoldingRegistersCount.Text));
            FServer.OnError += new EventHandler(ServerErrorEvent);
            btnEstablish.Enabled = false;
            btnShutdown.Enabled = true;
            tbCoilsCount.Enabled = false;
            tbDiscreteInputsCount.Enabled = false;
            tbHoldingRegistersCount.Enabled = false;
            tbInputRegistersCount.Enabled = false;
            FDiscreteInputs = new Boolean[Convert.ToUInt16(tbDiscreteInputsCount.Text)];
            FCoils = new Boolean[Convert.ToUInt16(tbCoilsCount.Text)];
            FInputRegisters = new UInt16[Convert.ToUInt16(tbInputRegistersCount.Text)];
            FHoldingRegisters = new UInt16[Convert.ToUInt16(tbHoldingRegistersCount.Text)];
            UInt16 i = 0;
            for (i = 0; i < Convert.ToUInt16(tbDiscreteInputsCount.Text); i++)
                FDiscreteInputs.SetValue((Boolean)false, i);
            for (i = 0; i < Convert.ToUInt16(tbCoilsCount.Text); i++)
                FCoils.SetValue((Boolean)false, i);
            for (i = 0; i < Convert.ToUInt16(tbInputRegistersCount.Text); i++)
                FInputRegisters.SetValue((UInt16)0, i);
            for (i = 0; i < Convert.ToUInt16(tbHoldingRegistersCount.Text); i++)
                FHoldingRegisters.SetValue((UInt16)0, i);
            tcPlocha.SelectedIndex = 0;
            tcPlocha.SelectedIndex = 1;
        }

        private void btnShutdown_Click(object sender, EventArgs e)
        {
            FServer.ShutdownServer();
            GC.Collect();
            btnShutdown.Enabled = false;
            btnEstablish.Enabled = true;
            tbCoilsCount.Enabled = true;
            tbDiscreteInputsCount.Enabled = true;
            tbHoldingRegistersCount.Enabled = true;
            tbInputRegistersCount.Enabled = true;
            lbCoils.Items.Clear();
            lbDiscreteInputs.Items.Clear();
            lbInputRegisters.Items.Clear();
            lbHoldingRegisters.Items.Clear();
        }

        private void ClientErrorEvent(object sender, EventArgs e)
        {
            ModbusLibrary.ErrorEventArgs chyba = (ModbusLibrary.ErrorEventArgs)e;
            File.AppendAllText("AppErrors.log", DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString() + " : " + chyba.ErrorCode.ToString() + " - " + chyba.Message + Environment.NewLine);
            if (chyba.ErrorCode == 0)
            {
                MessageBox.Show(chyba.Message);
                //FLastCommunicationError = true;
                //FCanAnswer = false;
            }
            else
            {
                if ((chyba.ErrorCode >= (Int32)Modbus.Chyby.EC_SERVER_ERROR) && (chyba.ErrorCode <= (Int32)Modbus.Chyby.EC_SERVER_ERROR_EXECUTION))
                {
                    MessageBox.Show("Error server answer : " + Modbus.GetErrorMessage(chyba.ErrorCode));
                    FCanAnswer = false;
                }
                else
                {
                    MessageBox.Show(Modbus.GetErrorMessage(chyba.ErrorCode));
                    FLastCommunicationError = true;
                    FCanAnswer = false;
                }
            }
        }

        private void ServerErrorEvent(object sender, EventArgs e)
        {
            ModbusLibrary.ErrorEventArgs chyba = (ModbusLibrary.ErrorEventArgs)e;
            File.AppendAllText("AppErrors.log", DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString() + " : " + chyba.ErrorCode.ToString() + " - " + chyba.Message + Environment.NewLine);
        }

        private void tcPlocha_SelectedIndexChanged(object sender, EventArgs e)
        {
            UInt16 i = 0;
            if (btnEstablish.Enabled == false)
                FServer.ChangeData(ref FCoils, FDiscreteInputs, ref FHoldingRegisters, FInputRegisters);
            if ((tcPlocha.SelectedIndex == 1) && (btnEstablish.Enabled == false))
            {
                lbCoils.Items.Clear();
                for (i = 0; i < FCoils.Length; i++)
                {
                    lbCoils.Items.Add((i+1).ToString() + " : " + FCoils[i].ToString());
                }
                lbHoldingRegisters.Items.Clear();
                for (i = 0; i < FHoldingRegisters.Length; i++)
                {
                    lbHoldingRegisters.Items.Add((i+1).ToString() + " : " + FHoldingRegisters[i].ToString());
                }
                lbDiscreteInputs.Items.Clear();
                for (i = 0; i < FDiscreteInputs.Length; i++)
                {
                    lbDiscreteInputs.Items.Add((i + 1).ToString() + " : " + FDiscreteInputs[i].ToString());
                }
                lbInputRegisters.Items.Clear();
                for (i = 0; i < FInputRegisters.Length; i++)
                {
                    lbInputRegisters.Items.Add((i + 1).ToString() + " : " + FInputRegisters[i].ToString());
                }
            }
        }

        private void btnWrite_Click(object sender, EventArgs e)
        {
            if ((tbNumber.Text == "") && (tbValue.Text == ""))
            {
                MessageBox.Show("Please type number and value.");
                return;
            }
            try
            {
                Convert.ToUInt16(tbNumber.Text);
            }
            catch (Exception exc)
            {
                MessageBox.Show("Incorrect number. Please type valid number.");
                return;
            }
            if (cbFunctionWrite.SelectedIndex == 0)
            {
                if ((tbValue.Text.ToUpper() != "TRUE") && (tbValue.Text.ToUpper() != "FALSE"))
                {
                    MessageBox.Show("Incorrect value. Please type 'true' or 'false'.");
                    return;
                }
                FLastCommunicationError = false;
                FCanAnswer = true;
                FClient.WriteCoil(Convert.ToUInt16(tbNumber.Text), Convert.ToBoolean(tbValue.Text));
                if (FCanAnswer) MessageBox.Show("Writing succesful.");
            }
            if (cbFunctionWrite.SelectedIndex == 1)
            {
                try
                {
                    Convert.ToUInt16(tbValue.Text);
                }
                catch(Exception exc)
                {
                    MessageBox.Show("Incorrect value. Please type valid value 0..32756.");
                    return;
                }
                FLastCommunicationError = false;
                FCanAnswer = true;
                FClient.WriteHoldingRegister(Convert.ToUInt16(tbNumber.Text), Convert.ToUInt16(tbValue.Text));
                if (FCanAnswer) MessageBox.Show("Writing succesful.");
            }
            ShowRawMesages();
        }

        private void tm_Tick(object sender, EventArgs e)
        {
            if (FLastCommunicationError == true)
            {
                lblConnected.Text = "Not connected.";
                if (btnDisconnect.Enabled == true) btnDisconnect.PerformClick();
            }
        }

        private void btnRead_Click(object sender, EventArgs e)
        {
            UInt16 i = 0;
            try
            {
                Convert.ToUInt16(tbFrom.Text);
                if (tbCount.Enabled == true) Convert.ToUInt16(tbCount.Text);
            }
            catch (Exception exc)
            {
                MessageBox.Show("Incorrect or missing values in fields From(Number) and Count.");
                return;
            }
            FLastCommunicationError = false;
            FCanAnswer = true;
            if (cbFunctionRead.SelectedIndex == 0)
            {
                Boolean tmp = false;
                FClient.ReadCoil(Convert.ToUInt16(tbFrom.Text), ref tmp);
                if (FCanAnswer == true) MessageBox.Show("Coil " + tbFrom.Text + " is " + tmp.ToString());

            }
            if (cbFunctionRead.SelectedIndex == 1)
            {
                UInt16 tmp = 0;
                FClient.ReadHoldingRegister(Convert.ToUInt16(tbFrom.Text), ref tmp);
                if (FCanAnswer == true) MessageBox.Show("Holding register " + tbFrom.Text + " is " + tmp.ToString());
            }
            if (cbFunctionRead.SelectedIndex == 2)
            {
                Boolean[] tmp = new Boolean[Convert.ToUInt16(tbCount.Text)];
                for (i = 0; i < tmp.Length; i++)
                    tmp.SetValue((Boolean)false, i);
                FClient.ReadDiscreteInputs(Convert.ToUInt16(tbFrom.Text), Convert.ToUInt16(tbCount.Text), ref tmp);
                if (FCanAnswer == true)
                {
                    StringBuilder str = new StringBuilder();
                    for (i = 0; i < tmp.Length; i++)
                        str.AppendLine("Discrete input " + (i + Convert.ToUInt16(tbFrom.Text)).ToString() + " is " + ((Boolean)tmp.GetValue(i)).ToString());
                    MessageBox.Show(str.ToString());
                }
            }
            if (cbFunctionRead.SelectedIndex == 3)
            {
                UInt16[] tmp = new UInt16[Convert.ToUInt16(tbCount.Text)];
                for (i = 0; i < tmp.Length; i++)
                    tmp.SetValue((UInt16)0, i);
                FClient.ReadInputRegisters(Convert.ToUInt16(tbFrom.Text), Convert.ToUInt16(tbCount.Text), ref tmp);
                if (FCanAnswer == true)
                {
                    StringBuilder str = new StringBuilder();
                    for (i = 0; i < tmp.Length; i++)
                        str.AppendLine("Input register " + (i + Convert.ToUInt16(tbFrom.Text)).ToString() + " is " + ((UInt16)tmp.GetValue(i)).ToString());
                    MessageBox.Show(str.ToString());
                }
            }
            if (cbFunctionRead.SelectedIndex == 4)
            {
                Boolean[] tmp = new Boolean[Convert.ToUInt16(tbCount.Text)];
                for (i = 0; i < tmp.Length; i++)
                    tmp.SetValue((Boolean)false, i);
                FClient.ReadCoils(Convert.ToUInt16(tbFrom.Text), Convert.ToUInt16(tbCount.Text), ref tmp);
                if (FCanAnswer == true)
                {
                    StringBuilder str = new StringBuilder();
                    for (i = 0; i < tmp.Length; i++)
                        str.AppendLine("Coil " + (i + Convert.ToUInt16(tbFrom.Text)).ToString() + " is " + ((Boolean)tmp.GetValue(i)).ToString());
                    MessageBox.Show(str.ToString());
                }
            }
            if (cbFunctionRead.SelectedIndex == 5)
            {
                UInt16[] tmp = new UInt16[Convert.ToUInt16(tbCount.Text)];
                for (i = 0; i < tmp.Length; i++)
                    tmp.SetValue((UInt16)0, i);
                FClient.ReadHoldingRegisters(Convert.ToUInt16(tbFrom.Text), Convert.ToUInt16(tbCount.Text), ref tmp);
                if (FCanAnswer == true)
                {
                    StringBuilder str = new StringBuilder();
                    for (i = 0; i < tmp.Length; i++)
                        str.AppendLine("Holding register " + (i + Convert.ToUInt16(tbFrom.Text)).ToString() + " is " + ((UInt16)tmp.GetValue(i)).ToString());
                    MessageBox.Show(str.ToString());
                }
            }
            ShowRawMesages();
        }

        private void ShowRawMesages()
        {
            String SendMessage = "";
            String ReadMessage = "";
            FClient.GetRWBuffer(out SendMessage, out ReadMessage);
            tbAnswer.Text = ReadMessage;
            tbSending.Text = SendMessage;
        }

        private void cbFunctionRead_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbFunctionRead.SelectedIndex <= 1)
            {
                lblFrom.Text = "Number :";
                tbCount.Enabled = false;
            }
            else
            {
                lblFrom.Text = "From :";
                tbCount.Enabled = true;
            }

        }

        private void lbDiscreteInputs_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (lbDiscreteInputs.SelectedIndex == -1) return;
            EditDialog frmEditDialog = new EditDialog();
            frmEditDialog.Mode = 0;
            frmEditDialog.Location =new Point(e.X + this.Location.X + lbDiscreteInputs.Location.X + 12, e.Y + this.Location.Y+lbDiscreteInputs.Location.Y + 50);
            if (frmEditDialog.ShowDialog(this) == DialogResult.OK)
            {
                FDiscreteInputs.SetValue((Boolean)frmEditDialog.BooleanValue, lbDiscreteInputs.SelectedIndex);
                lbDiscreteInputs.Items[lbDiscreteInputs.SelectedIndex] = (lbDiscreteInputs.SelectedIndex + 1).ToString() + " : " + ((Boolean)FDiscreteInputs.GetValue(lbDiscreteInputs.SelectedIndex)).ToString();
                 
            }
            frmEditDialog.Dispose();
        }

        private void lbInputRegisters_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (lbInputRegisters.SelectedIndex == -1) return;
            EditDialog frmEditDialog = new EditDialog();
            frmEditDialog.Mode = 1;
            frmEditDialog.Location = new Point(e.X + this.Location.X + lbInputRegisters.Location.X + 12, e.Y + this.Location.Y + lbInputRegisters.Location.Y + 50);
            if (frmEditDialog.ShowDialog(this) == DialogResult.OK)
            {
                lbInputRegisters.Items[lbInputRegisters.SelectedIndex] = (lbInputRegisters.SelectedIndex + 1).ToString() + " : " + frmEditDialog.UInt16Value.ToString();
                FInputRegisters.SetValue((UInt16)frmEditDialog.UInt16Value, lbInputRegisters.SelectedIndex);
            }
            frmEditDialog.Dispose();
        }

    }
}
