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


namespace HwComWrapperNETGui.UserControls
{
    public partial class ChannelConfigurationControlSENT : UserControl
    {
        #region Constructors and Destructiors

        /// <summary>
        ///     Initializes a new instance of the <see cref="ChannelConfigurationControlSENT"/> class.
        /// </summary>
        public ChannelConfigurationControlSENT()
        {
            this.InitializeComponent();
            if (!this.DesignMode)
            {
                this.comboBoxDirection.DataSource = Enum.GetValues(typeof(SENTDirection));
                this.comboBoxDirection.SelectedItem = SENTDirection.Receiver;
                this.comboBoxFormat.DataSource = Enum.GetValues(typeof(SENTFilterFormatTypes));
                this.comboBoxFormat.SelectedItem = SENTFilterFormatTypes.Fast;
                this.numericUpDownClockTickLength.Value = 3000;
                this.numericUpDownDataNibbles.Value = 6;
                this.checkBoxPausePulse.Checked = false;
                this.checkBoxCRC.Checked = false;
                this.checkBoxSlow.Checked = false;
                this.checkBoxSlowEnh.Checked = false;
            }
        }

        #endregion

        #region Events
        /// <summary>
        ///     Occurs when the COM_AnalyzerResetAllFiltersReq button was clicked.
        /// </summary>
        public event EventHandler<ResetAllFiltersEventArgs> ButtonResetAllFiltersClicked;

        /// <summary>
        ///     Occurs when the COM_AnalyzerConfigureChannelReq button was clicked.
        /// </summary>
        public event EventHandler<ChannelConfigurationsEventArgs> ButtonSetChannelConfigurationClicked;

        /// <summary>
        ///     Occurs when the COM_AnalyzerConfigureFilterReq button was clicked.
        /// </summary>
        public event EventHandler<FilterConfigurationEventArgs> ButtonSetFilterConfigurationClicked;
        #endregion

        #region Public Methods

        /// <summary>
        ///     Gets the <see cref="ChannelConfiguration"/> depending on the bus type.
        /// </summary>
        /// <returns> the <see cref="ChannelConfiguration"/> depending on the bus type. </returns>
        public IEnumerable<ChannelConfiguration> GetChannelConfiguration()
        {
            return new List<ChannelConfigurationSENT>
            {
                new ChannelConfigurationSENT
                {
                    BusType = BusTypes.SENT,
                    Direction = Convert.ToBoolean((SENTDirection)this.comboBoxDirection.SelectedItem),
                    SlowMessage = this.checkBoxSlow.Checked,
                    SlowMessageEnh = this.checkBoxSlowEnh.Checked,
                    PausePulse = this.checkBoxPausePulse.Checked,
                    IdlePolHigh = this.checkBoxIPH.Checked,
                    CRC = this.checkBoxCRC.Checked,
                    ContinuousMode = this.checkBoxCM.Checked,
                    SPCMode = this.checkBoxSPC.Checked,
                    DataNibbles = Convert.ToByte(this.numericUpDownDataNibbles.Value),
                    TxID = Convert.ToUInt16(this.numericUpDownTXID.Value),
                    ClockTickLength = Convert.ToUInt32(this.numericUpDownClockTickLength.Value),
                    ClockTickCount = Convert.ToUInt16(this.numericUpDownClockTickCount.Value),
                    SPCPulseWidth = Convert.ToUInt16(this.numericUpDownSPCPulseWidth.Value),
                    ChannelId = 0
                }
            };
        }

        #endregion

        #region Methods
        // ReSharper disable once InconsistentNaming
        private void OnButtonAddFilterClicked(object sender, EventArgs e)
        {
            var newBusFilter = new BusSpecificFilterSENT
            {
                MessageID = Convert.ToByte(this.numericUpDownFilterConfigurationMessageID.Value),
                IgnoreMessageID = this.checkBoxIMI.Checked,
                Format =(SENTFilterFormatTypes)this.comboBoxFormat.SelectedItem
            };

            if (busSpecificFilters.Exists(p => newBusFilter.IsEqual(p)))
            {
                // Already in list
                return;
            }

            this.busSpecificFilters.Add(newBusFilter);
            this.lvFilters.Items.Add(new ListViewItem(
                new[]
                {
                    newBusFilter.MessageID.ToString(CultureInfo.InvariantCulture),
                    newBusFilter.IgnoreMessageID.ToString(CultureInfo.InvariantCulture),
                    Enum.GetName(typeof(SENTFilterFormatTypes),newBusFilter.Format)
                })
            );
        }

