//-------------------------------------------------------------------------------------
// SID Monitor - Utility for Sudden Ionospheric Disturbances Monitoring Stations
// Copyright (C) 2006 - 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.Generic;
using System.Globalization;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Text.RegularExpressions;
using WeifenLuo.WinFormsUI;


namespace SID_monitor
{
    public partial class NGCDReportGenerate : Form
    {
        // UI configuration deserialization method
        private DeserializeDockContent m_deserializeDockContent;

        // all dockable panels
        public OutputTextBoxDockablePanel outputTextBoxDockablePanel = new OutputTextBoxDockablePanel();
        public ViewerDockablePanel viewerDockablePanel = new ViewerDockablePanel();
        public SIDEventsViewerDockablePanel sidEventsViewerDockablePanel = new SIDEventsViewerDockablePanel();
        public EventDialogDockablePanel eventDialogDockablePanel = new EventDialogDockablePanel();
        public GenerateReportParametersDockablePanel generateReportParametersDockablePanel = new GenerateReportParametersDockablePanel();

        // global variables
        private static String[] NullStrings = new string[16] { String.Empty, String.Empty, String.Empty, String.Empty, String.Empty, String.Empty, String.Empty, String.Empty, String.Empty, String.Empty, String.Empty, String.Empty, String.Empty, String.Empty, String.Empty, String.Empty };


        private bool ReportSaved = false;

        public NGCDReportGenerate()
        {
            m_deserializeDockContent = new DeserializeDockContent(GetContentFromPersistString);

            InitializeComponent();

            // generateReportParametersDockablePanel
            this.generateReportParametersDockablePanel.GraphUpdateRequested += new System.EventHandler(this.GraphUpdateRequested);
            this.generateReportParametersDockablePanel.DatabaseFileError += new System.EventHandler(this.generateReportParametersDockablePanel_DatabaseFileError);
            this.generateReportParametersDockablePanel.ClearEventsSelectionRequested += new System.EventHandler(this.generateReportParametersDockablePanel_ClearEventsSelectionRequested);
            this.generateReportParametersDockablePanel.ClearEventsRequested += new System.EventHandler(this.generateReportParametersDockablePanel_ClearEventsRequested);
            this.generateReportParametersDockablePanel.LoadReportRequested += new System.EventHandler(this.generateReportParametersDockablePanel_LoadReportRequested);
            this.generateReportParametersDockablePanel.ReportFileError += new System.EventHandler(this.generateReportParametersDockablePanel_ReportFileError);
            this.generateReportParametersDockablePanel.AddOutputTextRequired += new GenerateReportParametersDockablePanel.AddOutputTextRequireEventHandler(this.generateReportParametersDockablePanel_AddOutputTextRequired);

            // sidEventsViewerDockablePanel
            this.sidEventsViewerDockablePanel.SelectionChanged += new System.EventHandler(this.sidEventsViewer_SelectionChanged);
            this.sidEventsViewerDockablePanel.DataModified += new System.EventHandler(this.sidEventsViewer_DataModified);
            this.sidEventsViewerDockablePanel.AddEventRequested += new System.EventHandler(this.sidEventsViewer_AddEventRequested);
            this.sidEventsViewerDockablePanel.EditEventRequested += new System.EventHandler(this.sidEventsViewer_EditEventRequested);
            this.sidEventsViewerDockablePanel.DeleteEventRequested += new System.EventHandler(this.sidEventsViewer_DeleteEventRequested);

            this.sidEventsViewerDockablePanel.AllowUserToAddRows = false;
            this.sidEventsViewerDockablePanel.ReadOnly = true;
            this.sidEventsViewerDockablePanel.EnableContextMenu = true;
            this.sidEventsViewerDockablePanel.RowHeadersVisible = true;
            this.sidEventsViewerDockablePanel.SelectionMode = DataGridViewSelectionMode.FullRowSelect;

            // viewerDockablePanel
            this.viewerDockablePanel.ShowHint = DockState.Document;
            this.viewerDockablePanel.GraphUpdateRequested += new System.EventHandler(this.GraphUpdateRequested);

            // eventDialogDockablePanel
            this.eventDialogDockablePanel.EventCreated += new System.EventHandler(this.addEventDlg_EventCreated);
            this.eventDialogDockablePanel.EventEdited += new System.EventHandler(this.editEventDlg_EventCreated);

            this.saveToolStripMenuItem.Enabled = false;
        }

        #region NGCDReportGenerate Methods
        /// <summary>
        /// Gets UI configuration
        /// </summary>
        private IDockContent GetContentFromPersistString(string persistString)
        {
            if (persistString == typeof(SIDEventsViewerDockablePanel).ToString())
                return sidEventsViewerDockablePanel;
            else if (persistString == typeof(GenerateReportParametersDockablePanel).ToString())
                return generateReportParametersDockablePanel;
            else if (persistString == typeof(ViewerDockablePanel).ToString())
                return viewerDockablePanel;
            else if (persistString == typeof(OutputTextBoxDockablePanel).ToString())
                return outputTextBoxDockablePanel;
            else if (persistString == typeof(EventDialogDockablePanel).ToString())
                return eventDialogDockablePanel;
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Default configuration of the panels
        /// </summary>
        private void SetDefaultUI()
        {
            try
            {
                // default configuration: all panels visible
                // viewerDockablePanel
                this.viewerDockablePanel.Show(this.dockPanel);

                // outputTextBoxDockablePanel
                this.outputTextBoxDockablePanel.Show(this.dockPanel);

                // sidEventsViewerDockablePanel
                this.sidEventsViewerDockablePanel.Show(this.dockPanel);

                // viewReportParametersDockablePanel
                this.generateReportParametersDockablePanel.Show(this.dockPanel);
            }
            catch
            {
                MessageBox.Show("User Interface internal error.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Ask user confirmation if close required when no report has been saved.
        /// </summary>
        private void NGCDReportGenerate_FormClosing(object sender, FormClosingEventArgs e)
        {
            if ((!ReportSaved) && (this.sidEventsViewerDockablePanel.Rows.Count > 0))
            {
                if (MessageBox.Show("Report(s) file not saved.\nConfirm Exiting?", "Confirm Report(s) Generation Cancellation", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button3) != DialogResult.Yes)
                {
                    e.Cancel = true;
                }
            }
            if (e.Cancel == false)
            {
                // save UI config
                string configFile = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), SID_monitor.Properties.Settings.Default.GenerateReportLayoutFile);
                dockPanel.SaveAsXml(configFile);
            }
        }

        private void NGCDReportGenerate_Load(object sender, EventArgs e)
        {
            
            // loads UI configuration
            string configFile = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), SID_monitor.Properties.Settings.Default.GenerateReportLayoutFile);
            if (File.Exists(configFile))
            {
                try
                {
                    dockPanel.LoadFromXml(configFile, m_deserializeDockContent);
                }
                catch
                {
                    SetDefaultUI();
                }
            }
            else
            {
                SetDefaultUI();
            }

            
        }
        #endregion

        #region sidEventsViewer Events Handling
        private void sidEventsViewer_DataModified(object sender, EventArgs e)
        {
            if (this.sidEventsViewerDockablePanel.Rows.Count > 0)
            {
                this.saveToolStripMenuItem.Enabled = true;
            }
            else
            {
                this.saveToolStripMenuItem.Enabled = false;
            }
            ReportSaved = false; // indicates that we need to save the report

        }
        #endregion

