using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Ebel.Hardware.Communications;

namespace HwComWrapperNETGui.UserControls
{
    public partial class MsgCat83 : UserControl
    {
        #region Fields

        private readonly RbsChannelAppTypeList rbsChannelAppType = new RbsChannelAppTypeList();

        #endregion

        #region Construction

        public MsgCat83()
        {
            InitializeComponent();

            toolTip1.SetToolTip(numericUpDownSetValue, "The decimal value to write");
            toolTip2.SetToolTip(numericUpDownLengthByteGet, "The amount of bytes to read");
            toolTip2.SetToolTip(numericUpDownLengthByteSet, "The amount of bytes to write");

            button01.Click += (sender, args) => HandleButtonClick(ButtonGetRBSStatusClicked);
            buttonECUOn.Click += OnButtonECUOnClicked; // This button is a stub for message code 03 and 04
            buttonECUOff.Click += OnButtonECUOffClicked;
            buttonECUShutdown.Click += OnButtonECUShutdownClicked;
            button05.Click += (sender, args) => HandleButtonClick(ButtonGetRBSTimestampClicked);
            button06.Click += (sender, args) => HandleButtonClick(ButtonGetVersionStringClicked);
            btnGetRBSVersion.Click += (sender, args) => HandleButtonClick(ButtonGetRBSVersionClicked);
            button07.Click += (sender, args) => HandleButtonClick(ButtonGetRBSManipulationActiveClicked);
            button08.Click += (sender, args) => HandleButtonClick(ButtonStartRBSManipulationClicked);
            button09.Click += (sender, args) => HandleButtonClick(ButtonStartRBSManipulationCyclicClicked);
            button0A.Click += (sender, args) => HandleButtonClick(ButtonStopRBSManipulationClicked);
            button0B.Click += (sender, args) => HandleButtonClick(ButtonSaveRBSManipulationClicked);
            button0C.Click += (sender, args) => HandleButtonClick(ButtonDeleteRBSManipulationClicked);
            button0D.Click += OnButtonSetValueClicked;
            button0DByteStream.Click += OnButtonSetValueByteStreamClicked;
            button0E.Click += OnButtonGetValueClicked;
            button0F.Click += (sender, args) => HandleButtonClick(ButtonGetRBSChannelsInfoClicked);
            btnGetFrOssetCtrlStates.Click += (sender, args) => HandleButtonClick(ButtonGetFrOffsetCtrlStatesClicked);
            buttonGetActiveManipulations.Click +=
                (sender, args) => HandleButtonClick(ButtonGetActiveManipulationsClicked);
            buttonGetManipulationStatus.Click +=
                (sender, args) => HandleButtonClick(ButtonGetManipulationStatusClicked);
            buttonStartRbsManipulation64.Click +=
                (sender, args) => HandleButtonClick(ButtonStartRbsManipulation64Clicked);
            buttonStartRbsManipulationCyclic64.Click += (sender, args) =>
                HandleButtonClick(ButtonStartRbsManipulationCyclic64Clicked);
            buttonStopRbsManipulation64.Click +=
                (sender, args) => HandleButtonClick(ButtonStopRbsManipulation64Clicked);
            buttonGetManipulationStatus64.Click +=
                (sender, args) => HandleButtonClick(ButtonGetManipulationStatus64Clicked);
            buttonGetActiveManipulations64.Click +=
                (sender, args) => HandleButtonClick(ButtonGetActiveManipulations64Clicked);
            buttonAddManipulation64.Click +=
                (sender, args) => HandleButtonClick(ButtonAddRbsManipulation64Clicked);
            buttonRemoveManipulation64.Click +=
                (sender, args) => HandleButtonClick(ButtonRemoveRbsManipulation64Clicked);
            var dictTransportProtocol = new Dictionary<string, string>();
            dictTransportProtocol.Add("2", "UDP");
            dictTransportProtocol.Add("1", "TCP");
            comboBoxServiceProtocol.DataSource = new BindingSource(dictTransportProtocol, null);
        }

        #endregion

        #region Events

        /// <summary>
        ///     Occurs when the button for COM_RbsManipulationDeleteReq was clicked.
        /// </summary>
        public event EventHandler ButtonDeleteRBSManipulationClicked;

        /// <summary>
        ///     Occurs when the button for COM_GetRbsManipulationActiveReq was clicked.
        /// </summary>
        public event EventHandler ButtonGetRBSManipulationActiveClicked;

