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

namespace HwComWrapperNETGui.UserControls
{
    /// <summary>
    ///     The channel configuration control.
    /// </summary>
    public partial class ChannelConfigurationControlCAN : UserControl
    {
        #region Constructors and Destructors
        
        /// <summary>
        ///     Initializes a new instance of the <see cref="ChannelConfigurationControlCAN"/> class.
        /// </summary>
        public ChannelConfigurationControlCAN()
        {
            this.InitializeComponent();
            if (!this.DesignMode)
            {
                this.comboBoxBaudrate.DataSource = Enum.GetValues(typeof(CANBaudrate));
                this.comboBoxBaudrate.SelectedItem = CANBaudrate.KBit500;
            }
        }

        #endregion

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

        /// <summary>
        ///     Occurs when the COM_AnalyzerSendMessageReq button was clicked.
        /// </summary>
        public event EventHandler<SendMessageEventArgs> ButtonSendMessageClicked;

        /// <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;

        #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<ChannelConfigurationCAN>
            {
                new ChannelConfigurationCAN
                {
                    BusType = BusTypes.CAN,
                    Baudrate = (CANBaudrate)this.comboBoxBaudrate.SelectedItem,
                    LO = this.checkBoxLO.Checked,
                    ChannelId = 0
                }
            };
       
            throw new NotSupportedException();
        }

        #endregion

        #region Methods
        // ReSharper disable once InconsistentNaming
        private void OnButtonAddFilterClicked(object sender, EventArgs e)
        {
            var newBusFilter = new BusSpecificFilterCAN
            {
                Ex = this.checkBoxFilterConfigurationEx.Checked,
                ID = Convert.ToUInt32(this.numericUpDownFilterConfigurationID.Value)
            };
            
            if (busSpecificFilters.Exists(p => newBusFilter.IsEqual(p)))
            {
                // Already in list
                return;
            }

            this.busSpecificFilters.Add(newBusFilter);
            this.lvFilters.Items.Add(new ListViewItem(
                new[]
                {
                    newBusFilter.ID.ToString(CultureInfo.InvariantCulture),
                    newBusFilter.Ex.ToString(CultureInfo.InvariantCulture)
                })
            );
        }

        private void OnButtonRemoveFilterClicked(object sender, EventArgs e)
        {
            var removedItems = new List<IBusSpecificFilter>();
            foreach (ListViewItem item in lvFilters.SelectedItems)
            {
                if (item.SubItems.Count >= 2)
                {
                    if (uint.TryParse(item.SubItems[0].Text, out var tempId)
                        && bool.TryParse(item.SubItems[1].Text, out var isExtended))
                    {
                        removedItems.AddRange(
                    busSpecificFilters.Where(p =>
                                p is BusSpecificFilterCAN filterCan
                                && filterCan.ID == tempId
                                && filterCan.Ex == isExtended));
                    }
                }

                lvFilters.Items.Remove(item);
            }

            if (removedItems.Any())
            {
                // Deactivate removed filters in device
                IFilterConfiguration filterConfiguration = new FilterConfigurationCAN
                {
                    BusType = BusTypes.CAN,
                    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 BusSpecificFilterCAN);
           lvFilters.Items.Clear();
        }

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

        private void OnButtonSendMessageClicked(object sender, EventArgs e)
        {
            var handler = this.ButtonSendMessageClicked;
            if (handler == null)
            {
                return;
            }
            
            var data = this.textBoxSendMessageData.Text.GetByteArray();
            if (data == null)
            {
                // ReSharper disable LocalizableElement
                MessageBox.Show(
                    "The data stream value is invalid. Please ensure, that the data stream is a valid hex stream. Examples: '00 0A 4B', '00-0A-4B' or '00 0a-4B'",
                    "Invalid data stream value",
                    MessageBoxButtons.OK);
                // ReSharper restore LocalizableElement
                return;
            }

            var length = data.Length > 8 ? 8 : data.Length;
            var config = new SendCANMessageConfiguration
            {
                BusType = BusTypes.CAN,
                ChannelId = 0,
                ID =
                    Convert.ToUInt32(
                        this.numericUpDownSendMessageCANID.Value),
                DLC = (byte)length,
                Ex = this.checkBoxSendMessageCANEx.Checked,
                Data = data.Take(length).ToArray()
            };

            handler(this, new SendMessageEventArgs(config));
        }

        private void OnButtonSetChannelConfigurationClicked(object sender, EventArgs e)
        {
            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 FilterConfigurationCAN
            {
                BusType = BusTypes.CAN,
                ChannelId = 0,
                SF = this.checkBoxFilterConfigurationSF.Checked,
                AA = this.checkBoxFilterConfigurationAA.Checked
            };

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

        #endregion

        #region Constants and Fields

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

        #endregion
    }
}