//-------------------------------------------------------------------------------------
// SID Monitor - Utility for Sudden Ionospheric Disturbances Monitoring Stations
// Copyright (C) 2005 - Lionel Loudet
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//-------------------------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Globalization;
using WeifenLuo.WinFormsUI;


namespace SID_monitor
{
    public partial class EventDialogDockablePanel : DockContent
    {
        public enum EventDialogType { AddEvent, EditEvent };

        // global variables
        private ArrayList ErroneousElements = new ArrayList();
        private EventDialogType eventDialogType = EventDialogType.AddEvent; // defined the title and the returned event when closed is pressed
        // by default, add event type

        public EventDialogDockablePanel()
        {
            InitializeComponent();

            this.Text = "Add Event..."; // by default, add event type

            this.comboBoxStartTimeQualifier.Items.AddRange(SIDEventsViewer.TimeQualifierItems);
            this.comboBoxEndTimeQualifier.Items.AddRange(SIDEventsViewer.TimeQualifierItems);
            this.comboBoxMaxTimeQualifier.Items.AddRange(SIDEventsViewer.TimeQualifierItems);
            this.comboBoxImportance.Items.AddRange(SIDEventsViewer.ImportanceItems);
            this.comboBoxDefiniteness.Items.AddRange(SIDEventsViewer.DefinitenessItems);

            maskedTextBoxDate_TextChanged(maskedTextBoxDate, new EventArgs());
            maskedTextBoxTime_TextChanged(maskedTextBoxStartTime, new EventArgs());
            comboBoxTimeQualifier_TextChanged(comboBoxStartTimeQualifier, new EventArgs());
            maskedTextBoxTime_TextChanged(maskedTextBoxEndTime, new EventArgs());
            comboBoxTimeQualifier_TextChanged(comboBoxEndTimeQualifier, new EventArgs());
            maskedTextBoxTime_TextChanged(maskedTextBoxMaxTime, new EventArgs());
            comboBoxTimeQualifier_TextChanged(comboBoxMaxTimeQualifier, new EventArgs());
            comboBoxImportance_TextChanged(comboBoxImportance, new EventArgs());
            comboBoxDefiniteness_TextChanged(comboBoxDefiniteness, new EventArgs());
            comboBoxStationCode_TextChanged(comboBoxStationCode, new EventArgs());
            maskedTextBoxObserverCode_TextChanged(maskedTextBoxObserverCode, new EventArgs());

        }


        #region Properties
        public EventDialogType DialogType
        {
            get
            {
                return this.eventDialogType;
            }
            set
            {
                this.eventDialogType = value;
                if (this.eventDialogType == EventDialogType.AddEvent)
                {
                    this.Text = "Add Event...";
                }
                else
                {
                    this.Text = "Edit Event...";
                }
            }
        }

        public DateTime Date
        {
            get
            {
                try
                {
                    return DateTime.ParseExact(this.maskedTextBoxDate.Text, "dd/MM/yyyy", new CultureInfo("")).Date;
                }
                catch
                {
                    return DateTime.MinValue;
                }
            }
            set
            {
                this.maskedTextBoxDate.Text = value.ToString("dd/MM/yyyy");
            }
        }

        public DateTime StartTime
        {
            get
            {
                try
                {
                    return DateTime.ParseExact(this.maskedTextBoxStartTime.Text, "HH:mm", new CultureInfo(""));
                }
                catch
                {
                    return DateTime.MinValue;
                }
            }
            set
            {
                this.maskedTextBoxStartTime.Text = value.ToString("HH:mm");
            }
        }

        public DateTime EndTime
        {
            get
            {
                try
                {
                    return DateTime.ParseExact(this.maskedTextBoxEndTime.Text, "HH:mm", new CultureInfo(""));
                }
                catch
                {
                    return DateTime.MinValue;
                }
            }
            set
            {
                this.maskedTextBoxEndTime.Text = value.ToString("HH:mm");
            }
        }

        public DateTime MaxTime
        {
            get
            {
                try
                {
                    return DateTime.ParseExact(this.maskedTextBoxMaxTime.Text, "HH:mm", new CultureInfo(""));
                }
                catch
                {
                    return DateTime.MinValue;
                }
            }
            set
            {
                this.maskedTextBoxMaxTime.Text = value.ToString("HH:mm");
            }
        }