        #region Events Contextual Menu Events Handling
        #region Add SID Events Methods

        /// <summary>
        /// Handling of the "Add Event" button
        /// </summary>
        private void sidEventsViewer_AddEventRequested(object sender, EventArgs e)
        {
            this.eventDialogDockablePanel.DialogType = EventDialogDockablePanel.EventDialogType.AddEvent;

            this.eventDialogDockablePanel.Date = new DateTime(this.generateReportParametersDockablePanel.MonthReport.Year,
                                          this.generateReportParametersDockablePanel.MonthReport.Month,
                                          Convert.ToInt32(this.generateReportParametersDockablePanel.GraphDay));

            this.eventDialogDockablePanel.StationCodeItems = this.generateReportParametersDockablePanel.ChannelsDS;

            if (this.generateReportParametersDockablePanel.ChannelsDS.Length > 0)
            {
                this.eventDialogDockablePanel.StationCode = this.generateReportParametersDockablePanel.ChannelsDS[0];
            }

            this.eventDialogDockablePanel.ObserverCode = SID_monitor.Properties.Settings.Default.ObserverCode;

            this.eventDialogDockablePanel.Show(this.dockPanel);
        }

        /// <summary>
        /// Handles the event raised when OK has been pressed on the event dialog
        /// </summary>
        private void addEventDlg_EventCreated(object sender, EventArgs e)
        {
            // creates a new event row and adds it to the EventViewer table
            SIDEvents.DataTableEventsRow row = (SIDEvents.DataTableEventsRow)this.sidEventsViewerDockablePanel.SIDEventsDataTable.NewRow();

            row.Date = this.eventDialogDockablePanel.Date;
            row.StartTime = this.eventDialogDockablePanel.StartTime;
            row.StartQualifier = this.eventDialogDockablePanel.StartTimeQualifier;
            row.EndTime = this.eventDialogDockablePanel.EndTime;
            row.EndQualifier = this.eventDialogDockablePanel.EndTimeQualifier;
            row.MaxTime = this.eventDialogDockablePanel.MaxTime;
            row.MaxQualifier = this.eventDialogDockablePanel.MaxTimeQualifier;
            row.Importance = this.eventDialogDockablePanel.Importance;
            row.Definiteness = this.eventDialogDockablePanel.Definiteness;
            row.StationCode = this.eventDialogDockablePanel.StationCode;
            row.ObserverCode = this.eventDialogDockablePanel.ObserverCode;

            this.sidEventsViewerDockablePanel.SIDEventsDataTable.AddDataTableEventsRow(row);
        }
        #endregion

        #region Delete SID Events Methods
        /// <summary>
        /// Handling of the "Delete Events" button
        /// </summary>
        private void sidEventsViewer_DeleteEventRequested(object sender, EventArgs e)
        {
            if (this.sidEventsViewerDockablePanel.SelectedRows.Count > 0)
            {
                if (MessageBox.Show("Confirm Deletion of selected events?", "Event Deletion", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button3) == DialogResult.Yes)
                {
                    for (int i = 0; i < this.sidEventsViewerDockablePanel.SelectedRows.Count; i++)
                    {
                        DataRowView currentSelectedRow = (DataRowView)(this.sidEventsViewerDockablePanel.SelectedRows[i].DataBoundItem);
                        currentSelectedRow.Delete();
                    }
                }
            }
        }
        #endregion

        #region Edit SID Events Methods

        /// <summary>
        /// Handling of the "Edit Event" button
        /// </summary>
        private void sidEventsViewer_EditEventRequested(object sender, EventArgs e)
        {
            if (this.sidEventsViewerDockablePanel.SelectedRows.Count >= 1)
            {
                this.eventDialogDockablePanel.DialogType = EventDialogDockablePanel.EventDialogType.EditEvent;

                DataGridViewRow currentSelectedRow = this.sidEventsViewerDockablePanel.SelectedRows[0];

                this.eventDialogDockablePanel.Date = (DateTime)currentSelectedRow.Cells["Date"].Value;
                this.eventDialogDockablePanel.StartTime = (DateTime)currentSelectedRow.Cells["StartTime"].Value;
                this.eventDialogDockablePanel.EndTime = (DateTime)currentSelectedRow.Cells["EndTime"].Value;
                this.eventDialogDockablePanel.MaxTime = (DateTime)currentSelectedRow.Cells["MaxTime"].Value;
                this.eventDialogDockablePanel.StartTimeQualifier = (String)currentSelectedRow.Cells["StartQual"].Value;
                this.eventDialogDockablePanel.EndTimeQualifier = (String)currentSelectedRow.Cells["EndQual"].Value;
                this.eventDialogDockablePanel.MaxTimeQualifier = (String)currentSelectedRow.Cells["MaxQual"].Value;
                this.eventDialogDockablePanel.Importance = (String)currentSelectedRow.Cells["Importance"].Value;
                this.eventDialogDockablePanel.Definiteness = (String)currentSelectedRow.Cells["Definiteness"].Value;
                this.eventDialogDockablePanel.StationCodeItems = this.generateReportParametersDockablePanel.ChannelsDS;
                this.eventDialogDockablePanel.StationCode = (String)currentSelectedRow.Cells["StationCode"].Value;
                this.eventDialogDockablePanel.ObserverCode = (String)currentSelectedRow.Cells["ObserverCode"].Value;

                this.eventDialogDockablePanel.Show(this.dockPanel);
            }
        }

        /// <summary>
        /// Handles the event raised when OK has been pressed on the event dialog
        /// </summary>
        private void editEventDlg_EventCreated(object sender, EventArgs e)
        {
            if (this.sidEventsViewerDockablePanel.SelectedRows.Count >= 1)
            {
                DataGridViewRow currentSelectedRow = this.sidEventsViewerDockablePanel.SelectedRows[0];

                currentSelectedRow.Cells["Date"].Value = this.eventDialogDockablePanel.Date;
                currentSelectedRow.Cells["StartTime"].Value = this.eventDialogDockablePanel.StartTime;
                currentSelectedRow.Cells["EndTime"].Value = this.eventDialogDockablePanel.EndTime;
                currentSelectedRow.Cells["MaxTime"].Value = this.eventDialogDockablePanel.MaxTime;
                currentSelectedRow.Cells["StartQual"].Value = this.eventDialogDockablePanel.StartTimeQualifier;
                currentSelectedRow.Cells["EndQual"].Value = this.eventDialogDockablePanel.EndTimeQualifier;
                currentSelectedRow.Cells["MaxQual"].Value = this.eventDialogDockablePanel.MaxTimeQualifier;
                currentSelectedRow.Cells["Importance"].Value = this.eventDialogDockablePanel.Importance;
                currentSelectedRow.Cells["Definiteness"].Value = this.eventDialogDockablePanel.Definiteness;
                currentSelectedRow.Cells["StationCode"].Value = this.eventDialogDockablePanel.StationCode;
                currentSelectedRow.Cells["ObserverCode"].Value = this.eventDialogDockablePanel.ObserverCode;

            }
        }

        #endregion
        #endregion

