/*
 *
 * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
 *
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Text.RegularExpressions;

namespace RadioToolGUI
{
    internal partial class TxTab : UserControl
    {
        #region Members
        /*===================================================================*/
        private frmMain m_MainForm;
        private List<RadioButton> m_TxRadioButtons;
        private RadioTxMode_e currentTxMode;

        /* These two flags specify the status of StartTx and StopTx commands, respectively */
        private Boolean m_TxStartFinished, m_TxStopFinished;
        /*===================================================================*/
        #endregion /* Members */

        #region LifeCycle
        /*===================================================================*/
        internal TxTab(frmMain f)
        {
            m_MainForm = f;
            InitializeComponent();

            iFillRateList(0);
            iFillChannelList(0);
            iFillDataPatternList(0);
            iFillCCAThresholdList(2);
            iFillPreambleList(0);

            iFillTxRadioButtons();

            iInitHoverInformation();

            m_rdoPacketized.Checked = true;

            m_TxStartFinished = true;
            m_TxStopFinished = true;
        }
        /*===================================================================*/
        #endregion /* LifeCycle */

        #region Operations
        /*===================================================================*/  
        internal void EnableControls(Boolean enable)
        {
            m_btnTx.Enabled = enable;
        }

        private void iFillRateList(Int32 default_selection)
        {
            m_cboRate.Items.Add(new ComboboxItem("1 Mbps (DSSS)", RateIndex_e.RATE_1M));
            m_cboRate.Items.Add(new ComboboxItem("2 Mbps (DSSS)", RateIndex_e.RATE_2M));
            m_cboRate.Items.Add(new ComboboxItem("5.5 Mbps (CCK)", RateIndex_e.RATE_5_5M));
            m_cboRate.Items.Add(new ComboboxItem("11 Mbps (CCK)", RateIndex_e.RATE_11M));
            m_cboRate.Items.Add(new ComboboxItem("6 Mbps (OFDM)", RateIndex_e.RATE_6M));
            m_cboRate.Items.Add(new ComboboxItem("9 Mbps (OFDM)", RateIndex_e.RATE_9M));
            m_cboRate.Items.Add(new ComboboxItem("12 Mbps (OFDM)", RateIndex_e.RATE_12M));
            m_cboRate.Items.Add(new ComboboxItem("18 Mbps (OFDM)", RateIndex_e.RATE_18M));
            m_cboRate.Items.Add(new ComboboxItem("24 Mbps (OFDM)", RateIndex_e.RATE_24M));
            m_cboRate.Items.Add(new ComboboxItem("36 Mbps (OFDM)", RateIndex_e.RATE_36M));
            m_cboRate.Items.Add(new ComboboxItem("48 Mbps (OFDM)", RateIndex_e.RATE_48M));
            m_cboRate.Items.Add(new ComboboxItem("54 Mbps (OFDM)", RateIndex_e.RATE_54M));
            m_cboRate.Items.Add(new ComboboxItem("MCS 0", RateIndex_e.RATE_MCS_0));
            m_cboRate.Items.Add(new ComboboxItem("MCS 1", RateIndex_e.RATE_MCS_1));
            m_cboRate.Items.Add(new ComboboxItem("MCS 2", RateIndex_e.RATE_MCS_2));
            m_cboRate.Items.Add(new ComboboxItem("MCS 3", RateIndex_e.RATE_MCS_3));
            m_cboRate.Items.Add(new ComboboxItem("MCS 4", RateIndex_e.RATE_MCS_4));
            m_cboRate.Items.Add(new ComboboxItem("MCS 5", RateIndex_e.RATE_MCS_5));
            m_cboRate.Items.Add(new ComboboxItem("MCS 6", RateIndex_e.RATE_MCS_6));
            m_cboRate.Items.Add(new ComboboxItem("MCS 7", RateIndex_e.RATE_MCS_7));
            //m_cboRate.Items.Add(new ComboboxItem("Max Number Rates", RateIndex_e.MAX_NUM_RATES));

            m_cboRate.SelectedIndex = default_selection;
        }

        private void iFillChannelList(Int32 default_selection)
        {
            m_cboChannel.Items.Add(new ComboboxItem("1 (2412MHz)", Channel_e.CHANNEL_1));
            m_cboChannel.Items.Add(new ComboboxItem("2 (2417MHz)", Channel_e.CHANNEL_2));
            m_cboChannel.Items.Add(new ComboboxItem("3 (2422MHz)", Channel_e.CHANNEL_3));
            m_cboChannel.Items.Add(new ComboboxItem("4 (2427MHz)", Channel_e.CHANNEL_4));
            m_cboChannel.Items.Add(new ComboboxItem("5 (2432MHz)", Channel_e.CHANNEL_5));
            m_cboChannel.Items.Add(new ComboboxItem("6 (2437MHz)", Channel_e.CHANNEL_6));
            m_cboChannel.Items.Add(new ComboboxItem("7 (2442MHz)", Channel_e.CHANNEL_7));
            m_cboChannel.Items.Add(new ComboboxItem("8 (2447MHz)", Channel_e.CHANNEL_8));
            m_cboChannel.Items.Add(new ComboboxItem("9 (2452MHz)", Channel_e.CHANNEL_9));
            m_cboChannel.Items.Add(new ComboboxItem("10 (2457MHz)", Channel_e.CHANNEL_10));
            m_cboChannel.Items.Add(new ComboboxItem("11 (2462MHz)", Channel_e.CHANNEL_11));
            m_cboChannel.Items.Add(new ComboboxItem("12 (2467MHz)", Channel_e.CHANNEL_12));
            m_cboChannel.Items.Add(new ComboboxItem("13 (2472MHz)", Channel_e.CHANNEL_13));
            //m_cboChannel.Items.Add(new ComboboxItem("Max Channels", Channel_e.MAX_CHANNELS));

            m_cboChannel.SelectedIndex = default_selection;
        }

        private void iFillDataPatternList(Int32 default_selection)
        {
            m_cboDataPattern.Items.Add(new ComboboxItem("All 0", RadioDataPattern_e.ALL_0_PATTERN));
            m_cboDataPattern.Items.Add(new ComboboxItem("All 1", RadioDataPattern_e.ALL_1_PATTERN));
            m_cboDataPattern.Items.Add(new ComboboxItem("Incremental", RadioDataPattern_e.INCREMENTAL_PATTERN));
            m_cboDataPattern.Items.Add(new ComboboxItem("Decremental", RadioDataPattern_e.DECREMENTAL_PATTERN));
            m_cboDataPattern.Items.Add(new ComboboxItem("PN9  (WIP)", RadioDataPattern_e.PN9_PATTERN));
            m_cboDataPattern.Items.Add(new ComboboxItem("PN15 (WIP)", RadioDataPattern_e.PN15_PATTERN));
            m_cboDataPattern.Items.Add(new ComboboxItem("PN23 (WIP)", RadioDataPattern_e.PN23_PATTERN));
            //m_cboDataPattern.Items.Add(new ComboboxItem("Max Number Pattern", RadioDataPattern_e.MAX_NUM_PATTERN));

            m_cboDataPattern.SelectedIndex = default_selection;
        }

        private void iFillCCAThresholdList(Int32 default_selection)
        {
            m_cboCCAThreshold.Items.Add(new ComboboxItem("-88dBm (MIN)", RadioCCAThreshold_e.SL_TX_INHIBIT_THRESHOLD_MIN));
            m_cboCCAThreshold.Items.Add(new ComboboxItem("-78dBm (LOW)", RadioCCAThreshold_e.SL_TX_INHIBIT_THRESHOLD_LOW));
            m_cboCCAThreshold.Items.Add(new ComboboxItem("-68dBm (DEFAULT)", RadioCCAThreshold_e.SL_TX_INHIBIT_THRESHOLD_DEFAULT));
            m_cboCCAThreshold.Items.Add(new ComboboxItem("-58dBm (MED)", RadioCCAThreshold_e.SL_TX_INHIBIT_THRESHOLD_MED));
            m_cboCCAThreshold.Items.Add(new ComboboxItem("-48dBm (HIGH)", RadioCCAThreshold_e.SL_TX_INHIBIT_THRESHOLD_HIGH));
            m_cboCCAThreshold.Items.Add(new ComboboxItem("-38dBm (MAX)", RadioCCAThreshold_e.SL_TX_INHIBIT_THRESHOLD_MAX));

            m_cboCCAThreshold.SelectedIndex = default_selection;
        }

        private void iFillPreambleList(Int32 default_selection)
        {
            m_cboPreamble.Items.Add(new ComboboxItem("Long", RadioPreamble_e.LONG_PREAMBLE_MODE));
            m_cboPreamble.Items.Add(new ComboboxItem("Short", RadioPreamble_e.SHORT_PREAMBLE_MODE));

            m_cboPreamble.SelectedIndex = default_selection;
        }

        private void iFillTxRadioButtons()
        {
            m_TxRadioButtons = new List<RadioButton>();
            m_TxRadioButtons.Add(m_rdoContinuous);
            m_TxRadioButtons.Add(m_rdoToneCarrier);
            m_TxRadioButtons.Add(m_rdoPacketized);
        }

        private void iInitHoverInformation()
        {
            
            ToolTip tt = new ToolTip();
            tt.AutomaticDelay = 0;
            tt.ReshowDelay = 500;
            // Force the ToolTip text to be displayed whether or not the form is active.
            tt.ShowAlways = true;

            //Tone
            string title_Tone = Properties.Resources.info_ToneTitle;
            string info_Tone = Properties.Resources.info_Tone.Replace("\\n", "\n");
            tt.SetToolTip(m_nudTone, String.Format("{0}\n{1}", title_Tone, info_Tone));

            //Power
            string title_Power = Properties.Resources.info_PowerTitle;
            string info_Power = Properties.Resources.info_Power.Replace("\\n", "\n");
            tt.SetToolTip(m_nudPower, String.Format("{0}\n{1}", title_Power, info_Power));

            //Amount
            string title_Amount = Properties.Resources.info_AmountTitle;
            string info_Amount = Properties.Resources.info_Amount.Replace("\\n", "\n");
            tt.SetToolTip(m_nudAmount, String.Format("{0}\n{1}", title_Amount, info_Amount));

            //Size
            string title_Size = Properties.Resources.info_SizeTitle;
            string info_Size = Properties.Resources.info_Size.Replace("\\n", "\n");
            tt.SetToolTip(m_nudSize, String.Format("{0}\n{1}", title_Size, info_Size));
        }

        /// <summary>
        /// Specify the MAC address text box to accept only numbers 0-9 and letters a-f
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void iDestMacInputValidator(object sender, EventArgs e)
        {
            // Check for numbers
            //if (e.KeyChar > 47 && e.KeyChar < 58)
            //    return;

            // Check for letters A-F
            //if (e.KeyChar > 64 && e.KeyChar < 71)
            //    return;

            // Check for letters a-f
            //if (e.KeyChar > 96 && e.KeyChar < 103)
            //    return;

            //Other cases, not within specified range
            //e.Handled = true;
            Console.WriteLine(e.ToString());
        }

        private void iChangeGuiBasedOnTxMode(RadioTxMode_e mode)
        {
            //CW Mode
            if (mode == RadioTxMode_e.RADIO_TX_CW)
            {
                m_nudTone.Enabled = true;
                m_cboRate.Enabled = false;
                m_cboDataPattern.Enabled = false;
                m_nudPower.Enabled = false;
                m_cboPreamble.Enabled = false;
                m_ckbOverrideCCA.Enabled = false;
                m_nudSize.Enabled = false;
                m_nudDelay.Enabled = false;
                m_txtDstMacAddr.Enabled = false;
                m_nudAmount.Enabled = false;
                m_ckbEnableACKs.Enabled = false;
                m_cboCCAThreshold.Enabled = false;
                return;
            }

            //Packetized and Continuous mode - Common fields
            m_nudTone.Enabled = false;
            m_cboRate.Enabled = true;
            m_cboDataPattern.Enabled = true;
            m_nudPower.Enabled = true;
            m_cboPreamble.Enabled = true;
            m_ckbOverrideCCA.Enabled = true;
            m_nudSize.Enabled = true;
            m_txtDstMacAddr.Enabled = true;
            m_nudAmount.Enabled = true;
            m_cboCCAThreshold.Enabled = true;

            //Packetized Specific
            if (mode == RadioTxMode_e.RADIO_TX_PACKETIZED)
            {
                m_nudDelay.Enabled = true;
                m_ckbEnableACKs.Enabled = true;
            }
            else //Continuous Specific
            {
                m_nudDelay.Enabled = false;
                m_ckbEnableACKs.Enabled = false;
            }
        }

        private void t_Tx_DoWork(object sender, DoWorkEventArgs e)
        {
            e.Result = GlobalReference.StartTX((TxArgPack)e.Argument);
        }

        private void t_Tx_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            m_TxStartFinished = true;
            Boolean force_finish = false;

            Int32 workerResult = (Int32)e.Result;
            if (workerResult != 0)
            {
                //An error occurred in the StartTx, notify user and reset everthing.
                String error = String.Format("Error Code ({0}), Tx Abort", workerResult);
                MessageBox.Show(error,
                    "Tx Testing Error",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error,
                    MessageBoxDefaultButton.Button1);
                GlobalReference.WriteConsole(error);

                force_finish = true;
            }

            iCheckTxStatusAndCleanUp(force_finish);
        }

        private void t_StopTx_DoWork(object sender, DoWorkEventArgs e)
        {
            GlobalReference.StopTX(currentTxMode);
        }

        private void t_StopTx_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            m_TxStopFinished = true;
            iCheckTxStatusAndCleanUp(false);
        }

        /// <summary>
        /// There's a potential race condition here:
        /// If StopTx is called, there's no guarantee that StartTx returns before StopTx
        /// Therefore we use double checking to mack sure both are complete, then we can set the button back to "Start Tx"
        /// If either one of the flag is not true, nothing will be done.
        /// If force_finish flag is triggered, it means TX testing had some error and we need to reset everything.
        /// </summary>
        /// <param name="force_finish"></param>
        private void iCheckTxStatusAndCleanUp(Boolean force_finish)
        {
            if ((m_TxStopFinished & m_TxStartFinished) || force_finish)
            {
                m_grpTxMode.Enabled = true;
                m_btnTx.Enabled = true;
                m_btnTx.Text = Properties.Resources.txt_btnStartTx;

                GlobalReference.WriteConsole("Tx Testing Finished");
                m_MainForm.updateTestingStatus(GlobalReference.TESTING_STATUS_IDLE);
            }
        }

        /*===================================================================*/
        #endregion /* Operations */

        #region Event Handling
        /*===================================================================*/
        private void m_rdoPacketized_CheckedChanged(object sender, EventArgs e)
        {
            iChangeGuiBasedOnTxMode(RadioTxMode_e.RADIO_TX_PACKETIZED);
        }

        private void m_rdoContinuous_CheckedChanged(object sender, EventArgs e)
        {
            iChangeGuiBasedOnTxMode(RadioTxMode_e.RADIO_TX_CONTINUOUS);
        }

        private void m_rdoToneCarrier_CheckedChanged(object sender, EventArgs e)
        {
            iChangeGuiBasedOnTxMode(RadioTxMode_e.RADIO_TX_CW);
        }

        private void m_ckbOverrideCCA_CheckedChanged(object sender, EventArgs e)
        {
            m_cboCCAThreshold.Enabled = !m_ckbOverrideCCA.Checked;
        }

        private void m_cboRate_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(m_cboRate.SelectedIndex < 4)
            {
                m_cboPreamble.Enabled = true;
            }
            else
            {
                m_cboPreamble.Enabled = false;
            }
        }

        private void m_btnTx_Click(object sender, EventArgs e)
        {
            if (GlobalReference.isDeviceConnected())
            {
                frmMain.RadioToolThread = new BackgroundWorker();
                frmMain.RadioToolThread.WorkerReportsProgress = true;
                frmMain.RadioToolThread.WorkerSupportsCancellation = true;
                TxArgPack args = null;

                if (GlobalReference.getTestingState().Equals(GlobalReference.TESTING_STATUS_IDLE))
                {
                    //Device is idle, now starts TX testing.
                    #region Retrieve values

                    StringBuilder consoleprint = new StringBuilder("TX Started, Mode=");

                    SByte powerlv_or_tone       = 0x00;
                    RateIndex_e rate            = (RateIndex_e)(m_cboRate.SelectedItem as ComboboxItem).Value;
                    Channel_e channel           = (Channel_e)(m_cboChannel.SelectedItem as ComboboxItem).Value;
                    RadioPreamble_e preamble    = (RadioPreamble_e)(m_cboPreamble.SelectedItem as ComboboxItem).Value;
                    UInt16 size                 = Decimal.ToUInt16(m_nudSize.Value);
                    UInt32 delay                = Decimal.ToUInt32(m_nudDelay.Value);
                    UInt32 amount               = Decimal.ToUInt32(m_nudAmount.Value);
                    RadioDataPattern_e pattern  = (RadioDataPattern_e)(m_cboDataPattern.SelectedItem as ComboboxItem).Value;
                    Byte overrideCCA            = m_ckbOverrideCCA.Checked ? (Byte)0x01 : (Byte)0x00;
                    RadioCCAThreshold_e CCATsld = (RadioCCAThreshold_e)(m_cboCCAThreshold.SelectedItem as ComboboxItem).Value;
                    Byte enableACKs             = m_ckbEnableACKs.Checked ? (Byte)0x01 : (Byte)0x00;
                    Byte[] byteMAC              = { 0 };

                    //get testing type from radio buttons
                    if (m_rdoPacketized.Checked)
                    {
                        currentTxMode = RadioTxMode_e.RADIO_TX_PACKETIZED;
                        powerlv_or_tone = Decimal.ToSByte(m_nudPower.Value);
                        consoleprint.AppendFormat("Packetized, CH={0}, PW={1}, Rate={2}, Preamble={3}, Size={4}, Delay={5}, Amount={6}, Pattern={7}, CCA={8}, CCA_T={9}, ACK={10},",
                            channel,
                            m_nudPower.Value,
                            rate,
                            preamble,
                            size,
                            delay,
                            amount,
                            pattern,
                            overrideCCA,
                            CCATsld,
                            enableACKs);
                    }
                    else if (m_rdoContinuous.Checked)
                    {
                        currentTxMode = RadioTxMode_e.RADIO_TX_CONTINUOUS;
                        powerlv_or_tone = Decimal.ToSByte(m_nudPower.Value);
                        consoleprint.AppendFormat("Continuous, CH={0}, PW={1}, Rate={2}, Preamble={3}, Size={4}, Amount={5}, Pattern={6}, CCA={7}, CCA_T={8}",
                            channel,
                            m_nudPower.Value,
                            rate,
                            preamble,
                            size,
                            amount,
                            pattern,
                            overrideCCA,
                            CCATsld);
                    }
                    else if (m_rdoToneCarrier.Checked)
                    {
                        currentTxMode = RadioTxMode_e.RADIO_TX_CW;
                        powerlv_or_tone = Decimal.ToSByte(m_nudTone.Value);
                        byteMAC = GlobalReference.StringToByteArray("FFFFFFFFFFFF");
                        consoleprint.AppendFormat("CW, CH={0}, PW={1}, ", channel, m_nudTone.Value);
                    }

                    if (!m_rdoToneCarrier.Checked)
                    {
                        //Convert MAC address from string to byte
                        MaskedTextProvider mtp = m_txtDstMacAddr.MaskedTextProvider;
                        String strMAC = mtp.ToString(true, false, false, 0, mtp.Length);
                        Regex r = new Regex("^[a-fA-F0-9]*$");
                        if (!r.IsMatch(strMAC))
                        {
                            //MAC Address incorrect, alert user.
                            m_lblMacError.Visible = true;
                            return;
                        }

                        m_lblMacError.Visible = false;
                        byteMAC = GlobalReference.StringToByteArray(strMAC);
                        consoleprint.Append("Dest=" + mtp.ToString());
                    }

                    #endregion /* Retrieve values ends */

                    //Disable group box only because TX will be running in the background.
                    m_grpTxMode.Enabled = false;
                    m_TxStartFinished = false;
                    m_TxStopFinished = false;
                    m_btnTx.Text = Properties.Resources.txt_btnStopTx;

                    //Pack arguments into one object and give it to worker thread later.
                    args = new TxArgPack(
                        currentTxMode,
                        powerlv_or_tone,
                        channel,
                        rate,
                        preamble,
                        pattern,
                        size,
                        delay,
                        amount,
                        overrideCCA,
                        CCATsld,
                        enableACKs, 
                        byteMAC);

                    //Notify GUI
                    GlobalReference.WriteConsole(consoleprint.ToString());
                    m_MainForm.updateTestingStatus(GlobalReference.TESTING_STATUS_TX_RUNNING);

                    //Initialize a new worker thread
                    frmMain.RadioToolThread.DoWork += new DoWorkEventHandler(t_Tx_DoWork);
                    frmMain.RadioToolThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(t_Tx_RunWorkerCompleted);
                }
                else if (GlobalReference.getTestingState().Equals(GlobalReference.TESTING_STATUS_TX_RUNNING))
                {
                    //Device is already running in Tx mode, now stops.
                    frmMain.RadioToolThread.DoWork += new DoWorkEventHandler(t_StopTx_DoWork);
                    frmMain.RadioToolThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(t_StopTx_RunWorkerCompleted);

                    //No need to enable group_box and buttons here because t_StopTx_RunWorkerCompleted() will handle this.
                    m_TxStopFinished = false;
                    GlobalReference.WriteConsole("Tx Stopping...");
                    m_MainForm.updateTestingStatus(GlobalReference.TESTING_STATUS_TX_STOPPING);
                }
                else
                {
                    GlobalReference.WriteConsole("Error: Other tests running.");
                    MessageBox.Show("Other Tests Running: " + GlobalReference.getTestingState(), "Unknown Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                    return;
                }

                //Thread execution
                frmMain.RadioToolThread.RunWorkerAsync(args);
            }
            else
            {
                MessageBox.Show("Device is not connected.", "Connection Error", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);
            }

        }
        /*===================================================================*/
        #endregion /* Event Handling */
    }
}