        public String StartTimeQualifier
        {
            get
            {
                if (String.IsNullOrEmpty(this.comboBoxStartTimeQualifier.Text))
                {
                    return SIDEventsViewer.TimeQualifierItems[0];
                }
                else
                {
                    return this.comboBoxStartTimeQualifier.Text;
                }

            }
            set
            {
                if (comboBoxStartTimeQualifier.Items.Contains(value))
                {
                    this.comboBoxStartTimeQualifier.Text = value;
                }
                else
                {
                    this.comboBoxStartTimeQualifier.Text = String.Empty;
                }
            }
        }

        public String EndTimeQualifier
        {
            get
            {
                if (String.IsNullOrEmpty(this.comboBoxEndTimeQualifier.Text))
                {
                    return SIDEventsViewer.TimeQualifierItems[0];
                }
                else
                {
                    return this.comboBoxEndTimeQualifier.Text;
                }

            }
            set
            {
                if (comboBoxEndTimeQualifier.Items.Contains(value))
                {
                    this.comboBoxEndTimeQualifier.Text = value;
                }
                else
                {
                    this.comboBoxEndTimeQualifier.Text = String.Empty;
                }
            }
        }

        public String MaxTimeQualifier
        {
            get
            {
                if (String.IsNullOrEmpty(this.comboBoxMaxTimeQualifier.Text))
                {
                    return SIDEventsViewer.TimeQualifierItems[0];
                }
                else
                {
                    return this.comboBoxMaxTimeQualifier.Text;
                }

            }
            set
            {
                if (comboBoxMaxTimeQualifier.Items.Contains(value))
                {
                    this.comboBoxMaxTimeQualifier.Text = value;
                }
                else
                {
                    this.comboBoxMaxTimeQualifier.Text = String.Empty;
                }
            }
        }

        public String Importance
        {
            get
            {
                if (String.IsNullOrEmpty(this.comboBoxImportance.Text))
                {
                    return SIDEventsViewer.ImportanceItems[0];
                }
                else
                {
                    return this.comboBoxImportance.Text;
                }
            }
            set
            {
                if (comboBoxImportance.Items.Contains(value))
                {
                    this.comboBoxImportance.Text = value;
                }
                else
                {
                    this.comboBoxImportance.Text = String.Empty;
                }
            }
        }

        public String Definiteness
        {
            get
            {
                if (String.IsNullOrEmpty(this.comboBoxDefiniteness.Text))
                {
                    return SIDEventsViewer.DefinitenessItems[0];
                }
                else
                {
                    return this.comboBoxDefiniteness.Text;
                }
            }
            set
            {
                if (comboBoxDefiniteness.Items.Contains(value))
                {
                    this.comboBoxDefiniteness.Text = value;
                }
                else
                {
                    this.comboBoxDefiniteness.Text = String.Empty;
                }
            }
        }

        public String[] StationCodeItems
        {
            set
            {
                this.comboBoxStationCode.Items.Clear();
                this.comboBoxStationCode.Items.AddRange(value);
            }
        }

        public String StationCode
        {
            get
            {
                if (String.IsNullOrEmpty(this.comboBoxStationCode.Text))
                {
                    return String.Empty;
                }
                else
                {
                    return this.comboBoxStationCode.Text;
                }
            }
            set
            {
                if (comboBoxStationCode.Items.Contains(value))
                {
                    this.comboBoxStationCode.Text = value;
                }
                else
                {
                    this.comboBoxStationCode.Text = String.Empty;
                }
            }
        }

        public String ObserverCode
        {
            get
            {
                return this.maskedTextBoxObserverCode.Text;
            }
            set
            {
                this.maskedTextBoxObserverCode.Text = value;
            }
        }
        #endregion

        #region Validation methods

        private void maskedTextBoxDate_TextChanged(object sender, EventArgs e)
        {
            DateTime result;
            if (DateTime.TryParseExact(maskedTextBoxDate.Text, "dd/mm/yyyy", new CultureInfo(""), DateTimeStyles.NoCurrentDateDefault, out result))
            {
                errorProvider.SetError(maskedTextBoxDate, "");
                if (ErroneousElements.Contains(maskedTextBoxDate.Handle))
                {
                    ErroneousElements.Remove(maskedTextBoxDate.Handle);
                }
                if (ErroneousElements.Count == 0)
                {
                    this.buttonOK.Enabled = true;
                }
            }
            else
            {
                errorProvider.SetError(maskedTextBoxDate, "Invalid Date Format. Please use dd/mm/yyyy.");
                if (!ErroneousElements.Contains(maskedTextBoxDate.Handle))
                {
                    ErroneousElements.Add(maskedTextBoxDate.Handle);
                }
                this.buttonOK.Enabled = false;
            }


        }

