using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using Volpe.Cafe;
using Volpe.Cafe.EspressoUI.Utils;
using Volpe.Cafe.Model;

namespace Volpe.Cafe.EspressoUI.LegacyControls.Panels
{
    /// <summary>
    /// Provides a panel for configuring which compliance model to run.
    /// </summary>
	public class CompliancePanel : CafeUserControl
	{

        #region /*** Constructors ***/

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

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

        #endregion

        #region /*** Methods ***/

		#region /* Designer generated code */

        void InitializeComponent()
		{
            System.Windows.Forms.Label label1;
            System.Windows.Forms.Label label2;
            this.ux_complianceLabel = new System.Windows.Forms.Label();
            this.ux_compliancePanel = new System.Windows.Forms.Panel();
            this.ux_userNotesPanel = new System.Windows.Forms.Panel();
            this.ux_userKeywords = new System.Windows.Forms.TextBox();
            this.ux_userNotes = new System.Windows.Forms.TextBox();
            this.ux_userNotesLabel = new System.Windows.Forms.Label();
            label1 = new System.Windows.Forms.Label();
            label2 = new System.Windows.Forms.Label();
            this.ux_userNotesPanel.SuspendLayout();
            this.SuspendLayout();
            // 
            // label1
            // 
            label1.AutoSize = true;
            label1.Location = new System.Drawing.Point(8, 8);
            label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
            label1.Name = "label1";
            label1.Size = new System.Drawing.Size(47, 16);
            label1.TabIndex = 0;
            label1.Text = "Notes:";
            // 
            // label2
            // 
            label2.AutoSize = true;
            label2.Location = new System.Drawing.Point(8, 64);
            label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
            label2.Name = "label2";
            label2.Size = new System.Drawing.Size(70, 16);
            label2.TabIndex = 2;
            label2.Text = "Keywords:";
            // 
            // ux_complianceLabel
            // 
            this.ux_complianceLabel.AutoSize = true;
            this.ux_complianceLabel.Location = new System.Drawing.Point(8, 8);
            this.ux_complianceLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
            this.ux_complianceLabel.Name = "ux_complianceLabel";
            this.ux_complianceLabel.Size = new System.Drawing.Size(252, 16);
            this.ux_complianceLabel.TabIndex = 0;
            this.ux_complianceLabel.Text = "What type of model would you like to run?";
            // 
            // ux_compliancePanel
            // 
            this.ux_compliancePanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.ux_compliancePanel.Location = new System.Drawing.Point(8, 16);
            this.ux_compliancePanel.Margin = new System.Windows.Forms.Padding(4, 2, 4, 2);
            this.ux_compliancePanel.Name = "ux_compliancePanel";
            this.ux_compliancePanel.Size = new System.Drawing.Size(768, 59);
            this.ux_compliancePanel.TabIndex = 1;
            // 
            // ux_userNotesPanel
            // 
            this.ux_userNotesPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.ux_userNotesPanel.Controls.Add(this.ux_userKeywords);
            this.ux_userNotesPanel.Controls.Add(label2);
            this.ux_userNotesPanel.Controls.Add(this.ux_userNotes);
            this.ux_userNotesPanel.Controls.Add(label1);
            this.ux_userNotesPanel.Location = new System.Drawing.Point(8, 112);
            this.ux_userNotesPanel.Margin = new System.Windows.Forms.Padding(4, 2, 4, 2);
            this.ux_userNotesPanel.Name = "ux_userNotesPanel";
            this.ux_userNotesPanel.Size = new System.Drawing.Size(768, 96);
            this.ux_userNotesPanel.TabIndex = 3;
            // 
            // ux_userKeywords
            // 
            this.ux_userKeywords.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.ux_userKeywords.Location = new System.Drawing.Point(80, 64);
            this.ux_userKeywords.Margin = new System.Windows.Forms.Padding(4, 2, 4, 2);
            this.ux_userKeywords.Name = "ux_userKeywords";
            this.ux_userKeywords.Size = new System.Drawing.Size(680, 22);
            this.ux_userKeywords.TabIndex = 3;
            // 
            // ux_userNotes
            // 
            this.ux_userNotes.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.ux_userNotes.Location = new System.Drawing.Point(64, 8);
            this.ux_userNotes.Margin = new System.Windows.Forms.Padding(4, 2, 4, 2);
            this.ux_userNotes.Multiline = true;
            this.ux_userNotes.Name = "ux_userNotes";
            this.ux_userNotes.Size = new System.Drawing.Size(696, 52);
            this.ux_userNotes.TabIndex = 1;
            // 
            // ux_userNotesLabel
            // 
            this.ux_userNotesLabel.AutoSize = true;
            this.ux_userNotesLabel.Location = new System.Drawing.Point(8, 96);
            this.ux_userNotesLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
            this.ux_userNotesLabel.Name = "ux_userNotesLabel";
            this.ux_userNotesLabel.Size = new System.Drawing.Size(517, 16);
            this.ux_userNotesLabel.TabIndex = 2;
            this.ux_userNotesLabel.Text = "Optionally, please specify additional notes and/or keywords describing the type o" +
    "f run:";
            // 
            // CompliancePanel
            // 
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
            this.Controls.Add(this.ux_userNotesLabel);
            this.Controls.Add(this.ux_userNotesPanel);
            this.Controls.Add(this.ux_complianceLabel);
            this.Controls.Add(this.ux_compliancePanel);
            this.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.Margin = new System.Windows.Forms.Padding(4, 2, 4, 2);
            this.Name = "CompliancePanel";
            this.Size = new System.Drawing.Size(784, 400);
            this.ux_userNotesPanel.ResumeLayout(false);
            this.ux_userNotesPanel.PerformLayout();
            this.ResumeLayout(false);
            this.PerformLayout();

        }

