#region << Using Directives >>
using System;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using Volpe.Cafe.Model;
using Volpe.Cafe.EspressoUI.LegacyControls.Panels;
using Volpe.Cafe.EspressoUI.Utils;
#endregion

namespace Volpe.Cafe.EspressoUI.LegacyControls
{
    /// <summary>
    /// Provides a graphical user interface (GUI) for configuring CAFE Model modeling settings.
    /// </summary>
    public class ManageModelingSettings : Form
	{

        #region /*** Nested Types ***/

        class PanelItem
        {
            public PanelItem(string title, TreeNode node, CafeUserControl panel, bool enabled)
            {
                this.Title   = title;
                this.Node    = node;
                this.Panel   = panel;
                this.Enabled = enabled;
            }

            public string          Title;
            public TreeNode        Node;
            public CafeUserControl Panel;
            /// <summary>Determines whether this node/panel item is enabled.</summary>
            public bool Enabled;
        }

        class Panels
        {

            #region /*** Constructors ***/

            public Panels(Point panelLocation, Size panelSize)
            {
                // initialize nodes and panels
                this._itemCount = PanelNames.Length;
                this._items     = new PanelItem[this._itemCount];
                for (int i = 0; i < this._itemCount; i++)
                {
                    TreeNode        node    = new TreeNode(PanelNames[i]);
                    CafeUserControl panel   = null;
                    bool            enabled = true;
                    switch (i)
                    {
                        case  0: panel = new CompliancePanel(); break;
                        case  1: panel = new IOSettingsPanel(); break;
                        case  2: panel = new RuntimeSettingsPanel   (); break;
                    }
                    panel.Location = panelLocation;
                    panel.Size     = panelSize;
                    panel.Dock     = DockStyle.Fill;
                    this._items[i] = new PanelItem(PanelNames[i], node, panel, enabled);
                }
            }

            #endregion

            #region /*** Methods ***/

            public void SelectPanel(PanelItem item)
            {
                foreach (var subitem in this._items)
                {
                    subitem.Panel.Visible = false;
                }
                item.Panel.Visible = true;
            }

            #endregion

            #region /*** Properties ***/

            public PanelItem this[int index] { get { return this._items[index]; } }
            public int ItemCount { get { return this._itemCount; } }

            public PanelItem GeneralCompliancePanelItem { get { return this._items[0]; } }
            public PanelItem IOSettingsPanelItem { get { return this._items[1]; } }
            public PanelItem RuntimeSettingsPanelItem { get { return this._items[2]; } }

            public CompliancePanel GeneralCompliancePanel { get { return (CompliancePanel)this._items[0].Panel; } }
            public IOSettingsPanel IOSettingsPanel { get { return (IOSettingsPanel)this._items[1].Panel; } }
            public RuntimeSettingsPanel RuntimeSettingsPanel { get { return (RuntimeSettingsPanel)this._items[2].Panel; } }

            #endregion

            #region /*** Variables ***/

            public static readonly string[] PanelNames =
                new string[] {
                                 "General Compliance Settings",
                                 "I/O Settings",
                                 "Runtime Settings"
                             };

            PanelItem[] _items;
            int         _itemCount;

            #endregion

        }

        #endregion

        #region /*** Constructors ***/

