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


namespace HwComWrapperNETGui.UserControls
{
    /// <summary>
    ///     The message category 84 (Analyser Functions) class.
    /// </summary>
    public partial class MsgCat84 : UserControl
    {
        #region Constructors and Destructors

        /// <summary>
        ///     Initializes a new instance of the <see cref="MsgCat84"/> class.
        /// </summary>
        public MsgCat84()
        {
            this.InitializeComponent();

            if (!this.DesignMode)
            {
                this.comboBoxBusTypes.DataSource = GetValidBusTypes();
                this.comboBoxBusTypes.SelectedItem = BusTypes.FlexRay; // As default

                Dictionary<string, string> dictTimeSource = new Dictionary<string, string>();
                dictTimeSource.Add("3", "Time Sync (Bus Time)");
                dictTimeSource.Add("2", "RealTimeClock (RTC)");
                dictTimeSource.Add("1", "Device Time (FPGA)");
                this.comboBoxTimeSource.DataSource = new BindingSource(dictTimeSource, null);
                this.comboBoxTimeSource.SelectedIndex = 2; // Device Time

                Dictionary<string, string> dictTargetType = new Dictionary<string, string>();
                dictTargetType.Add("1", "Unicast");
                dictTargetType.Add("2", "Multicast");
                this.comboBoxTargetType.DataSource = new BindingSource(dictTargetType, null);

                Dictionary<string, string> dictTransportProtocol = new Dictionary<string, string>();
                dictTransportProtocol.Add("3", "Ethernet");
                dictTransportProtocol.Add("2", "UDP");
                dictTransportProtocol.Add("1", "TCP");
                this.comboBoxTransportProtocol.DataSource = new BindingSource(dictTransportProtocol, null);
                this.comboBoxTransportProtocol.SelectedIndex = 1; // UDP

                Dictionary<string, string> dictProtocolFormat = new Dictionary<string, string>();
                dictProtocolFormat.Add("5", "ASAM CMP (Capture Module Protocol)");
                //dictProtocolFormat.Add("4", "SDK UDS"); // We don't want this in GUI
                dictProtocolFormat.Add("3", "SDK 64Bit Timestamps (FL3X Measure)");
                dictProtocolFormat.Add("2", "SDK 32Bit Timestamps (FL3X Measure)");
                dictProtocolFormat.Add("1", "Legacy (Analyzer)");
                this.comboBoxProtocolFormat.DataSource = new BindingSource(dictProtocolFormat, null);
                this.comboBoxProtocolFormat.SelectedIndex = 1; // SDK 64Bit

                Dictionary<string, string> dictPersistenceCommand = new Dictionary<string, string>();
                dictPersistenceCommand.Add("1", "Save");
                dictPersistenceCommand.Add("2", "Save+Start");
                dictPersistenceCommand.Add("3", "Delete");
                this.comboBoxPersistenceCommand.DataSource = new BindingSource(dictPersistenceCommand, null);

                this.comboBoxAnnounceTimeSource.DataSource = Enum.GetValues(typeof(PTPAnnounceTimeSource));
                this.comboBoxAnnounceTimeSource.SelectedItem = PTPAnnounceTimeSource.InternalOscillator;
                this.comboBoxAnnounceClockClass.DataSource = Enum.GetValues(typeof(PTPAnnounceClockClass));
                this.comboBoxAnnounceClockClass.SelectedItem = PTPAnnounceClockClass.Default;
                this.comboBoxAnnounceClockAccurracy.DataSource = Enum.GetValues(typeof(PTPAnnounceAccurracy));
                this.comboBoxAnnounceClockAccurracy.SelectedItem = PTPAnnounceAccurracy.AccurracyUnknown;
            }
        }

        #endregion

        #region Public Events

        /// <summary>
        ///     Occurs when the get button for COM_AnalyzerVersionReq was clicked. 
        /// </summary>
        public event EventHandler ButtonAnalyzerVersionClicked;

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