        /// <summary>
        ///     Occurs when the button for COM_RbsStatusReq was clicked.
        /// </summary>
        public event EventHandler ButtonGetRBSStatusClicked;

        /// <summary>
        ///     Occurs when the button for COM_TimestampReq was clicked.
        /// </summary>
        public event EventHandler ButtonGetRBSTimestampClicked;

        /// <summary>
        ///     Occurs when the button for COM_GetRBSVersionReq was clicked.
        /// </summary>
        public event EventHandler ButtonGetRBSVersionClicked;

        /// <summary>
        ///     Occurs when the button for COM_VersionStringReq was clicked.
        /// </summary>
        public event EventHandler ButtonGetVersionStringClicked;

        /// <summary>
        ///     Occurs when the button for COM_GetRBSChannelsInfoReq was clicked.
        /// </summary>
        public event EventHandler ButtonGetRBSChannelsInfoClicked;

        /// <summary>
        ///     Occurs when the button for COM_GetValueReq was clicked.
        /// </summary>
        public event EventHandler<GetValueEventArgs> ButtonGetValueClicked;

        /// <summary>
        ///     Occurs when the button for COM_RbsManipulationSaveReq was clicked.
        /// </summary>
        public event EventHandler ButtonSaveRBSManipulationClicked;

        /// <summary>
        ///     Occurs when the button for COM_SetValueReq was clicked.
        /// </summary>
        public event EventHandler<SetValueEventArgs> ButtonSetValueClicked;

        /// <summary>
        ///     Occurs when the button for COM_StartRbsManipulationReq was clicked.
        /// </summary>
        public event EventHandler ButtonStartRBSManipulationClicked;

        /// <summary>
        ///     Occurs when the button for COM_StartRbsManipulationCyclicReq was clicked.
        /// </summary>
        public event EventHandler ButtonStartRBSManipulationCyclicClicked;

        /// <summary>
        ///     Occurs when the button for COM_StopRbsManipulationReq was clicked.
        /// </summary>
        public event EventHandler ButtonStopRBSManipulationClicked;

        /// <summary>
        ///     Occurs when the button for COM_RbsECUControlReq/COM_RbsECUFullControlReq was clicked.
        /// </summary>
        public event EventHandler<ECUControlEventArgs> ButtonECUControlClicked;

        /// <summary>
        ///     Occurs when the button for COM_GetFrOffsetControlStates was clicked.
        /// </summary>
        public event EventHandler ButtonGetFrOffsetCtrlStatesClicked;

        /// <summary>
        ///     Occurs when the button for COM_RbsECUShutdownReq was clicked.
        /// </summary>
        public event EventHandler<ECUShutdownEventArgs> ButtonECUShutdownClicked;

        /// <summary>
        ///     Occurs when the button for COM_RbsServiceControlReq was clicked.
        /// </summary>
        public event EventHandler<ServiceControlEventArgs> ButtonServiceControlClicked;

        /// <summary>
        ///     Occurs when the button for COM_RbsServiceStateReq was clicked.
        /// </summary>
        public event EventHandler<ServiceControlEventArgs> ButtonServiceGetStateClicked;

        /// <summary>
        ///     Occurs when the button for COM_ChangeRBSApplicationTypeReq was clicked.
        /// </summary>
        public event EventHandler<RbsChannelAppTypeListEventArgs> ButtonChangeRbsApplicationType;

        /// <summary>
        ///     Occurs when the button for COM_GetRbsActiveManipulationsReq was clicked.
        /// </summary>
        public event EventHandler ButtonGetActiveManipulationsClicked;

        /// <summary>
        ///     Occurs when the button for COM_GetRbsManipulationStatusReq was clicked.
        /// </summary>
        public event EventHandler ButtonGetManipulationStatus64Clicked;

        /// <summary>
        ///     Occurs when the button for COM_StartRbsManipulationReq was clicked.
        /// </summary>
        public event EventHandler ButtonStartRbsManipulation64Clicked;

        /// <summary>
        ///     Occurs when the button for COM_StartRbsManipulationCyclicReq was clicked.
        /// </summary>
        public event EventHandler ButtonStartRbsManipulationCyclic64Clicked;

        /// <summary>
        ///     Occurs when the button for COM_StopRbsManipulationReq was clicked.
        /// </summary>
        public event EventHandler ButtonStopRbsManipulation64Clicked;

        /// <summary>
        ///     Occurs when the button for COM_GetRbsActiveManipulationsReq was clicked.
        /// </summary>
        public event EventHandler ButtonGetActiveManipulations64Clicked;