        /// <summary>
        /// Initializes a new instance of the <see cref="ManageModelingSettings"/> class using the modeling configuration
        /// settings from the specified session.
        /// </summary>
        /// <param name="session">The modeling session for which to display the settings window.</param>
        public ManageModelingSettings(ISession session)
		{
            // main initialization
            this.InitializeComponent();
            this.InitializeUI();

            // perform additional initialization
            this._session      = session;
            this._inputParsing = false;
            this._inputSaving  = false;
            this._saving       = false;
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose(bool disposing)
		{
			base.Dispose(disposing);
		}

        #endregion

        #region /*** Methods ***/

		#region /* Windows Form Designer generated code */

        void InitializeComponent()
		{
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ManageModelingSettings));
            this.ux_navigation = new System.Windows.Forms.TreeView();
            this.ux_settingsPanel = new System.Windows.Forms.Panel();
            this.ux_titleLabel = new System.Windows.Forms.Label();
            this.ux_toolbarPanel = new System.Windows.Forms.Panel();
            this.ux_close = new System.Windows.Forms.Button();
            this.ux_save = new System.Windows.Forms.Button();
            this.ux_status = new System.Windows.Forms.RichTextBox();
            this.ux_settingsPanel.SuspendLayout();
            this.ux_toolbarPanel.SuspendLayout();
            this.SuspendLayout();
            // 
            // ux_navigation
            // 
            this.ux_navigation.Dock = System.Windows.Forms.DockStyle.Left;
            this.ux_navigation.FullRowSelect = true;
            this.ux_navigation.HideSelection = false;
            this.ux_navigation.HotTracking = true;
            this.ux_navigation.Location = new System.Drawing.Point(0, 0);
            this.ux_navigation.Name = "ux_navigation";
            this.ux_navigation.ShowRootLines = false;
            this.ux_navigation.Size = new System.Drawing.Size(200, 562);
            this.ux_navigation.TabIndex = 0;
            this.ux_navigation.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.Navigation_AfterSelect);
            // 
            // ux_settingsPanel
            // 
            this.ux_settingsPanel.AutoScroll = true;
            this.ux_settingsPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.ux_settingsPanel.Controls.Add(this.ux_titleLabel);
            this.ux_settingsPanel.Dock = System.Windows.Forms.DockStyle.Fill;
            this.ux_settingsPanel.Location = new System.Drawing.Point(200, 0);
            this.ux_settingsPanel.Name = "ux_settingsPanel";
            this.ux_settingsPanel.Size = new System.Drawing.Size(784, 442);
            this.ux_settingsPanel.TabIndex = 1;
            // 
            // ux_titleLabel
            // 
            this.ux_titleLabel.AutoEllipsis = true;
            this.ux_titleLabel.Dock = System.Windows.Forms.DockStyle.Top;
            this.ux_titleLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.ux_titleLabel.Location = new System.Drawing.Point(0, 0);
            this.ux_titleLabel.Name = "ux_titleLabel";
            this.ux_titleLabel.Padding = new System.Windows.Forms.Padding(4, 0, 4, 0);
            this.ux_titleLabel.Size = new System.Drawing.Size(782, 32);
            this.ux_titleLabel.TabIndex = 0;
            this.ux_titleLabel.Text = "Modeling Settings";
            this.ux_titleLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            // 
            // ux_toolbarPanel
            // 
            this.ux_toolbarPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.ux_toolbarPanel.Controls.Add(this.ux_close);
            this.ux_toolbarPanel.Controls.Add(this.ux_save);
            this.ux_toolbarPanel.Controls.Add(this.ux_status);
            this.ux_toolbarPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.ux_toolbarPanel.Location = new System.Drawing.Point(200, 442);
            this.ux_toolbarPanel.Name = "ux_toolbarPanel";
            this.ux_toolbarPanel.Size = new System.Drawing.Size(784, 120);
            this.ux_toolbarPanel.TabIndex = 2;
            // 
            // ux_close
            // 
            this.ux_close.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
            this.ux_close.BackColor = System.Drawing.SystemColors.Control;
            this.ux_close.DialogResult = System.Windows.Forms.DialogResult.Cancel;
            this.ux_close.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
            this.ux_close.ForeColor = System.Drawing.Color.Red;
            this.ux_close.Location = new System.Drawing.Point(704, 40);
            this.ux_close.Name = "ux_close";
            this.ux_close.Size = new System.Drawing.Size(64, 64);
            this.ux_close.TabIndex = 2;
            this.ux_close.Text = "Close";
            this.ux_close.UseVisualStyleBackColor = false;
            this.ux_close.Click += new System.EventHandler(this.Close_Click);
            // 
            // ux_save
            // 
            this.ux_save.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
            this.ux_save.BackColor = System.Drawing.SystemColors.Control;
            this.ux_save.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
            this.ux_save.ForeColor = System.Drawing.Color.Green;
            this.ux_save.Location = new System.Drawing.Point(632, 40);
            this.ux_save.Name = "ux_save";
            this.ux_save.Size = new System.Drawing.Size(64, 64);
            this.ux_save.TabIndex = 1;
            this.ux_save.Text = "Save";
            this.ux_save.UseVisualStyleBackColor = false;
            this.ux_save.Click += new System.EventHandler(this.Save_Click);
            // 
            // ux_status
            // 
            this.ux_status.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.ux_status.BackColor = System.Drawing.SystemColors.Control;
            this.ux_status.BorderStyle = System.Windows.Forms.BorderStyle.None;
            this.ux_status.Location = new System.Drawing.Point(8, 8);
            this.ux_status.Name = "ux_status";
            this.ux_status.ReadOnly = true;
            this.ux_status.Size = new System.Drawing.Size(616, 102);
            this.ux_status.TabIndex = 0;
            this.ux_status.Text = "";
            // 
            // ManageModelingSettings
            // 
            this.AcceptButton = this.ux_save;
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
            this.CancelButton = this.ux_close;
            this.ClientSize = new System.Drawing.Size(1008, 562);
            this.Controls.Add(this.ux_settingsPanel);
            this.Controls.Add(this.ux_toolbarPanel);
            this.Controls.Add(this.ux_navigation);
            this.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.MaximizeBox = false;
            this.MaximumSize = new System.Drawing.Size(1024, 640);
            this.MinimizeBox = false;
            this.MinimumSize = new System.Drawing.Size(1024, 640);
            this.Name = "ManageModelingSettings";
            this.ShowInTaskbar = false;
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
            this.Text = "Modeling Settings";
            this.ux_settingsPanel.ResumeLayout(false);
            this.ux_toolbarPanel.ResumeLayout(false);
            this.ResumeLayout(false);

        }

		#endregion

        #region /* Overriden Methods */

        /// <summary>
        /// Raises the <see cref="Form.Load"/> event.
        /// </summary>
        /// <param name="e">Event data to pass to the event.</param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            // hide the save button if the session is running
            this.ux_save.Visible = !this._session.IsRunning;

            // add event handlers for the input panel
            this._panels.IOSettingsPanel.ParsingChanged += new EventHandler(this.InputPanel_ParsingChanged);
            //
            // set initial states for each panel
            this._panels.GeneralCompliancePanel.SetInitialState(this._session.Compliance);
            this._panels.IOSettingsPanel       .SetInitialState(this._session.Settings.IOSettings);
            this._panels.RuntimeSettingsPanel  .SetInitialState(this._session.Settings.RuntimeSettings);
            //
            // select the "general compliance panel"
            this.SelectPanel(0);

            // determine which compliance model is initially selected
            ICompliance selCompliance = this._panels.GeneralCompliancePanel.SelectedCompliance;

            // add idle hanlder
            Application.Idle += new EventHandler(this.ModelingSettings_Idle);
        }
        /// <summary>
        /// Raises the <see cref="Form.Closing"/> event.
        /// </summary>
        /// <param name="e">Event data to pass to the event.</param>
        protected override void OnClosing(CancelEventArgs e)
        {
            // do not close while parsing input files or saving
            if (this._saving || this._inputParsing || this._inputSaving) { e.Cancel = true; return; }
            //
            // remove event handlers
            this._panels.IOSettingsPanel.ParsingChanged -= new EventHandler(this.InputPanel_ParsingChanged);
            Application.Idle -= new EventHandler(this.ModelingSettings_Idle);

            // continue closing ...
            base.OnClosing(e);
        }

        #endregion

        void InitializeUI()
        {
            // fix font for systems with custom DPI scalling
            // windows forms scales fonts, but its auto-size feature does not work for fixed pos controls
            this.Font = new Font("Microsoft Sans Serif", 9.75F * GlobalSettings.DPIScale, FontStyle.Regular, GraphicsUnit.Point, 0);

            // also set bold fonts for save/close buttons
            Font toolbarButtonFont = new Font("Microsoft Sans Serif", 9.75F * GlobalSettings.DPIScale, FontStyle.Bold, GraphicsUnit.Point, 0);
            this.ux_save.Font = toolbarButtonFont;
            this.ux_close.Font = toolbarButtonFont;

            // initialize nodes and panels
            this._panels = new Panels(new Point(0, 32), new Size(this.ux_settingsPanel.Width, this.ux_settingsPanel.Height - 40));

            // add panels to the main settings panel
            for (int i = 0; i < this._panels.ItemCount; i++)
            {
                this.ux_settingsPanel.Controls.Add(this._panels[i].Panel);
            }
            this.ux_titleLabel.SendToBack();

            // refresh navigation tree
            this.RefreshNavigationTree();
        }
        void RefreshNavigationTree()
        {
            this.ux_navigation.BeginUpdate();
            this.ux_navigation.Nodes.Clear();
            for (int i = 0; i < this._panels.ItemCount; i++)
            {
                if (this._panels[i].Enabled) { this.ux_navigation.Nodes.Add(this._panels[i].Node); }
            }
            this.ux_navigation.EndUpdate();
        }
        void RefreshStatusTextBox()
        {
            string newStatus;
            Color  statusColor;

            int numErr = 0, numChn = 0;
            for (int i = 0; i < this._panels.ItemCount; i++)
            {
                if (this._panels[i].Enabled)
                {
                    if      (this._panels[i].Panel.Messages.HasMessages) { numErr++; }
                    else if (this._panels[i].Panel.SettingsChanged     ) { numChn++; }
                }
            }
            //
            if (numErr > 0)
            {
                StringBuilder errors = new StringBuilder();
                for (int i = 0; i < this._panels.ItemCount; i++)
                {
                    if (this._panels[i].Enabled && this._panels[i].Panel.Messages.HasMessages)
                    {
                        errors.Append(this._panels[i].Panel.Messages.ToString());
                        errors.Append("\n");
                    }
                }
                //
                newStatus   = errors.ToString();
                statusColor = Color.Red;
            }
            else
            {
                newStatus   = string.Empty;
                statusColor = Color.Black;
            }

            // update the status, if changed
            if (this.ux_status.Text != newStatus)
            {
                this.ux_status.Text      = newStatus;
                this.ux_status.ForeColor = statusColor;
            }
        }

        void ModelingSettings_Idle(object sender, EventArgs e)
        {
            // get compliance model currently selected
            ICompliance selCompliance = this._panels.GeneralCompliancePanel.SelectedCompliance;

            // enable the save button only if there are no error/warning messages and some settings have changed
            bool hasErrors  = false;
            bool hasChanges = false;
            for (int i = 0; i < this._panels.ItemCount; i++)
            {
                if (this._panels[i].Enabled)
                {
                    if      (this._panels[i].Panel.Messages.HasMessages) { hasErrors  = true; break; }
                    else if (this._panels[i].Panel.SettingsChanged     ) { hasChanges = true; }
                }
            }
            this.ux_save.Enabled = !this._session.IsRunning && !hasErrors && hasChanges;

            // refresh the status text-box
            this.RefreshStatusTextBox();
        }
        void Navigation_AfterSelect(object sender, TreeViewEventArgs e)
        {
            this.SelectPanel(this.IndexOf(e.Node));
        }
        void InputPanel_ParsingChanged(object sender, EventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new EventHandler(this.InputPanel_ParsingChanged));
            }
            else
            {
                IOSettingsPanel pnl = (IOSettingsPanel)this._panels.IOSettingsPanelItem.Panel;
                this._inputParsing           = pnl.Parsing;
                bool enabled                 = !this._inputParsing;
              //this.ux_navigation  .Enabled = enabled;
                this.ux_toolbarPanel.Enabled = enabled;
                this.ControlBox              = enabled;
                this.ShowIcon                = enabled;
                //
                for (int i = 0; i < this._panels.ItemCount; i++)
                {
                    this._panels[i].Panel.Enabled = enabled;
                }
                //
                if (this._inputSaving && enabled)
                {   // save updated data loaded from input files
                    if (pnl.MarketData   != null) { this._session.Data                  = pnl.MarketData; }
                    if (pnl.Technologies != null) { this._session.Settings.Technologies = pnl.Technologies; }
                    if (pnl.Parameters   != null) { this._session.Settings.Parameters   = pnl.Parameters; }
                    if (pnl.Scenarios    != null) { this._session.Settings.Scenarios    = pnl.Scenarios; }
                    // save input settings
                    this._inputSaving = false;
                }
            }
        }
        void Save_Click(object sender, EventArgs e)
        {
            // begin saving --
            this._saving = true;

            // save the changes for each panel
            for (int i = 0; i < this._panels.ItemCount; i++)
            {
                if (this._panels[i].Panel.SettingsChanged)
                {
                    if (this._panels[i].Panel is IOSettingsPanel) { this._inputSaving = true; }
                    this._panels[i].Panel.SaveChanges();
                }
            }

            // save the selected compliance model
            this._session.Compliance = (this._panels.GeneralCompliancePanel).Compliance;

            // indicate that session should be saved
            this._session.SaveRequired = true;

            // saving complete! :)
            this._saving = false;
        }
        void Close_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// Selects the panel at the specifid index.
        /// </summary>
        /// <param name="index">The index of the panel to select.</param>
        public void SelectPanel(int index)
        {
            if (index < 0 || index >= this._panels.ItemCount) { return; }
            this.SelectPanel(this._panels[index]);
        }
        void SelectPanel(PanelItem item)
        {
            if (!item.Enabled) { return; }
            //
            this._panels.SelectPanel(item);
            this.ux_navigation.SelectedNode = item.Node;
            this.ux_titleLabel.Text = item.Title;
        }
        int IndexOf(TreeNode node)
        {
            for (int i = 0; i < this._panels.ItemCount; i++)
            {
                if (this._panels[i].Node == node) { return i; }
            }
            return -1;
        }
        int IndexOf(CafeUserControl panel)
        {
            for (int i = 0; i < this._panels.ItemCount; i++)
            {
                if (this._panels[i].Panel == panel) { return i; }
            }
            return -1;
        }

        #endregion

        #region /*** Variables ***/

        #region /* UI Variables */

        TreeView ux_navigation;
        Panel ux_settingsPanel;
        Label ux_titleLabel;
        Panel ux_toolbarPanel;
        RichTextBox ux_status;
        Button ux_save;
        Button ux_close;

        #endregion

        Panels _panels;
        bool _inputParsing;
        bool _inputSaving;
        bool _saving;

        ISession _session;

        #endregion

    }
}