        private void maskedTextBoxTime_TextChanged(object sender, EventArgs e)
        {
            MaskedTextBox currentMaskedTextBox = (MaskedTextBox)sender;
            DateTime result;
            if (DateTime.TryParseExact(currentMaskedTextBox.Text, "HH:mm", new CultureInfo(""), DateTimeStyles.NoCurrentDateDefault, out result))
            {
                errorProvider.SetError(currentMaskedTextBox, "");
                if (ErroneousElements.Contains(currentMaskedTextBox.Handle))
                {
                    ErroneousElements.Remove(currentMaskedTextBox.Handle);
                }
                if (ErroneousElements.Count == 0)
                {
                    this.buttonOK.Enabled = true;
                }
            }
            else
            {
                errorProvider.SetError(currentMaskedTextBox, "Invalid Time Format. Please use HH:mm.");
                if (!ErroneousElements.Contains(currentMaskedTextBox.Handle))
                {
                    ErroneousElements.Add(currentMaskedTextBox.Handle);
                }
                this.buttonOK.Enabled = false;
            }

        }

        private void maskedTextBoxObserverCode_TextChanged(object sender, EventArgs e)
        {
            if (maskedTextBoxObserverCode.MaskFull)
            {
                errorProvider.SetError(maskedTextBoxObserverCode, "");
                if (ErroneousElements.Contains(maskedTextBoxObserverCode.Handle))
                {
                    ErroneousElements.Remove(maskedTextBoxObserverCode.Handle);
                }
                if (ErroneousElements.Count == 0)
                {
                    this.buttonOK.Enabled = true;
                }
            }
            else
            {
                errorProvider.SetError(maskedTextBoxObserverCode, "Invalid Observer Code Format. Observer code consists of 4 alphanumeric characters.");
                if (!ErroneousElements.Contains(maskedTextBoxObserverCode.Handle))
                {
                    ErroneousElements.Add(maskedTextBoxObserverCode.Handle);
                }
                this.buttonOK.Enabled = false;
            }
        }

        private void comboBoxTimeQualifier_TextChanged(object sender, EventArgs e)
        {
            ComboBox currentComboBox = (ComboBox)sender;
            if (currentComboBox.Items.Contains(currentComboBox.Text))
            {
                errorProvider.SetError(currentComboBox, "");
                if (ErroneousElements.Contains(currentComboBox.Handle))
                {
                    ErroneousElements.Remove(currentComboBox.Handle);
                }
                if (ErroneousElements.Count == 0)
                {
                    this.buttonOK.Enabled = true;
                }
            }
            else
            {
                errorProvider.SetError(currentComboBox, "Invalid Time Qualifier. Please select qualifier from the dropdown list.");
                if (!ErroneousElements.Contains(currentComboBox.Handle))
                {
                    ErroneousElements.Add(currentComboBox.Handle);
                }
                this.buttonOK.Enabled = false;
            }
        }

        private void comboBoxImportance_TextChanged(object sender, EventArgs e)
        {
            if (comboBoxImportance.Items.Contains(comboBoxImportance.Text))
            {
                int ImportanceIndex = GetEventImportanceIndex();

                // if the start and endtime are defined, we check if the selected importance setting is correct
                if ((ImportanceIndex != -1) && (comboBoxImportance.SelectedIndex != ImportanceIndex)) // not corect
                {
                    errorProvider.SetError(comboBoxImportance, "The Importance parameter has to be consistent with event duration.");
                    if (!ErroneousElements.Contains(comboBoxImportance.Handle))
                    {
                        ErroneousElements.Add(comboBoxImportance.Handle);
                    }
                    this.buttonOK.Enabled = false;
                }
                else // start and end time not defined or valid importance setting
                {
                    errorProvider.SetError(comboBoxImportance, "");
                    if (ErroneousElements.Contains(comboBoxImportance.Handle))
                    {
                        ErroneousElements.Remove(comboBoxImportance.Handle);
                    }
                    if (ErroneousElements.Count == 0)
                    {
                        this.buttonOK.Enabled = true;
                    }
                }
            }
            else
            {
                errorProvider.SetError(comboBoxImportance, "Invalid Importance Parameter. Please select parameter from the dropdown list.");
                if (!ErroneousElements.Contains(comboBoxImportance.Handle))
                {
                    ErroneousElements.Add(comboBoxImportance.Handle);
                }
                this.buttonOK.Enabled = false;
            }
        }