        /// <summary>
        ///     Occurs when the button for COM_GetRbsManipulationStatusReq was clicked.
        /// </summary>
        public event EventHandler ButtonGetManipulationStatusClicked;

        /// <summary>
        ///     Occurs when the button for COM_AddRbsManipulation64Req was clicked.
        /// </summary>
        public event EventHandler ButtonAddRbsManipulation64Clicked;

        /// <summary>
        ///     Occurs when the button for COM_RemoveRbsManipulation64Req was clicked.
        /// </summary>
        public event EventHandler ButtonRemoveRbsManipulation64Clicked;

        #endregion

        #region Public Properties

        public List<ulong> ManipulationUIDs
        {
            get
            {
                var activeUids = new List<ulong>();
                var checkedItems = this.listBoxManipulationUIDs.CheckedItems;
                if (checkedItems != null)
                {
                    foreach (var item in checkedItems)
                    {
                        if (item is ulong uid)
                        {
                            activeUids.Add(uid);
                        }
                    }
                }

                return activeUids;
            }
        }

        #endregion

        #region Public Methods

        public uint GetManipulationTarget()
        {
            return (uint)numericUpDownManipulationTarget.Value;
        }

        public byte GetManipulationSequenceNumber()
        {
            return (byte)numericUpDownManipulationSequenceNumber.Value;
        }

        #endregion

        #region Private Methods

        private void HandleButtonClick(EventHandler handler)
        {
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }

        private void OnButtonGetValueClicked(object sender, EventArgs eventArgs)
        {
            var handler = ButtonGetValueClicked;
            if (handler == null)
            {
                return;
            }

            var destination = Convert.ToUInt64(numericUpDownGetValueDestination.Value);
            var length = Convert.ToUInt16(numericUpDownLengthByteGet.Text);
            handler(this, new GetValueEventArgs(destination, length));
        }

        private void OnButtonSetValueClicked(object sender, EventArgs eventArgs)
        {
            var handler = ButtonSetValueClicked;
            if (handler == null)
            {
                return;
            }

            var byteLength = Convert.ToInt32(numericUpDownLengthByteSet.Value);
            byte[] value = null;
            if (byteLength > 0)
            {
                value = numericUpDownSetValue.Value.GetByteArray(byteLength);
                if (value == null)
                {
                    return;
                }
            }

            var destination = Convert.ToUInt64(numericUpDownSetValueDestination.Value);
            handler(this, new SetValueEventArgs(destination, value));
        }

        private void OnButtonSetValueByteStreamClicked(object sender, EventArgs eventArgs)
        {
            var handler = ButtonSetValueClicked;
            if (handler == null)
            {
                return;
            }

            var value = richTextBoxSetValue.Text.GetByteArray();
            var destination = Convert.ToUInt64(numericUpDownSetValueDestination.Value);
            handler(this, new SetValueEventArgs(destination, value));
        }

        private void OnButtonECUOnClicked(object sender, EventArgs e)
        {
            var handler = ButtonECUControlClicked;
            if (handler == null)
            {
                return;
            }

            handler(
                this,
                new ECUControlEventArgs(Convert.ToByte(numericUpDownECUId.Value), checkBoxFullControl.Checked, true));
        }

        private void OnButtonECUOffClicked(object sender, EventArgs e)
        {
            var handler = ButtonECUControlClicked;
            if (handler == null)
            {
                return;
            }

            handler(
                this,
                new ECUControlEventArgs(Convert.ToByte(numericUpDownECUId.Value), checkBoxFullControl.Checked, false));
        }

        private void OnButtonECUShutdownClicked(object sender, EventArgs e)
        {
            var handler = ButtonECUShutdownClicked;
            if (handler == null)
            {
                return;
            }

            handler(this, new ECUShutdownEventArgs(Convert.ToByte(numericUpDownECUId.Value)));
        }

        private void OnButtonServiceOnClicked(object sender, EventArgs e)
        {
            var handler = ButtonServiceControlClicked;
            if (handler == null)
            {
                return;
            }

            var serviceControlServiceOn = new RBSServiceControl();

            serviceControlServiceOn.Channel = (byte)numericUpDownServiceChannel.Value;
            serviceControlServiceOn.Protocol =
                Convert.ToByte(((KeyValuePair<string, string>)comboBoxServiceProtocol.SelectedItem).Key);
            serviceControlServiceOn.VLAN = (ushort)numericUpDownServiceVlan.Value;
            serviceControlServiceOn.ServiceID = (ushort)numericUpDownServiceId.Value;
            serviceControlServiceOn.InstanceID = (ushort)numericUpDownInstanceId.Value;
            serviceControlServiceOn.MajorVersion = (byte)numericUpDownMajorNr.Value;
            serviceControlServiceOn.MinorVersion = (uint)numericUpDownMinorNr.Value;

            handler(this, new ServiceControlEventArgs(serviceControlServiceOn, true));
        }