        /// <summary>
        ///     Occurs when the COM_AnalyzerStartReq button was clicked.
        /// </summary>
        public event EventHandler<StartAnalyzerEventArgs> ButtonStartAnalyzerClicked;

        /// <summary>
        ///     Occurs when the COM_AnalyzerConfigureReq button was clicked.
        /// </summary>
        public event EventHandler<AnalyzerConfigureEventArgs> ButtonAnalyzerConfigureClicked;

        /// <summary>
        ///     Occurs when the COM_AnalyzerStopReq button was clicked.
        /// </summary>
        public event EventHandler ButtonStopAnalyzerClicked;

        /// <summary>
        ///     Occurs when the COM_AnalyzerStartChannelReq button was clicked.
        /// </summary>
        public event EventHandler<AnalyzerChannelStartEventArgs> ButtonAnalyzerStartChannelClicked;

        /// <summary>
        ///     Occurs when the COM_AnalyzerStopChannelReq button was clicked.
        /// </summary>
        public event EventHandler<AnalyzerChannelStopEventArgs> ButtonAnalyzerStopChannelClicked;

        /// <summary>
        ///     Occurs when the COM_AnalyzerPersistenceControlReq button was clicked.
        /// </summary>
        public event EventHandler<AnalyzerPersistenceControlEventArgs> ButtonAnalyzerPersistenceControlClicked;

        /// <summary>
        ///     Occurs when the COM_AnalyzerConfigurePTPTimeSyncReq button was clicked.
        /// </summary>
        public event EventHandler<AnalyzerPTPTimeSyncConfigEventArgs> ButtonAnalyzerConfigurePTPTimeSyncClicked;
        #endregion

        #region Methods

        private void OnButtonAnalyzerVersionClicked(object sender, EventArgs e)
        {
            ButtonAnalyzerVersionClicked?.Invoke(this, EventArgs.Empty);
        }

        private void OnButtonStartAnalyzerClicked(object sender, EventArgs e)
        {
            ButtonStartAnalyzerClicked?.Invoke(this, new StartAnalyzerEventArgs(Convert.ToUInt16(this.numericUpDownTCPPort.Value)));
        }

        private void OnButtonStopAnalyzerClicked(object sender, EventArgs e)
        {
            ButtonStopAnalyzerClicked?.Invoke(this, EventArgs.Empty);
        }

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

            IAnalyzerConfiguration analyzerConfiguration = new AnalyzerConfiguration
            {
                AnalyzerConfigVersion = CurrentAnalyzerConfigVersion,
                TimeSourceChannel = Convert.ToByte(this.numericUpDownTimeSourceChannel.Value),
                DataInterval = Convert.ToUInt16(this.numericUpDownDataInterval.Value),
                StatisticInterval = Convert.ToUInt16(this.numericUpDownStatisticInterval.Value),
                ThreasholdSize = Convert.ToUInt16(this.numericUpDownThreasholdSize.Value),
                TransportProtocol = Convert.ToByte(((KeyValuePair<string, string>)this.comboBoxTransportProtocol.SelectedItem).Key),
                ProtocolFormat = Convert.ToByte(((KeyValuePair<string, string>)this.comboBoxProtocolFormat.SelectedItem).Key),
                TargetPort = Convert.ToUInt16(this.numericUpDownTargetPort.Value),
                TargetType = Convert.ToUInt16(((KeyValuePair<string, string>)this.comboBoxTargetType.SelectedItem).Key),
                IPv4_0 = Convert.ToByte(this.textBoxIP0.Text),
                IPv4_1 = Convert.ToByte(this.textBoxIP1.Text),
                IPv4_2 = Convert.ToByte(this.textBoxIP2.Text),
                IPv4_3 = Convert.ToByte(this.textBoxIP3.Text)
            };

            handler(this, new AnalyzerConfigureEventArgs(analyzerConfiguration));
        }

        #endregion