        private void comboBoxDefiniteness_TextChanged(object sender, EventArgs e)
        {
            if (comboBoxDefiniteness.Items.Contains(comboBoxDefiniteness.Text))
            {
                errorProvider.SetError(comboBoxDefiniteness, "");
                if (ErroneousElements.Contains(comboBoxDefiniteness.Handle))
                {
                    ErroneousElements.Remove(comboBoxDefiniteness.Handle);
                }
                if (ErroneousElements.Count == 0)
                {
                    this.buttonOK.Enabled = true;
                }
            }
            else
            {
                errorProvider.SetError(comboBoxDefiniteness, "Invalid Definiteness Parameter. Please select parameter from the dropdown list.");
                if (!ErroneousElements.Contains(comboBoxDefiniteness.Handle))
                {
                    ErroneousElements.Add(comboBoxDefiniteness.Handle);
                }
                this.buttonOK.Enabled = false;
            }
        }

        private void comboBoxStationCode_TextChanged(object sender, EventArgs e)
        {
            if (comboBoxStationCode.Items.Contains(comboBoxStationCode.Text))
            {
                errorProvider.SetError(comboBoxStationCode, "");
                if (ErroneousElements.Contains(comboBoxStationCode.Handle))
                {
                    ErroneousElements.Remove(comboBoxStationCode.Handle);
                }
                if (ErroneousElements.Count == 0)
                {
                    this.buttonOK.Enabled = true;
                }
            }
            else
            {
                errorProvider.SetError(comboBoxStationCode, "Invalid Station Code. Please select code from the dropdown list.");
                if (!ErroneousElements.Contains(comboBoxStationCode.Handle))
                {
                    ErroneousElements.Add(comboBoxStationCode.Handle);
                }
                this.buttonOK.Enabled = false;
            }
        }

        /// <summary>
        /// Check that max time between start and end times
        /// </summary>
        private void maskedTextBoxMaxTime_Validated(object sender, EventArgs e)
        {
            DateTime startTime, endTime, maxTime;

            // check if times are valid
            if ((DateTime.TryParseExact(this.maskedTextBoxStartTime.Text, "HH:mm", new CultureInfo(""), DateTimeStyles.NoCurrentDateDefault, out startTime)) &&
                (DateTime.TryParseExact(this.maskedTextBoxEndTime.Text, "HH:mm", new CultureInfo(""), DateTimeStyles.NoCurrentDateDefault, out endTime)) &&
                (DateTime.TryParseExact(this.maskedTextBoxMaxTime.Text, "HH:mm", new CultureInfo(""), DateTimeStyles.NoCurrentDateDefault, out maxTime)))
            {

                // max between start and end if end >= start (start and end are on the same day) OR max after start or before end if end < start (end is the day after)
                if (((endTime.CompareTo(startTime) >= 0) && (maxTime.CompareTo(startTime) >= 0) && (maxTime.CompareTo(endTime) <= 0)) ||
                     ((endTime.CompareTo(startTime) < 0) && !((maxTime.CompareTo(startTime) < 0) && (maxTime.CompareTo(endTime) > 0))))
                {
                    errorProvider.SetError(maskedTextBoxMaxTime, "");
                    if (ErroneousElements.Contains(maskedTextBoxMaxTime.Handle))
                    {
                        ErroneousElements.Remove(maskedTextBoxMaxTime.Handle);
                    }
                    if (ErroneousElements.Count == 0)
                    {
                        this.buttonOK.Enabled = true;
                    }

                }
                else
                {
                    errorProvider.SetError(maskedTextBoxMaxTime, "Please ensure that maximum event time between start event time and end event time.");
                    if (!ErroneousElements.Contains(maskedTextBoxMaxTime.Handle))
                    {
                        ErroneousElements.Add(maskedTextBoxMaxTime.Handle);
                    }
                    this.buttonOK.Enabled = false;

                }
            }
        }
        #endregion

        #region Events