        private void OnButtonServiceOffClicked(object sender, EventArgs e)
        {
            var handler = ButtonServiceControlClicked;
            if (handler == null)
            {
                return;
            }

            var serviceControlServiceOff = new RBSServiceControl();

            serviceControlServiceOff.Channel = (byte)numericUpDownServiceChannel.Value;
            serviceControlServiceOff.Protocol =
                Convert.ToByte(((KeyValuePair<string, string>)comboBoxServiceProtocol.SelectedItem).Key);
            serviceControlServiceOff.VLAN = (ushort)numericUpDownServiceVlan.Value;
            serviceControlServiceOff.ServiceID = (ushort)numericUpDownServiceId.Value;
            serviceControlServiceOff.InstanceID = (ushort)numericUpDownInstanceId.Value;
            serviceControlServiceOff.MajorVersion = (byte)numericUpDownMajorNr.Value;
            serviceControlServiceOff.MinorVersion = (uint)numericUpDownMinorNr.Value;

            handler(this, new ServiceControlEventArgs(serviceControlServiceOff, false));
        }

        private void OnButtonChangeRbsApplicationTypeClicked(object sender, EventArgs e)
        {
            var handler = ButtonChangeRbsApplicationType;
            if (handler == null)
            {
                return;
            }

            if (CollectionEditorHelper.EditValue(
                    this,
                    rbsChannelAppType,
                    nameof(rbsChannelAppType.RbsChannelAppTypes)) == DialogResult.OK)
            {
                handler(this, new RbsChannelAppTypeListEventArgs(rbsChannelAppType));
            }
        }

        private void OnButtonServiceGetStateClicked(object sender, EventArgs e)
        {
            var handler = ButtonServiceGetStateClicked;
            if (handler == null)
            {
                return;
            }

            var serviceControlServiceOn = new RBSServiceControl();

            serviceControlServiceOn.Channel = (byte)numericUpDownServiceChannel.Value;
            serviceControlServiceOn.Protocol =
                Convert.ToByte(((KeyValuePair<string, string>)comboBoxServiceProtocol.SelectedItem).Key);
            serviceControlServiceOn.VLAN = (ushort)numericUpDownServiceVlan.Value;
            serviceControlServiceOn.ServiceID = (ushort)numericUpDownServiceId.Value;
            serviceControlServiceOn.InstanceID = (ushort)numericUpDownInstanceId.Value;
            serviceControlServiceOn.MajorVersion = (byte)numericUpDownMajorNr.Value;
            serviceControlServiceOn.MinorVersion = (uint)numericUpDownMinorNr.Value;

            handler(this, new ServiceControlEventArgs(serviceControlServiceOn, true));
        }

        #endregion
        private void OnButtonAddManipulationUidClicked(object sender, EventArgs e)
        {
            ulong uid;

            try
            {
                uid = Convert.ToUInt64(this.textBoxManipulationUID.Text);
            }
            catch (Exception)
            {
                this.textBoxManipulationUID.BackColor = Color.Red;
                return;
            }

            this.textBoxManipulationUID.BackColor = Color.White;
            this.AddManipulationUids(new List<ulong> { uid });
        }

        private void OnButtonRemoveManipulationUidClicked(object sender, EventArgs e)
        {
            var selectedIndex = this.listBoxManipulationUIDs.SelectedIndex;
            if (selectedIndex > -1)
            {
                this.listBoxManipulationUIDs.Items.RemoveAt(selectedIndex);
            }
        }

        public void AddManipulationUids(IEnumerable<ulong> uids)
        {
            foreach (var uid in uids)
            {
                if (!this.listBoxManipulationUIDs.Items.Contains(uid))
                {
                    this.listBoxManipulationUIDs.Items.Add(uid, true);
                }
            }
        }

        private void OnButtonRemoveAllManipulationUidsClicked(object sender, EventArgs e)
        {
            this.listBoxManipulationUIDs.Items.Clear();
        }
    }
}