        #region generateReportParametersDockablePanel Events Handling
        private void generateReportParametersDockablePanel_DatabaseFileError(object sender, EventArgs e)
        {
            // Clears the image
            this.viewerDockablePanel.Image = SID_monitor.Properties.Resources.no_image_available_300;
        }

        private void generateReportParametersDockablePanel_ClearEventsSelectionRequested(object sender, EventArgs e)
        {
            this.sidEventsViewerDockablePanel.ClearSelection();
        }

        private void generateReportParametersDockablePanel_ClearEventsRequested(object sender, EventArgs e)
        {
            if ((!ReportSaved) && (this.sidEventsViewerDockablePanel.Rows.Count > 0))
            {
                if (MessageBox.Show("Need to save report(s) file...", "Confirm Report(s) Generation", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                {
                    buttonSaveReport_Click(sender, e);
                }
            }
            // Clears the events list
            this.sidEventsViewerDockablePanel.SIDEventsDataTable.Clear();
        }

        private void generateReportParametersDockablePanel_LoadReportRequested(object sender, EventArgs e)
        {
            LoadReport(this.generateReportParametersDockablePanel.ReportFilename);
        }

        private void generateReportParametersDockablePanel_ReportFileError(object sender, EventArgs e)
        {
            // Clears the events list
            this.sidEventsViewerDockablePanel.ClearDataTable();

            // Clears the image
            this.viewerDockablePanel.Image = SID_monitor.Properties.Resources.no_image_available_300;
        }

        private void generateReportParametersDockablePanel_AddOutputTextRequired(object sender, GenerateReportParametersDockablePanel.AddOutputTextRequireEventArgs e)
        {
            switch (e.Category)
            {
                case OutputTextBox.OutputTextMessageCategory.Warning:
                    this.outputTextBoxDockablePanel.AddOutputTextWarningMessage(e.Msg);
                    break;
                case OutputTextBox.OutputTextMessageCategory.Error:
                    this.outputTextBoxDockablePanel.AddOutputTextErrorMessage(e.Msg);
                    break;
                case OutputTextBox.OutputTextMessageCategory.RRDToolError:
                    this.outputTextBoxDockablePanel.AddOutputTextRRDToolErrorMessage(e.Msg);
                    break;
                case OutputTextBox.OutputTextMessageCategory.RRDToolNormal:
                    this.outputTextBoxDockablePanel.AddOutputTextRRDToolMessage(e.Msg);
                    break;
                case OutputTextBox.OutputTextMessageCategory.Normal:
                default:
                    this.outputTextBoxDockablePanel.AddOutputTextMessage(e.Msg);
                    break;
            }

        }
        #endregion

        #region Graph Update Methods

        /// <summary>
        /// Updates the graph when a new day is selected or a new event is selected.
        /// </summary>
        private void GraphUpdateRequested(object sender, EventArgs e)
        {
            if (String.IsNullOrEmpty(this.generateReportParametersDockablePanel.TextBoxChannelsDatabaseFilename) || !File.Exists(Path.GetFullPath(this.generateReportParametersDockablePanel.TextBoxChannelsDatabaseFilename)))
            {
                this.viewerDockablePanel.Image = SID_monitor.Properties.Resources.no_image_available_300;
                return;
            }

            // defines the graph Date
            SIDMonitorDateTime GraphDate;
            if (this.sidEventsViewerDockablePanel.SelectedRows.Count == 0) // the selected date
            {
                GraphDate = new SIDMonitorDateTime(new DateTime(this.generateReportParametersDockablePanel.MonthReport.Year,
                                                                this.generateReportParametersDockablePanel.MonthReport.Month,
                                                                Convert.ToInt32(this.generateReportParametersDockablePanel.GraphDay)));
            }
            else // the date of the event
            {
                if (this.sidEventsViewerDockablePanel.SelectedRows[0].IsNewRow || this.sidEventsViewerDockablePanel.SelectedRows[0].Cells["Date"].Value.Equals(System.DBNull.Value) || this.sidEventsViewerDockablePanel.SelectedRows[0].Cells["StationCode"].Value.Equals(System.DBNull.Value))
                {
                    this.viewerDockablePanel.Image = SID_monitor.Properties.Resources.no_image_available_300;
                    return;
                }
                GraphDate = new SIDMonitorDateTime(Convert.ToDateTime(this.sidEventsViewerDockablePanel.SelectedRows[0].Cells["Date"].Value));
            }

            // defines the list of channels to show:
            // - for date change from the numeric up-down, as per the comboboxChannel
            // - the one from the event if row is selected.
            bool[] ChannelsToShow = new bool[16];
            if (this.sidEventsViewerDockablePanel.SelectedRows.Count == 0)
            {
                // display all Datasets in the database if comboboxChannel says "All", otherwise, only the specified channel
                for (int i = 0; i < this.generateReportParametersDockablePanel.ChannelsDS.Length; i++)
                {
                    if ((!string.IsNullOrEmpty(this.generateReportParametersDockablePanel.ChannelsDS[i])) && (String.Equals(this.generateReportParametersDockablePanel.ComboBoxChannelSelectedItem, GenerateReportParametersDockablePanel.allChannelsString) || (String.Equals(this.generateReportParametersDockablePanel.ComboBoxChannelSelectedItem, this.generateReportParametersDockablePanel.ChannelsDS[i]))))
                    {
                        ChannelsToShow[i] = true;
                    }
                    else
                    {
                        ChannelsToShow[i] = false;
                    }
                }
            }
            else
            {
                // check if the selected station code if present in the database
                for (int i = 0; i < this.generateReportParametersDockablePanel.ChannelsDS.Length; i++)
                {
                    if (!string.IsNullOrEmpty(this.generateReportParametersDockablePanel.ChannelsDS[i]) && String.Equals(this.generateReportParametersDockablePanel.ChannelsDS[i], (string)this.sidEventsViewerDockablePanel.SelectedRows[0].Cells["StationCode"].Value))
                    {
                        ChannelsToShow[i] = true;
                    }
                    else
                    {
                        ChannelsToShow[i] = false;
                    }
                }
            }
            if (Array.IndexOf(ChannelsToShow, true) < 0) // no channel to show
            {
                this.viewerDockablePanel.Image = SID_monitor.Properties.Resources.no_image_available_300;
                return;
            }

            // determines if the GOES data is to be displayed
            bool[] GOESToShow;
            string GOESfile = String.Empty;
            try
            {
                if (File.Exists(Path.GetFullPath(this.generateReportParametersDockablePanel.LabelGOESDatabaseFilename)))
                {
                    GOESfile = Path.GetFullPath(this.generateReportParametersDockablePanel.LabelGOESDatabaseFilename);
                    GOESToShow = new bool[3] { this.generateReportParametersDockablePanel.ShowGOES10Checked, this.generateReportParametersDockablePanel.ShowGOES11Checked, this.generateReportParametersDockablePanel.ShowGOES12Checked };
                }
                else
                {
                    GOESfile = String.Empty;
                    GOESToShow = new bool[3] { false, false, false };
                }
            }
            catch
            {
                GOESfile = String.Empty;
                GOESToShow = new bool[3] { false, false, false };
            }

            this.outputTextBoxDockablePanel.AddOutputTextMessage("Updating graph...\n");

            // displays the graph
            if (Path.Equals(Path.GetFullPath(this.generateReportParametersDockablePanel.TextBoxChannelsDatabaseFilename), Path.GetFullPath(SID_monitor.Properties.Settings.Default.RRDToolDatabase)))
            {   // associated database is current database
                this.viewerDockablePanel.GenerateGraph(Path.GetFullPath(this.generateReportParametersDockablePanel.TextBoxChannelsDatabaseFilename),
                                          GOESfile,
                                          GraphDate.Date.UnixTime.ToString(),
                                          GraphDate.AddDays(1).Date.UnixTime.ToString(),
                                          GraphDate.Date.WinTime.ToLongDateString(),
                                          this.generateReportParametersDockablePanel.ShowSunChecked,
                                          this.generateReportParametersDockablePanel.ShowForecastChecked,
                                          SID_monitor.Properties.Settings.ChannelStationCodes,
                                          SID_monitor.Properties.Settings.ChannelTitles,
                                          SID_monitor.Properties.Settings.ChannelLineWidths,
                                          SID_monitor.Properties.Settings.ChannelColors,
                                          SID_monitor.Properties.Settings.ChannelDev1Colors,
                                          SID_monitor.Properties.Settings.ChannelDev2Colors,
                                          SID_monitor.Properties.Settings.ChannelDev3Colors,
                                          ChannelsToShow,
                                          SID_monitor.Properties.Settings.GOESTitles,
                                          SID_monitor.Properties.Settings.GOESLineWidths,
                                          SID_monitor.Properties.Settings.GOESColors,
                                          GOESToShow);
            }
            else // associated database is not current database
            {
                this.viewerDockablePanel.GenerateGraph(Path.GetFullPath(this.generateReportParametersDockablePanel.TextBoxChannelsDatabaseFilename),
                                          GOESfile,
                                          GraphDate.Date.UnixTime.ToString(),
                                          GraphDate.AddDays(1).Date.UnixTime.ToString(),
                                          GraphDate.Date.WinTime.ToLongDateString(),
                                          this.generateReportParametersDockablePanel.ShowSunChecked,
                                          this.generateReportParametersDockablePanel.ShowForecastChecked,
                                          this.generateReportParametersDockablePanel.ChannelsDS,
                                          NullStrings,
                                          SID_monitor.Properties.Settings.ChannelLineWidths,
                                          SID_monitor.Properties.Settings.ChannelColors,
                                          SID_monitor.Properties.Settings.ChannelDev1Colors,
                                          SID_monitor.Properties.Settings.ChannelDev2Colors,
                                          SID_monitor.Properties.Settings.ChannelDev3Colors,
                                          ChannelsToShow,
                                          SID_monitor.Properties.Settings.GOESTitles,
                                          SID_monitor.Properties.Settings.GOESLineWidths,
                                          SID_monitor.Properties.Settings.GOESColors,
                                          GOESToShow);
            }
        }



        /// <summary>
        /// Updates the graph when event selection changes. Updates the edit window if raised.
        /// Updates the comboBox Channel selection
        /// </summary>
        private void sidEventsViewer_SelectionChanged(object sender, EventArgs e)
        {
            if ((this.sidEventsViewerDockablePanel.SelectedRows.Count > 0) && (!this.sidEventsViewerDockablePanel.SelectedRows[0].IsNewRow))
            {
                // we set the channelComboBox to hte selected event station code
                this.generateReportParametersDockablePanel.ComboBoxChannelSelectedItem = (string)this.sidEventsViewerDockablePanel.SelectedRows[0].Cells["StationCode"].Value;

                // we set the graph day to the selected event day
                this.generateReportParametersDockablePanel.GraphDay = ((DateTime)this.sidEventsViewerDockablePanel.SelectedRows[0].Cells["Date"].Value).Day;

                // we refresh the graph to display the plot that corresponds to the event day
                this.GraphUpdateRequested(sender, e);
            }
            if (!this.eventDialogDockablePanel.IsHidden)
            {
                sidEventsViewer_EditEventRequested(sender, e);
            }
        }
        #endregion

        #region Report Load File Methods
        /// <summary>
        /// Parse the given report file and:
        /// - fills in the event list
        /// - fills in the associated databases names
        /// </summary>
        private void LoadReport(String filename)
        {
            try
            {
                // read file
                String ReportText = File.ReadAllText(filename, Encoding.ASCII);
                this.outputTextBoxDockablePanel.AddOutputTextMessage(" Reading report file \"" + filename + "\"\n");


                // search for the date of the report
                Regex DateRegEx = new Regex("^\\s*Date:\\s*(?<Month>\\d\\d)/(?<Year>\\d\\d)\\s*$",
                              RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Multiline);

                Match DateMatch = DateRegEx.Match(ReportText);

                if (!DateMatch.Success)
                {
                    this.outputTextBoxDockablePanel.AddOutputTextErrorMessage(" Wrong report file format \"" + Path.GetFullPath(filename) + "\"\n");
                    return;
                }


                // search for the channels database name
                Regex DatabaseRegEx = new Regex("^\\s*Database:\\s*(?<File>.+)\\s*$",
                              RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Multiline);

                Match DatabaseMatch = DatabaseRegEx.Match(ReportText);

                if (!DatabaseMatch.Success)
                {
                    this.outputTextBoxDockablePanel.AddOutputTextWarningMessage(" Wrong report file format \"" + Path.GetFullPath(filename) + "\". No Channels Database field.\n");
                }
                // fills in the associated database name and array of datasets
                if (!String.IsNullOrEmpty(GetChannelsDatabaseName(DatabaseMatch.Groups["File"].Value, DateMatch.Groups["Month"].Value, DateMatch.Groups["Year"].Value)))
                {
                    this.generateReportParametersDockablePanel.TextBoxChannelsDatabaseFilename = Path.GetFullPath(DatabaseMatch.Groups["File"].Value);
                    this.generateReportParametersDockablePanel.ShowSunEnabled = true;
                    this.generateReportParametersDockablePanel.ShowForecastEnabled = true;
                    this.generateReportParametersDockablePanel.ComboBoxChannelEnabled = true;
                    this.generateReportParametersDockablePanel.ChannelsDS = NGDCReportView.GetDatasetsFromRRDToolDatabase(this.generateReportParametersDockablePanel.TextBoxChannelsDatabaseFilename, this.outputTextBoxDockablePanel.Handle);
                }
                else
                {
                    this.generateReportParametersDockablePanel.TextBoxChannelsDatabaseFilename = "No associated database file! ";
                    this.generateReportParametersDockablePanel.ShowSunEnabled = false;
                    this.generateReportParametersDockablePanel.ShowForecastEnabled = false;
                    this.generateReportParametersDockablePanel.ComboBoxChannelEnabled = false;
                    for (int i = 0; i < this.generateReportParametersDockablePanel.ChannelsDS.Length; i++)
                    {
                        this.generateReportParametersDockablePanel.ChannelsDS[i] = String.Empty;
                    }

                }

                // search for the GOES database name
                Regex GOESDatabaseRegEx = new Regex("^\\s*GOES\\s+Database:\\s*(?<File>.+)\\s*$",
                              RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Multiline);

                Match GOESDatabaseMatch = GOESDatabaseRegEx.Match(ReportText);

                if (!GOESDatabaseMatch.Success)
                {
                    this.outputTextBoxDockablePanel.AddOutputTextWarningMessage(" Wrong report file format. \"" + Path.GetFullPath(filename) + "\". No GOES database field.\n");
                }

                // fills in the associated GOES database name
                if (!String.IsNullOrEmpty(GetGOESDatabaseName(GOESDatabaseMatch.Groups["File"].Value, DateMatch.Groups["Month"].Value, DateMatch.Groups["Year"].Value)))
                {
                    this.generateReportParametersDockablePanel.LabelGOESDatabaseFilename = Path.GetFullPath(GOESDatabaseMatch.Groups["File"].Value);
                    this.generateReportParametersDockablePanel.ShowGOES10Enabled = true;
                    this.generateReportParametersDockablePanel.ShowGOES12Enabled = true;
                }
                else
                {
                    this.generateReportParametersDockablePanel.LabelGOESDatabaseFilename = "No associated GOES database file!";
                    this.generateReportParametersDockablePanel.ShowGOES10Enabled = false;
                    this.generateReportParametersDockablePanel.ShowGOES12Enabled = false;
                }


                // search for events
                Regex EventRegEx = new Regex("^40\\s+(?<Year>\\d\\d)(?<Month>\\d\\d)(?<Day>\\d\\d)\\s+(?<StartHour>\\d\\d)(?<StartMin>\\d\\d)(?<StartQual>[ DEU])(?<EndHour>\\d\\d)(?<EndMin>\\d\\d)(?<EndQual>[ DEU])(?<MaxHour>\\d\\d)(?<MaxMin>\\d\\d)(?<MaxQual>[ DEU])\\s+(?<Importance>1-|1[ ]|1\\+|2[ ]|2\\+|3[ ]|3\\+)\\s+(?<Definiteness>[012345])(?<StationCode>[a-zA-Z]{2}\\d{2})\\s+(?<ObsCode>[^\\s]{3,}).*$",
                                              RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Multiline);

                Match m;
                int nbMatches = 0; // events counter

                // Clears the events list
                this.sidEventsViewerDockablePanel.ClearDataTable();

                // fills in the events list for each event found in the report
                for (m = EventRegEx.Match(ReportText); m.Success; m = m.NextMatch())
                {
                    nbMatches++;

                    SIDEvents.DataTableEventsRow row = (SIDEvents.DataTableEventsRow)this.sidEventsViewerDockablePanel.NewRow();

                    row.Date = DateTime.ParseExact(m.Groups["Day"].Value + "/" + m.Groups["Month"].Value + "/" + m.Groups["Year"].Value, "dd/MM/yy", DateTimeFormatInfo.InvariantInfo).Date;

                    row.StartTime = row.Date.AddHours(Convert.ToInt32(m.Groups["StartHour"].Value)).AddMinutes(Convert.ToInt32(m.Groups["StartMin"].Value));
                    switch (m.Groups["StartQual"].Value)
                    {
                        case " ":
                            row.StartQualifier = "None";
                            break;
                        case "D":
                            row.StartQualifier = "After (D)";
                            break;
                        case "E":
                            row.StartQualifier = "Before (E)";
                            break;
                        case "U":
                            row.StartQualifier = "Uncertain (U)";
                            break;
                        default:
                            throw (new Exception("Invalid Start Time qualifier (" + m.Groups["StartQual"].Value + ")\n"));
                    }
                    // if endtime time is less than starttime, it is on the next day
                    DateTime endTime = row.Date.AddHours(Convert.ToInt32(m.Groups["EndHour"].Value)).AddMinutes(Convert.ToInt32(m.Groups["EndMin"].Value));
                    if (DateTime.Compare(row.StartTime, endTime) < 0)
                    {
                        endTime.AddDays(1);
                    }
                    row.EndTime = endTime;
                    switch (m.Groups["EndQual"].Value)
                    {
                        case " ":
                            row.EndQualifier = "None";
                            break;
                        case "D":
                            row.EndQualifier = "After (D)";
                            break;
                        case "E":
                            row.EndQualifier = "Before (E)";
                            break;
                        case "U":
                            row.EndQualifier = "Uncertain (U)";
                            break;
                        default:
                            throw (new Exception("Invalid End Time qualifier (" + m.Groups["StartQual"].Value + ")\n"));
                    }

                    // if maxtime time is less than maxtime, it is on the next day
                    DateTime maxTime = row.Date.AddHours(Convert.ToInt32(m.Groups["MaxHour"].Value)).AddMinutes(Convert.ToInt32(m.Groups["MaxMin"].Value));
                    if (DateTime.Compare(row.StartTime, maxTime) < 0)
                    {
                        maxTime.AddDays(1);
                    }
                    row.MaxTime = maxTime;
                    switch (m.Groups["MaxQual"].Value)
                    {
                        case " ":
                            row.MaxQualifier = "None";
                            break;
                        case "D":
                            row.MaxQualifier = "After (D)";
                            break;
                        case "E":
                            row.MaxQualifier = "Before (E)";
                            break;
                        case "U":
                            row.MaxQualifier = "Uncertain (U)";
                            break;
                        default:
                            throw (new Exception("Invalid Maximum Time qualifier (" + m.Groups["StartQual"].Value + ")\n"));
                    }

                    switch (m.Groups["Importance"].Value)
                    {
                        case "1-":
                            row.Importance = "1- (< 19 mn)";
                            break;
                        case "1 ":
                            row.Importance = "1 (19-25mn)";
                            break;
                        case "1+":
                            row.Importance = "1+ (26-32mn)";
                            break;
                        case "2 ":
                            row.Importance = "2 (33-45mn)";
                            break;
                        case "2+":
                            row.Importance = "2+ (46-85mn)";
                            break;
                        case "3 ":
                            row.Importance = "3 (86-125mn)";
                            break;
                        case "3+":
                            row.Importance = "3+ (>125mn)";
                            break;
                        default:
                            throw (new Exception("Invalid Importance Parameter (" + m.Groups["Importance"].Value + ")\n"));
                    }

                    switch (m.Groups["Definiteness"].Value)
                    {
                        case "0":
                            row.Definiteness = "0 (Questionable)";
                            break;
                        case "1":
                            row.Definiteness = "1 (Possible)";
                            break;
                        case "2":
                            row.Definiteness = "2 (Fair)";
                            break;
                        case "3":
                            row.Definiteness = "3 (Reasonable)";
                            break;
                        case "4":
                            row.Definiteness = "4 (Reasonably Definite)";
                            break;
                        case "5":
                            row.Definiteness = "5 (Definite)";
                            break;
                        default:
                            throw (new Exception("Invalid Definiteness Parameter (" + m.Groups["Definiteness"].Value + ")\n"));
                    }

                    row.StationCode = m.Groups["StationCode"].Value;

                    row.ObserverCode = m.Groups["ObsCode"].Value;


                    // add the new event to the datagrid
                    this.sidEventsViewerDockablePanel.AddDataTableEventsRow(row);

                }

                ReportSaved = true; // we just load the report file. No need to save it now

                if (nbMatches > 1)
                {
                    this.outputTextBoxDockablePanel.AddOutputTextMessage(" Found " + nbMatches.ToString() + " events in report \"" + Path.GetFullPath(filename) + "\"\n");
                }
                else
                {
                    this.outputTextBoxDockablePanel.AddOutputTextMessage(" Found " + nbMatches.ToString() + " event in report \"" + Path.GetFullPath(filename) + "\"\n");
                }

            }
            catch (Exception ex)
            {
                this.outputTextBoxDockablePanel.AddOutputTextErrorMessage(" Cannot parse report file \"" + filename +
                         "\"\n*** " + ex.ToString().Split('\n')[0] + "\n");
            }

        }


        /// <summary>
        /// Tries to guess the channels database name associated with the report file.
        /// The following filenames are used:
        /// - the one from the report, as supplied in the filename variable
        /// - the file sid.MMYY.rrd where sid is the default filename obtained from the settings. MM and YY are obtained from the variables monthe and year.
        /// - the fie sid.rrd
        /// </summary>
        /// <returns>an existing filename or string.empty if none found</returns>
        private string GetChannelsDatabaseName(string filename, string month, string year)
        {
            String currentFilename;
            try // try with the filename supplied in the report file
            {
                currentFilename = Path.GetFullPath(filename);
                if (File.Exists(currentFilename))
                {
                    return currentFilename;
                }
            }
            catch
            {
            }
            try // try with the file sid.MMYY.rrd
            {
                currentFilename = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(filename), SID_monitor.Properties.Settings.Default.RRDToolChannelsSaveFilename + "." + month + year + ".rrd"));
                if (File.Exists(currentFilename))
                {
                    return currentFilename;
                }
            }
            catch
            {
            }
            try // try with the file sid.rrd
            {
                currentFilename = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(filename), SID_monitor.Properties.Settings.Default.RRDToolChannelsSaveFilename + ".rrd"));
                if (File.Exists(currentFilename))
                {
                    return currentFilename;
                }
            }
            catch
            {
            }
            return String.Empty;

        }

        /// <summary>
        /// Tries to guess the GOES database name associated with the report file.
        /// The following filenames are used:
        /// - the one from the report, as supplied in the filename variable
        /// - the file goes.MMYY.rrd where goes is the default filename obtained from the settings. MM and YY are obtained from the variables monthe and year.
        /// - the fie goes.rrd
        /// </summary>
        /// <returns>an existing filename or string.empty if none found</returns>
        private string GetGOESDatabaseName(string filename, string month, string year)
        {
            String currentFilename;
            try // try with the filename supplied in the report file
            {
                currentFilename = Path.GetFullPath(filename);
                if (File.Exists(currentFilename))
                {
                    return currentFilename;
                }
            }
            catch
            {
            }
            try // try with the file sid.MMYY.rrd
            {
                currentFilename = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(filename), SID_monitor.Properties.Settings.Default.RRDToolGOESSaveFilename + "." + month + year + ".rrd"));
                if (File.Exists(currentFilename))
                {
                    return currentFilename;
                }
            }
            catch
            {
            }
            try // try with the file sid.rrd
            {
                currentFilename = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(filename), SID_monitor.Properties.Settings.Default.RRDToolGOESSaveFilename + ".rrd"));
                if (File.Exists(currentFilename))
                {
                    return currentFilename;
                }
            }
            catch
            {
            }
            return String.Empty;

        }
        #endregion

        #region Report Generation Methods
        /// <summary>
        /// Generates an empty report file corresponding to the given Station Code.
        /// Only headers are present
        /// </summary>
        private String GenerateEmptyReport(string stationCode)
        {
            String ReportText = String.Empty;

            ReportText += "AAVSO Sudden Ionospheric Disturbance Report" + Environment.NewLine;
            ReportText += "Observer: " + SID_monitor.Properties.Settings.Default.ObserverCode + Environment.NewLine;
            ReportText += "Station: " + stationCode + Environment.NewLine;
            ReportText += "Database: " + Path.GetFileName(this.generateReportParametersDockablePanel.TextBoxChannelsDatabaseFilename) + Environment.NewLine;
            ReportText += "GOES Database: " + Path.GetFileName(this.generateReportParametersDockablePanel.LabelGOESDatabaseFilename) + Environment.NewLine;
            ReportText += "Date: " + this.generateReportParametersDockablePanel.MonthReport.ToString("MM/yy") + Environment.NewLine + Environment.NewLine;

            ReportText += "-- end report --" + Environment.NewLine;

            return ReportText;
        }

        /// <summary>
        /// Generates the report file corresponding to the given Station Code
        /// </summary>
        private String GenerateReport(string stationCode)
        {

            // Column  Description
            // 1-2     Data code; always 40
            // 3-5     Blank
            // 6-7     Year
            // 8-9     Month
            // 10-11   Day
            // 12-13   Blank
            // 14-17   Start time; UT hours and minutes event began
            // 18      Start time qualifier; D = after, E = before, U = uncertain
            // 19-22   End time; UT hours and minutes event ended
            // 23      End time qualifier; D, E, U
            // 24-27   Maximum time; UT hours and minutes of event maximum
            // 28      Maximum time qualifier; D, E, U
            // 29-44   Blank
            // 45-46   SID Importance; sign in column 46 (1 1- 1+ 2 2+ 3 3+)
            // 47-50   Blank
            // 51      Definiteness (0 1 2 3 4 5)
            // 52-55   Code for monitored transmitter. The field consists of the final two station call letters and the two numbers which represent the frequency (kHz). The latter is rounded to the nearest integer. Example; the code for NSS at 21.4 kHz is recorded as SS21  
            // 56-69   Blank  
            // 70-72   Observer code; Example A82  

            // Duration (mn)    Importance 
            // < 19             1- 
            // 19-25            1 
            // 26-32            1+ 
            // 33-45            2 
            // 46-85            2+ 
            // 86-125           3 
            // >125             3+ 

            // Confidence           Definition 
            // Questionable         0 
            // Possible             1 
            // Fair                 2 
            // Reasonable           3 
            // Reasonably Definite  4 
            // Definite             5 

            int NbEvents = 0;

            String ReportText = String.Empty;


            ReportText += "AAVSO Sudden Ionospheric Disturbance Report" + Environment.NewLine;
            ReportText += "Observer: " + SID_monitor.Properties.Settings.Default.ObserverCode + Environment.NewLine;
            ReportText += "Station: " + stationCode + Environment.NewLine;
            ReportText += "Database: " + Path.GetFileName(this.generateReportParametersDockablePanel.TextBoxChannelsDatabaseFilename) + Environment.NewLine;
            ReportText += "GOES Database: " + Path.GetFileName(this.generateReportParametersDockablePanel.LabelGOESDatabaseFilename) + Environment.NewLine;
            ReportText += "Date: " + this.generateReportParametersDockablePanel.MonthReport.ToString("MM/yy") + Environment.NewLine + Environment.NewLine;

            foreach (SIDEvents.DataTableEventsRow row in this.sidEventsViewerDockablePanel.SIDEventsDataTable.Rows)
            {
                if (String.Compare(row.StationCode, stationCode, true) == 0)
                {
                    NbEvents++;

                    // 1-5         12345
                    ReportText += "40   ";

                    // 6-13                          67890123
                    ReportText += row.Date.ToString("yyMMdd  ");

                    // 14-17                              4567
                    ReportText += row.StartTime.ToString("HHmm");

                    // 18
                    switch (row.StartQualifier)
                    {
                        case "After (D)":
                            ReportText += "D";
                            break;
                        case "Before (E)":
                            ReportText += "E";
                            break;
                        case "Uncertain (U)":
                            ReportText += "U";
                            break;
                        case "None":
                        default:
                            ReportText += " ";
                            break;
                    }

                    // 19-22                            9012
                    ReportText += row.EndTime.ToString("HHmm");

                    // 23
                    switch (row.EndQualifier)
                    {
                        case "After (D)":
                            ReportText += "D";
                            break;
                        case "Before (E)":
                            ReportText += "E";
                            break;
                        case "Uncertain (U)":
                            ReportText += "U";
                            break;
                        case "None":
                        default:
                            ReportText += " ";
                            break;
                    }

                    // 24-27                            4567
                    ReportText += row.MaxTime.ToString("HHmm");

                    // 28
                    switch (row.MaxQualifier)
                    {
                        case "After (D)":
                            ReportText += "D";
                            break;
                        case "Before (E)":
                            ReportText += "E";
                            break;
                        case "Uncertain (U)":
                            ReportText += "U";
                            break;
                        case "None":
                        default:
                            ReportText += " ";
                            break;
                    }

                    //             23         4
                    // 29-44       9012345678901234
                    ReportText += "                ";

                    // 45-46
                    switch (row.Importance)
                    {
                        case "1- (< 19 mn)":
                        default:
                            ReportText += "1-";
                            break;
                        case "1 (19-25mn)":
                            ReportText += "1 ";
                            break;
                        case "1+ (26-32mn)":
                            ReportText += "1+";
                            break;
                        case "2 (33-45mn)":
                            ReportText += "2 ";
                            break;
                        case "2+ (46-85mn)":
                            ReportText += "2+";
                            break;
                        case "3 (86-125mn)":
                            ReportText += "3 ";
                            break;
                        case "3+ (>125mn)":
                            ReportText += "3+";
                            break;
                    }

                    //             4  5
                    // 47-50       7890
                    ReportText += "    ";

                    // 51
                    switch (row.Definiteness)
                    {
                        case "0 (Questionable)":
                        default:
                            ReportText += "0";
                            break;
                        case "1 (Possible)":
                            ReportText += "1";
                            break;
                        case "2 (Fair)":
                            ReportText += "2";
                            break;
                        case "3 (Reasonable)":
                            ReportText += "3";
                            break;
                        case "4 (Reasonably Definite)":
                            ReportText += "4";
                            break;
                        case "5 (Definite)":
                            ReportText += "5";
                            break;
                    }


                    // 52-55
                    ReportText += row.StationCode;

                    //             5   6
                    // 56-69       67890123456789
                    ReportText += "              ";

                    // 70-72
                    ReportText += row.ObserverCode;

                    ReportText += Environment.NewLine + Environment.NewLine;
                }
            }

            ReportText += "-- end report --" + Environment.NewLine;

            if (NbEvents > 0)
            {
                return ReportText;
            }
            else
            {
                return String.Empty;
            }
        }
        #endregion

        #region File Menu
        private void openDatabaseToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.generateReportParametersDockablePanel.radioButtonDatabase.Checked = true;
            this.generateReportParametersDockablePanel.buttonOpenDatabase_Click(sender, e);
        }

        private void openReportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.generateReportParametersDockablePanel.radioButtonSelectExistingReport.Checked = true;
            this.generateReportParametersDockablePanel.buttonSelectReport_Click(sender, e);
        }

        private void buttonSaveEmptyReport_Click(object sender, EventArgs e)
        {
            foreach (string station in this.generateReportParametersDockablePanel.ChannelsDS)
            {
                if (!String.IsNullOrEmpty(station))
                {
                    if (String.IsNullOrEmpty(GenerateReport(station)))  // the normal report would be empty, we create an "empty" one with headers only and save it
                    {
                        String ReportText = GenerateEmptyReport(station);

                        if (!String.IsNullOrEmpty(ReportText))
                        {

                            // Determine the filename of the report
                            String reportFilename = SID_monitor.Properties.Settings.Default.ObserverCode + station + ".dat";
                            String reportPath = Path.GetFullPath(Path.Combine(SID_monitor.Properties.Settings.Default.HistoryDatabaseFolder, this.generateReportParametersDockablePanel.MonthReport.ToString("MMyy")));

                            if (!Directory.Exists(reportPath))
                            {
                                try
                                {
                                    Directory.CreateDirectory(reportPath);
                                }
                                catch (Exception ex)
                                {
                                    this.outputTextBoxDockablePanel.AddOutputTextErrorMessage(" Cannot create directory \"" + reportPath +
                                             "\"\n*** " + ex.ToString().Split('\n')[0] + "\n");
                                    break;
                                }
                            }

                            this.saveFileDialog.InitialDirectory = reportPath;
                            this.saveFileDialog.Title = "Select Report Filename for station " + station;
                            this.saveFileDialog.FileName = reportFilename;

                            if (this.saveFileDialog.ShowDialog() == DialogResult.OK)
                            {
                                try
                                {
                                    File.WriteAllText(this.saveFileDialog.FileName, ReportText, Encoding.ASCII);
                                    this.outputTextBoxDockablePanel.AddOutputTextMessage(" Saving report file \"" + this.saveFileDialog.FileName + "\" with NO event.\n");
                                }
                                catch (Exception ex)
                                {
                                    this.outputTextBoxDockablePanel.AddOutputTextErrorMessage(" Cannot save report file \"" + this.saveFileDialog.FileName +
                                             "\"\n*** " + ex.ToString().Split('\n')[0] + "\n");
                                }

                            }
                        }
                    }
                }
            }
        }

        private void buttonSaveReport_Click(object sender, EventArgs e)
        {

            foreach (string station in this.generateReportParametersDockablePanel.ChannelsDS)
            {
                if (!String.IsNullOrEmpty(station))
                {
                    String ReportText = GenerateReport(station);

                    if (!String.IsNullOrEmpty(ReportText))
                    {

                        // Determine the filename of the report
                        String reportFilename = SID_monitor.Properties.Settings.Default.ObserverCode + station + ".dat";
                        String reportPath = Path.GetFullPath(Path.Combine(SID_monitor.Properties.Settings.Default.HistoryDatabaseFolder, this.generateReportParametersDockablePanel.MonthReport.ToString("MMyy")));

                        if (!Directory.Exists(reportPath))
                        {
                            try
                            {
                                Directory.CreateDirectory(reportPath);
                            }
                            catch (Exception ex)
                            {
                                this.outputTextBoxDockablePanel.AddOutputTextErrorMessage(" Cannot create directory \"" + reportPath +
                                         "\"\n*** " + ex.ToString().Split('\n')[0] + "\n");
                                break;
                            }
                        }

                        this.saveFileDialog.InitialDirectory = reportPath;
                        this.saveFileDialog.Title = "Select Report Filename for station " + station;
                        this.saveFileDialog.FileName = reportFilename;

                        if (this.saveFileDialog.ShowDialog() == DialogResult.OK)
                        {
                            try
                            {
                                File.WriteAllText(this.saveFileDialog.FileName, ReportText, Encoding.ASCII);
                                this.outputTextBoxDockablePanel.AddOutputTextMessage(" Saving report file \"" + this.saveFileDialog.FileName + "\"\n");
                            }
                            catch (Exception ex)
                            {
                                this.outputTextBoxDockablePanel.AddOutputTextErrorMessage(" Cannot save report file \"" + this.saveFileDialog.FileName +
                                         "\"\n*** " + ex.ToString().Split('\n')[0] + "\n");
                            }

                            // saves each image file for the given station
                            foreach (SIDEvents.DataTableEventsRow row in this.sidEventsViewerDockablePanel.SIDEventsDataTable.Rows)
                            {
                                if (String.Compare(row.StationCode, station, true) == 0)
                                {
                                    SIDMonitorDateTime GraphDate = new SIDMonitorDateTime(row.Date);

                                    // defines the list of channels to show:  the one from the event is row.
                                    bool[] ChannelsToShow = new bool[16];
                                    // check if the selected station code if present in the database
                                    for (int i = 0; i < this.generateReportParametersDockablePanel.ChannelsDS.Length; i++)
                                    {
                                        if (!string.IsNullOrEmpty(this.generateReportParametersDockablePanel.ChannelsDS[i]) && String.Equals(this.generateReportParametersDockablePanel.ChannelsDS[i], station))
                                        {
                                            ChannelsToShow[i] = true;
                                        }
                                        else
                                        {
                                            ChannelsToShow[i] = false;
                                        }
                                    }

                                    if (Array.IndexOf(ChannelsToShow, true) < 0) // no channel to show -- should never happen...
                                    {
                                        break;
                                    }

                                    // determines if the GOES data is to be displayed
                                    bool[] GOESToShow;
                                    string GOESfile = String.Empty;
                                    try
                                    {
                                        if (File.Exists(Path.GetFullPath(this.generateReportParametersDockablePanel.LabelGOESDatabaseFilename)))
                                        {
                                            GOESfile = Path.GetFullPath(this.generateReportParametersDockablePanel.LabelGOESDatabaseFilename);
                                            GOESToShow = new bool[3] { this.generateReportParametersDockablePanel.ShowGOES10Checked, this.generateReportParametersDockablePanel.ShowGOES11Checked, this.generateReportParametersDockablePanel.ShowGOES12Checked };
                                        }
                                        else
                                        {
                                            GOESfile = String.Empty;
                                            GOESToShow = new bool[3] { false, false, false };
                                        }
                                    }
                                    catch
                                    {
                                        GOESfile = String.Empty;
                                        GOESToShow = new bool[3] { false, false, false };
                                    }

                                    String ImageFile = this.viewerDockablePanel.GenerateGraphFile(Path.GetFullPath(this.generateReportParametersDockablePanel.TextBoxChannelsDatabaseFilename),
                                                                                     GOESfile,
                                                                                     GraphDate.Date.UnixTime.ToString(),
                                                                                     GraphDate.AddDays(1).Date.UnixTime.ToString(),
                                                                                     GraphDate.Date.WinTime.ToLongDateString(),
                                                                                     this.generateReportParametersDockablePanel.ShowSunChecked,
                                                                                     this.generateReportParametersDockablePanel.ShowForecastChecked,
                                                                                     this.generateReportParametersDockablePanel.ChannelsDS,
                                                                                     NullStrings,
                                                                                     SID_monitor.Properties.Settings.ChannelLineWidths,
                                                                                     SID_monitor.Properties.Settings.ChannelColors,
                                                                                     SID_monitor.Properties.Settings.ChannelDev1Colors,
                                                                                     SID_monitor.Properties.Settings.ChannelDev2Colors,
                                                                                     SID_monitor.Properties.Settings.ChannelDev3Colors,
                                                                                     ChannelsToShow,
                                                                  SID_monitor.Properties.Settings.GOESTitles,
                                                                  SID_monitor.Properties.Settings.GOESLineWidths,
                                                                  SID_monitor.Properties.Settings.GOESColors,
                                                                  GOESToShow);

                                    // Determine the filename of the image
                                    String DestImageFilename = Path.Combine(reportPath, SID_monitor.Properties.Settings.Default.ObserverCode + station + "_" + GraphDate.WinTime.ToString("dd") + ".png");

                                    try
                                    {
                                        // Copy the image file to report folder
                                        File.Move(ImageFile, DestImageFilename);
                                        this.outputTextBoxDockablePanel.AddOutputTextMessage(" Saving image file \"" + DestImageFilename + "\"\n");
                                    }
                                    catch (Exception ex)
                                    {
                                        this.outputTextBoxDockablePanel.AddOutputTextErrorMessage(" Cannot save image file \"" + DestImageFilename +
                                                "\"\n*** " + ex.ToString().Split('\n')[0] + "\n");
                                    }
                                }
                            }
                        }
                    }
                }
            }
            ReportSaved = true;
        }

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

        #region View Menu
        private void reportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!this.generateReportParametersDockablePanel.IsDisposed)
            {
                this.generateReportParametersDockablePanel.Show(this.dockPanel);
                this.generateReportParametersDockablePanel.PanelPane.Activate();
            }
        }

        private void eventsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!this.sidEventsViewerDockablePanel.IsDisposed)
            {
                this.sidEventsViewerDockablePanel.Show(this.dockPanel);
                this.sidEventsViewerDockablePanel.PanelPane.Activate();
            }
        }

        private void graphToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!this.viewerDockablePanel.IsDisposed)
            {
                this.viewerDockablePanel.Show(this.dockPanel);
                this.viewerDockablePanel.PanelPane.Activate();
            }
        }

        private void outputToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!this.outputTextBoxDockablePanel.IsDisposed)
            {
                this.outputTextBoxDockablePanel.Show(this.dockPanel);
                this.outputTextBoxDockablePanel.PanelPane.Activate();
            }
        }
        #endregion

        #region Edit Menu
        private void addEventToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.sidEventsViewer_AddEventRequested(sender, e);
        }

        private void editEventToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.sidEventsViewer_EditEventRequested(sender, e);

        }

        private void deleteEventToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.sidEventsViewer_DeleteEventRequested(sender, e);
        }

        private void editToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            // take care to ensure consistency with contextMenuStripEvents_Opening() method in SIDEventsViewer.cs
            if (this.sidEventsViewerDockablePanel.SelectedRows.Count > 0)
            {
                deleteEventToolStripMenuItem.Enabled = true;
            }
            else
            {
                deleteEventToolStripMenuItem.Enabled = false;
            }

            if (this.sidEventsViewerDockablePanel.SelectedRows.Count == 1)
            {
                editEventToolStripMenuItem.Enabled = true;
            }
            else
            {
                editEventToolStripMenuItem.Enabled = false;
            }
        }
        #endregion

        #region Help Menu
        private void contentsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Help.ShowHelp(this, this.helpProvider.HelpNamespace, HelpNavigator.Topic, "generate_report.htm");
        }

        private void indexToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Help.ShowHelpIndex(this, this.helpProvider.HelpNamespace);
        }

        private void searchToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Help.ShowHelp(this, this.helpProvider.HelpNamespace, HelpNavigator.Find, "");
        }
        #endregion 


    }
}