        /// <summary>
        /// EventCreated Event
        /// </summary>

        public event EventHandler EventCreated;  // OK has been pressed with a dialog type AddEvent

        protected virtual void OnEventCreated(EventArgs e)
        {
            EventHandler handler = EventCreated;
            if (handler != null)
            {
                // Invokes the delegates. 
                handler(this, e);
            }
        }

        /// <summary>
        /// EventEdited Event
        /// </summary>

        public event EventHandler EventEdited;  // OK has been pressed with a dialog type EditEvent

        protected virtual void OnEventEdited(EventArgs e)
        {
            EventHandler handler = EventEdited;
            if (handler != null)
            {
                // Invokes the delegates. 
                handler(this, e);
            }
        }
        #endregion

        #region Button Handling Methods
        private void buttonOK_Click(object sender, EventArgs e)
        {
            // returns the event that corresponds to the dialog type
            if (this.eventDialogType == EventDialogType.AddEvent)
            {
                OnEventCreated(e);
            }
            else
            {
                OnEventEdited(e);
            }
            this.Hide();
        }

        private void buttonCancel_Click(object sender, EventArgs e)
        {
            this.Hide();
        }
        #endregion

        #region Importance Combobox automatic setting
        /// <summary>
        /// Ask for an update of the importance combobox automatic setting
        /// and a validation of the maxTime value
        /// </summary>
        private void maskedTextBoxStartTime_Validated(object sender, EventArgs e)
        {
            if (String.IsNullOrEmpty(errorProvider.GetError(maskedTextBoxEndTime)))
            {
                SetImportanceField();
            }

            // validate also maxTime value
            maskedTextBoxMaxTime_Validated(sender, e);
        }

        /// <summary>
        /// Ask for an update of the importance combobox automatic setting
        /// and a validation of the maxTime value
        /// </summary>
        private void maskedTextBoxEndTime_Validated(object sender, EventArgs e)
        {
            if (String.IsNullOrEmpty(errorProvider.GetError(maskedTextBoxStartTime)))
            {
                SetImportanceField();
            }

            // validate also maxTime value
            maskedTextBoxMaxTime_Validated(sender, e);
        }

        /// <summary>
        /// return the importance combobox index that corresponds to the time difference between end and start time
        /// returns -1 if time difference cannot be calculated
        /// </summary>
        private int GetEventImportanceIndex()
        {
            DateTime startTime, endTime;
            int ImportanceIndex = -1;

            // check if times are valid
            if ((DateTime.TryParseExact(this.maskedTextBoxStartTime.Text, "HH:mm", new CultureInfo(""), DateTimeStyles.NoCurrentDateDefault, out startTime)) &&
                (DateTime.TryParseExact(this.maskedTextBoxEndTime.Text, "HH:mm", new CultureInfo(""), DateTimeStyles.NoCurrentDateDefault, out endTime)))
            {
                // calculates the time difference and ensures it is positive
                TimeSpan deltaTime = endTime.Subtract(startTime);

                if (deltaTime.CompareTo(TimeSpan.Zero) < 0) // endTime is on the next day
                {
                    deltaTime = deltaTime.Add(TimeSpan.FromHours(24));
                }

                // sets the importance combobox value according to the time difference
                int deltaMins = (int)deltaTime.TotalMinutes;

                if (deltaMins < 19)
                {
                    ImportanceIndex = 0;
                }
                else if (deltaMins < 26)
                {
                    ImportanceIndex = 1;
                }
                else if (deltaMins < 33)
                {
                    ImportanceIndex = 2;
                }
                else if (deltaMins < 46)
                {
                    ImportanceIndex = 3;
                }
                else if (deltaMins < 86)
                {
                    ImportanceIndex = 4;
                }
                else if (deltaMins < 126)
                {
                    ImportanceIndex = 5;
                }
                else
                {
                    ImportanceIndex = 6;
                }

            }

            return ImportanceIndex;

        }

        /// <summary>
        /// sets the importance combobox value according to the time difference between end and start time
        /// </summary>
        private void SetImportanceField()
        {
            int ImportanceIndex = GetEventImportanceIndex();

            if ((ImportanceIndex >= 0) && (ImportanceIndex < comboBoxImportance.Items.Count))
            {
                comboBoxImportance.SelectedIndex = ImportanceIndex;
            }

        }
        #endregion

    }





}