		#endregion

        SizeF MeasureString(Graphics g, string text, Font font, int width)
        {
            //return g.MeasureString(text, font, width - 16);

            SizeF fontSize = g.MeasureString(text, font);
            float fontH    = g.MeasureString("a", font).Height;
            int startLineCount = (int)Math.Ceiling(fontSize.Height / fontH);
            int lineCount = (int)Math.Ceiling(fontSize.Width / width);
            return new SizeF(width, fontH * (lineCount + startLineCount - 1) + 2);
        }

        void PostInitialize()
        {
            // 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);

            this.RegisterTextControl(this.ux_userNotes, string.Empty, null, null, true);
            this.RegisterTextControl(this.ux_userKeywords, string.Empty, null, null, true);
            // initialize check-changes
            this.AutoInitializeCheckChangesDetector(this.Controls);
        }
        void InitializeComplianceList(ICompliance initialCompliance)
        {
            int  y     = 8; // the starting vertical position of the first item
            var  g     = this.ux_compliancePanel.CreateGraphics();
            Font font  = this.ux_compliancePanel.Font;
            int  width = this.ux_compliancePanel.Width - 24; // desired width of each item

            Type initialComplianceType = (initialCompliance == null)
                                       ? ComplianceModels.DefaultType
                                       : initialCompliance.GetType();
            string initialComplianceName = initialComplianceType.FullName.ToLower();

            foreach (Type complianceType in ComplianceModels.ModelTypes)
            {
                var ctor = complianceType.GetConstructor(Type.EmptyTypes);
                var compliance = (ICompliance)ctor.Invoke(new object[] {});

                // get name and description of the compliance model
                var attr = (ModelDescriptionAttribute)Attribute.GetCustomAttribute(
                    complianceType, typeof(ModelDescriptionAttribute));
                string name  = attr.FullTitle;
                string descr = attr.Description;
                string text  = name + "\n" + descr;
                SizeF  size  = this.MeasureString(g, text, font, width - 16);

                // create radio-button for the compliance title
                RadioButton rdb = new RadioButton
                {
                    CheckAlign  = ContentAlignment.TopLeft,
                    FlatStyle   = FlatStyle.Popup,
                    Location    = new Point(8, y),
                    Size        = new Size(width, (int)(size.Height + 1)),
                    Tag         = compliance,
                    Text        = text,
                    TextAlign   = ContentAlignment.TopLeft
                };

                rdb.CheckedChanged += new EventHandler(this.CheckChangesDetector);
                rdb.CheckedChanged += new EventHandler(this.ComplianceItem_CheckedChanged);
                this.ux_compliancePanel.Controls.Add(rdb);
                y = rdb.Top + rdb.Height + 8;

                // select the initial compliance
                if (initialComplianceName == complianceType.FullName.ToLower()) { rdb.Checked = true; }
            }

            if (initialCompliance != null)
            {
                this.ux_userNotes   .Text = initialCompliance.UserNotes;
                this.ux_userKeywords.Text = initialCompliance.UserKeywords;
            }

            // adjust the positioning of the compliance panel and user-notes label/panel
            this.ux_compliancePanel.Height = y;
            this.ux_userNotesLabel.Top = this.ux_compliancePanel.Height + this.ux_compliancePanel.Top + 8;
            this.ux_userNotesPanel.Top = this.ux_userNotesLabel.Top + 16;
        }
        void ComplianceItem_CheckedChanged(object sender, EventArgs e)
        {
            RadioButton rdb = (RadioButton)sender;
            if (rdb.Checked)
            {
                this._selCompliance = (ICompliance)rdb.Tag;
            }
        }