        #region Constants and Fields

        private readonly List<IBusSpecificFilter> busSpecificFilters = new List<IBusSpecificFilter>();
        const byte CurrentAnalyzerConfigVersion = 0;

        #endregion

        private void OnButtonStartChannelClicked(object sender, EventArgs e)
        {
            ButtonAnalyzerStartChannelClicked?.Invoke(this, new AnalyzerChannelStartEventArgs(Convert.ToByte(this.numericUpDownChannelID.Value)));
        }

        private void OnButtonStopChannelClicked(object sender, EventArgs e)
        {
            ButtonAnalyzerStopChannelClicked?.Invoke(this, new AnalyzerChannelStopEventArgs(Convert.ToByte(this.numericUpDownChannelID.Value)));
        }

        private void OnButtonPersistenceCommandSetClicked(object sender, EventArgs e)
        {
            ButtonAnalyzerPersistenceControlClicked?.Invoke(this, new AnalyzerPersistenceControlEventArgs((PersistenceCommand)Convert.ToInt32(((KeyValuePair<string, string>)this.comboBoxPersistenceCommand.SelectedItem).Key)));
        }

        private void comboBoxBusTypes_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.panelChannelConfiguration.Controls.Clear();

            switch ((BusTypes)this.comboBoxBusTypes.SelectedValue)
            {
            case BusTypes.FlexRay:
                {
                    var channelConfigurationControl = new HwComWrapperNETGui.UserControls.ChannelConfigurationControlFlexRay();
                    channelConfigurationControl.ButtonResetAllFiltersClicked += OnButtonResetAllFiltersClicked;
                    channelConfigurationControl.ButtonSetChannelConfigurationClicked += OnButtonSetChannelConfigurationClicked;
                    channelConfigurationControl.ButtonSetFilterConfigurationClicked += OnButtonSetFilterConfigurationClicked;
                    channelConfigurationControl.Dock = DockStyle.Fill;
                    this.panelChannelConfiguration.Controls.Add(channelConfigurationControl);
                    break;
                }
            case BusTypes.CAN:
                {
                    var channelConfigurationControl = new HwComWrapperNETGui.UserControls.ChannelConfigurationControlCAN();
                    channelConfigurationControl.ButtonResetAllFiltersClicked += OnButtonResetAllFiltersClicked;
                    channelConfigurationControl.ButtonSendMessageClicked += OnButtonSendMessageClicked;
                    channelConfigurationControl.ButtonSetChannelConfigurationClicked += OnButtonSetChannelConfigurationClicked;
                    channelConfigurationControl.ButtonSetFilterConfigurationClicked += OnButtonSetFilterConfigurationClicked;
                    channelConfigurationControl.Dock = DockStyle.Fill;
                    this.panelChannelConfiguration.Controls.Add(channelConfigurationControl);
                    break;
                }
            case BusTypes.CAN_FD:
                {
                    var channelConfigurationControl = new HwComWrapperNETGui.UserControls.ChannelConfigurationControlCANFD();
                    channelConfigurationControl.ButtonResetAllFiltersClicked += OnButtonResetAllFiltersClicked;
                    channelConfigurationControl.ButtonSendMessageClicked += OnButtonSendMessageClicked;
                    channelConfigurationControl.ButtonSetChannelConfigurationClicked += OnButtonSetChannelConfigurationClicked;
                    channelConfigurationControl.ButtonSetFilterConfigurationClicked += OnButtonSetFilterConfigurationClicked;
                    channelConfigurationControl.Dock = DockStyle.Fill;
                    this.panelChannelConfiguration.Controls.Add(channelConfigurationControl);
                    break;
                }
            case BusTypes.LIN:
                {
                    var channelConfigurationControl = new HwComWrapperNETGui.UserControls.ChannelConfigurationControlLIN();
                    channelConfigurationControl.ButtonResetAllFiltersClicked += OnButtonResetAllFiltersClicked;
                    channelConfigurationControl.ButtonSendMessageClicked += OnButtonSendMessageClicked;
                    channelConfigurationControl.ButtonSetChannelConfigurationClicked += OnButtonSetChannelConfigurationClicked;
                    channelConfigurationControl.ButtonSetFilterConfigurationClicked += OnButtonSetFilterConfigurationClicked;
                    channelConfigurationControl.Dock = DockStyle.Fill;
                    this.panelChannelConfiguration.Controls.Add(channelConfigurationControl);
                    break;
                }
            case BusTypes.ETH:
            case BusTypes.BROADR_REACH:
                {
                    var channelConfigurationControl = new HwComWrapperNETGui.UserControls.ChannelConfigurationControlEthernet((BusTypes)this.comboBoxBusTypes.SelectedValue);
                    channelConfigurationControl.ButtonSetChannelConfigurationClicked += OnButtonSetChannelConfigurationClicked;
                    channelConfigurationControl.ButtonResetAllFiltersClicked += OnButtonResetAllFiltersClicked;
                    channelConfigurationControl.ButtonSetFilterConfigurationClicked += OnButtonSetFilterConfigurationClicked;
                    channelConfigurationControl.Dock = DockStyle.Fill;
                    this.panelChannelConfiguration.Controls.Add(channelConfigurationControl);
                    break;
                }
            case BusTypes.SENT:
                {
                        var channelConfigurationControl = new HwComWrapperNETGui.UserControls.ChannelConfigurationControlSENT();
                        channelConfigurationControl.ButtonResetAllFiltersClicked += OnButtonResetAllFiltersClicked;
                        channelConfigurationControl.ButtonSetChannelConfigurationClicked += OnButtonSetChannelConfigurationClicked;
                        channelConfigurationControl.ButtonSetFilterConfigurationClicked += OnButtonSetFilterConfigurationClicked;
                        channelConfigurationControl.Dock = DockStyle.Fill;
                        this.panelChannelConfiguration.Controls.Add(channelConfigurationControl);
                    break;
                }
            default:
                {
                    var channelConfigurationControl = new HwComWrapperNETGui.UserControls.ChannelConfigurationControl();
                    channelConfigurationControl.Dock = DockStyle.Fill;
                    this.panelChannelConfiguration.Controls.Add(channelConfigurationControl);
                    break;
                }
            }
        }

        private void OnButtonResetAllFiltersClicked(object sender, ResetAllFiltersEventArgs e)
        {
            e.ChannelId = (byte)numericUpDownChannelID.Value;
            this.ButtonResetAllFiltersClicked?.Invoke(sender, e);
        }
        private void OnButtonSendMessageClicked(object sender, SendMessageEventArgs e)
        {
            e.MessageConfiguration.ChannelId = (byte)numericUpDownChannelID.Value;
            this.ButtonSendMessageClicked?.Invoke(sender, e);
        }
        private void OnButtonSetChannelConfigurationClicked(object sender, ChannelConfigurationsEventArgs e)
        {
            foreach (var item in e.ChannelConfigurations)
            {
                item.ChannelId = (byte)numericUpDownChannelID.Value;
                item.TimestampBase = (TimestampBases)Convert.ToByte(((KeyValuePair<string, string>)this.comboBoxTimeSource.SelectedItem).Key);
            }
           
            this.ButtonSetChannelConfigurationClicked?.Invoke(sender, e);
        }
        private void OnButtonSetFilterConfigurationClicked(object sender, FilterConfigurationEventArgs e)
        {
            e.FilterConfiguration.ChannelId = (byte)numericUpDownChannelID.Value; ;
            this.ButtonSetFilterConfigurationClicked?.Invoke(sender, e);
        }


        /// <summary>Gets the valid bus types used for bus configurations</summary>
        /// <returns>A list with all known used bus types; otherwise a empty list.</returns>
        private List<BusTypes> GetValidBusTypes()
        {
            // Old list with all enum type expect the _ISO ones. But deprecated because we support only a few bus types for configuration.
            //var enumValues = Enum.GetValues(typeof(BusTypes));
            //List<BusTypes> sortedOnes = new List<BusTypes>();
            //foreach (BusTypes enumValue in enumValues)
            //{
            //    var valueString = enumValue.ToString();
            //    if (!string.IsNullOrEmpty(valueString) && !valueString.EndsWith("_ISO"))
            //    {
            //        sortedOnes.Add(enumValue);
            //    }
            //}

            //return sortedOnes;

            // We only support the current listed bus types for configuration in Analyzer and FL3X Measure!
            // If a new type was added to be supported. Add it here.
            return new List<BusTypes>
            {
                BusTypes.FlexRay,
                BusTypes.CAN,
                BusTypes.CAN_FD,
                BusTypes.LIN,
                BusTypes.SENT,
                BusTypes.ETH,
                BusTypes.BROADR_REACH
            };
        }

        private void buttonAnalyzerPTP_Click(object sender, EventArgs e)
        {
            PTPTimeSyncConfiguration timeSyncConfig = new PTPTimeSyncConfiguration();

            timeSyncConfig.Channel = (byte)this.numericUpDownPTPChannel.Value;
            timeSyncConfig.IsMaster = this.checkBoxPTPMaster.Checked;
            timeSyncConfig.GlobalMasterFlag = this.checkBoxPTPGlobalMaster.Checked;
            timeSyncConfig.IsBusTimeSource = this.checkBoxPTPSource.Checked;
            timeSyncConfig.UseIPv4 = this.checkBoxPTPIPv4.Checked;
            timeSyncConfig.UseRealtimeClockBackup = this.checkBoxPTPBackup.Checked;
            timeSyncConfig.DomainId = (byte)this.numericUpDownPTPDomain.Value;
            timeSyncConfig.VLAN = (ushort)this.numericUpDownPTPVLAN.Value;
            timeSyncConfig.TransportSpecific = (byte)this.numericUpDownPTPTransportSpecific.Value;
            timeSyncConfig.SyncPeriodMs = (ushort)this.numericUpDownPTPSyncMs.Value;
            timeSyncConfig.FollowUpOffsetMs = (ushort)this.numericUpDownPTPFupMs.Value;
            timeSyncConfig.PDelayMs = (ushort)this.numericUpDownPTPPdelayMs.Value;
            timeSyncConfig.PDelayStaticNs = (ushort)this.numericUpDownPTPPDelayStaticNs.Value;

            timeSyncConfig.AnnounceIntervalMs = (ushort)this.numericUpDownPTPAnnounceIntervalMs.Value;
            timeSyncConfig.AnnounceTimeSource = (PTPAnnounceTimeSource)this.comboBoxAnnounceTimeSource.SelectedItem;
            timeSyncConfig.AnnounceClockClass = (PTPAnnounceClockClass)this.comboBoxAnnounceClockClass.SelectedItem;
            timeSyncConfig.AnnounceClockAccurracy = (PTPAnnounceAccurracy)this.comboBoxAnnounceClockAccurracy.SelectedItem;
            timeSyncConfig.AnnounceClockVariance = (short)this.numericUpDownPTPVariance.Value;
            timeSyncConfig.AnnounceUTCOffset = (short)this.numericUpDownPTPUTCOffset.Value;
            timeSyncConfig.AnnounceStepsRemoved = (short)this.numericUpDownPTPStepsRemoved.Value;
            timeSyncConfig.AnnouncePriority1 = (byte)this.numericUpDownPTPPriority1.Value;
            timeSyncConfig.AnnouncePriority2 = (byte)this.numericUpDownPTPPriority2.Value;

            ButtonAnalyzerConfigurePTPTimeSyncClicked?.Invoke(this, new AnalyzerPTPTimeSyncConfigEventArgs(timeSyncConfig));
        }
    }

}