        private void OnButtonRemoveFilterClicked(object sender, EventArgs e)
        {
            var removedItems = new List<IBusSpecificFilter>();
            foreach (ListViewItem item in lvFilters.SelectedItems)
            {
                if (item.SubItems.Count >= 3)
                {
                    var itemEnum = SENTFilterFormatTypes.Fast;
                    foreach(SENTFilterFormatTypes enumValue in Enum.GetValues(typeof(SENTFilterFormatTypes)))
                    {
                        if(Enum.GetName(typeof(SENTFilterFormatTypes), enumValue) == item.SubItems[2].Text)
                        {
                            itemEnum = enumValue;
                            break;
                        }
                    }
                    if (byte.TryParse(item.SubItems[0].Text, out var tempMessageID)
                        && bool.TryParse(item.SubItems[1].Text, out var tempIMI))
                    {
                        removedItems.AddRange(
                    busSpecificFilters.Where(p =>
                                p is BusSpecificFilterSENT filterSENT
                                && filterSENT.MessageID == tempMessageID
                                && filterSENT.IgnoreMessageID == tempIMI
                                && filterSENT.Format == itemEnum));
                    }
                }

                lvFilters.Items.Remove(item);
            }

            if (removedItems.Any())
            {
                // Deactivate removed filters in device
                IFilterConfiguration filterConfiguration = new FilterConfigurationSENT
                {
                    BusType = BusTypes.SENT,
                    ChannelId = 0,
                    SF = false
                };

                filterConfiguration.AddFilters(removedItems);
                ButtonSetFilterConfigurationClicked?.Invoke(this, new FilterConfigurationEventArgs(filterConfiguration));
                removedItems.ForEach(x => busSpecificFilters.Remove(x));
            }
        }

        // ReSharper disable once InconsistentNaming
        private void OnButtonClearFilterClicked(object sender, EventArgs e)
        {
            this.busSpecificFilters.RemoveAll(p => p is BusSpecificFilterSENT);
            lvFilters.Items.Clear();
        }

        private void OnButtonResetAllFiltersClicked(object sender, EventArgs e)
        {
            ButtonResetAllFiltersClicked?.Invoke(this, new ResetAllFiltersEventArgs(BusTypes.SENT, 0));
        }

        private void OnButtonSetChannelConfigurationClicked(object sender, EventArgs e)
        {
            if (this.checkBoxPausePulse.Checked)
            {
                if (this.numericUpDownClockTickCount.Value < 12)
                {
                    this.errorClockTickCount.SetError(this.numericUpDownClockTickCount, "When Pause Pulse is active the minimum accepted value is 12, Please change the value before trying again.");
                    return;
                }
                else
                {
                    this.errorClockTickCount.SetError(this.numericUpDownClockTickCount, "");
                }
            }

            var handler = this.ButtonSetChannelConfigurationClicked;
            if (handler == null)
            {
                return;
            }

            var channelConfigurations = this.GetChannelConfiguration();
            handler(this, new ChannelConfigurationsEventArgs(channelConfigurations));
        }

        private void OnButtonSetFilterConfigurationClicked(object sender, EventArgs e)
        {
            var handler = this.ButtonSetFilterConfigurationClicked;
            if (handler == null)
            {
                return;
            }

            IFilterConfiguration filterConfiguration = new FilterConfigurationSENT
            {
                BusType = BusTypes.SENT,
                ChannelId = 0,
                SF = this.checkBoxFilterConfigurationSF.Checked,
                AA = this.checkBoxFilterConfigurationAA.Checked
            };

            filterConfiguration.AddFilters(this.busSpecificFilters.Where(p => p is BusSpecificFilterSENT));
            handler(this, new FilterConfigurationEventArgs(filterConfiguration));
        }

        #endregion

        #region Constants and Fields

        private readonly List<IBusSpecificFilter> busSpecificFilters = new List<IBusSpecificFilter>();

        #endregion

    }
}