        /// <summary>
        /// Sets up the initial states of the controls for the <see cref="CompliancePanel"/> instance based on the specified
        /// compliance model.
        /// </summary>
        /// <param name="compliance">The compliance model currently in use by the session.  This value can be null.</param>
        public void SetInitialState(ICompliance compliance)
        {
            // initialize the compliance list and set initial compliance model
            this.InitializeComplianceList(compliance);

            // call save to reset changes (only if initial compliance has been specified)
            if (compliance != null) { this.SaveChanges(); }
        }

        /// <summary>
        /// Commits the most recently made changes to the <see cref="CompliancePanel"/>.
        /// </summary>
        public override void SaveChanges()
        {
            if (this.SettingsChanged)
            {
                this._compliance              = this._selCompliance.CreateNew();
                this._compliance.UserNotes    = this.ux_userNotes.Text;
                this._compliance.UserKeywords = this.ux_userKeywords.Text;
                //
                base.SaveChanges();
            }
        }

        #endregion

        #region /*** Properties ***/

        /// <summary>Gets whether any of the settings have changed since the <see cref="CompliancePanel"/> has been loaded or
        ///   since the changes have been last saved.</summary>
        [Browsable(false)]
        public override bool SettingsChanged { get { return base.SettingsChanged || (this._compliance == null); } }

        /// <summary>Gets the compliance model selected by the user during the last save.  (This compliance model will be used by
        ///   the session when modeling begins.)</summary>
        [Browsable(false)]
        public ICompliance Compliance { get { return this._compliance; } }
        /// <summary>Gets the compliance model currently selected by the user.</summary>
        [Browsable(false)]
        public ICompliance SelectedCompliance { get { return this._selCompliance; } }

        #endregion

        #region /*** Variables ***/

        #region /* UI Variables */

        Label   ux_complianceLabel;
        Panel   ux_compliancePanel;
        Label   ux_userNotesLabel;
        Panel   ux_userNotesPanel;
        TextBox ux_userNotes;
        TextBox ux_userKeywords;

        #endregion

        /// <summary>Represents the compliance model selected by the user during the last save.  (This compliance model will be
        ///   used by the session when modeling begins.)</summary>
        ICompliance _compliance;
        /// <summary>Represents the compliance model currently selected by the user.</summary>
        ICompliance _selCompliance;

        #endregion

    }
}
