#region << Using Directives >>
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using Volpe.Cafe.EspressoUI.Utils;
using Volpe.Cafe.Resources;
using Volpe.Cafe.UI;
using Volpe.Cafe.Utils;
#endregion

namespace Volpe.Cafe.EspressoUI
{
    /// <summary>
    /// Provides a message dialog capable of loading and displaying information from RTF files.
    /// </summary>
    public class RtfDialog : Form
	{

        #region <<< Constructors >>>

        /// <summary>
        /// Initializes a new instance of the <see cref="RtfDialog"/> class.
        /// </summary>
		protected RtfDialog()
		{
			this.InitializeComponent();
            this.InitializeOther();
		}

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

        #endregion

        #region <<< Methods >>>

        #region < Initialization methods >

        void InitializeComponent()
		{
            this.ux_rtf = new System.Windows.Forms.RichTextBox();
            this.ux_buttons = new System.Windows.Forms.Panel();
            this.ux_viewLGPLv21 = new System.Windows.Forms.LinkLabel();
            this.ux_viewExcelDataReaderLicense = new System.Windows.Forms.LinkLabel();
            this.ux_noButton = new System.Windows.Forms.Button();
            this.ux_yesButton = new System.Windows.Forms.Button();
            this.ux_cancelButton = new System.Windows.Forms.Button();
            this.ux_okButton = new System.Windows.Forms.Button();
            this.ux_buildInfo = new System.Windows.Forms.Label();
            this.ux_buttons.SuspendLayout();
            this.SuspendLayout();
            // 
            // ux_rtf
            // 
            this.ux_rtf.BackColor = System.Drawing.Color.White;
            this.ux_rtf.Dock = System.Windows.Forms.DockStyle.Fill;
            this.ux_rtf.Location = new System.Drawing.Point(0, 0);
            this.ux_rtf.Name = "ux_rtf";
            this.ux_rtf.ReadOnly = true;
            this.ux_rtf.Size = new System.Drawing.Size(624, 373);
            this.ux_rtf.TabIndex = 1;
            this.ux_rtf.TabStop = false;
            this.ux_rtf.Text = "";
            this.ux_rtf.LinkClicked += new System.Windows.Forms.LinkClickedEventHandler(this.RTF_LinkClicked);
            // 
            // ux_buttons
            // 
            this.ux_buttons.Controls.Add(this.ux_viewLGPLv21);
            this.ux_buttons.Controls.Add(this.ux_viewExcelDataReaderLicense);
            this.ux_buttons.Controls.Add(this.ux_noButton);
            this.ux_buttons.Controls.Add(this.ux_yesButton);
            this.ux_buttons.Controls.Add(this.ux_cancelButton);
            this.ux_buttons.Controls.Add(this.ux_okButton);
            this.ux_buttons.Controls.Add(this.ux_buildInfo);
            this.ux_buttons.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.ux_buttons.Location = new System.Drawing.Point(0, 373);
            this.ux_buttons.Name = "ux_buttons";
            this.ux_buttons.Size = new System.Drawing.Size(624, 68);
            this.ux_buttons.TabIndex = 0;
            // 
            // ux_viewLGPLv21
            // 
            this.ux_viewLGPLv21.AutoSize = true;
            this.ux_viewLGPLv21.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
            this.ux_viewLGPLv21.Location = new System.Drawing.Point(8, 44);
            this.ux_viewLGPLv21.Name = "ux_viewLGPLv21";
            this.ux_viewLGPLv21.Size = new System.Drawing.Size(133, 16);
            this.ux_viewLGPLv21.TabIndex = 6;
            this.ux_viewLGPLv21.TabStop = true;
            this.ux_viewLGPLv21.Text = "View GNU LGPL v2.1";
            this.ux_viewLGPLv21.Visible = false;
            this.ux_viewLGPLv21.Click += new System.EventHandler(this.ViewLGPLv21_Click);
            // 
            // ux_viewExcelDataReaderLicense
            // 
            this.ux_viewExcelDataReaderLicense.AutoSize = true;
            this.ux_viewExcelDataReaderLicense.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
            this.ux_viewExcelDataReaderLicense.Location = new System.Drawing.Point(144, 44);
            this.ux_viewExcelDataReaderLicense.Name = "ux_viewExcelDataReaderLicense";
            this.ux_viewExcelDataReaderLicense.Size = new System.Drawing.Size(198, 16);
            this.ux_viewExcelDataReaderLicense.TabIndex = 7;
            this.ux_viewExcelDataReaderLicense.TabStop = true;
            this.ux_viewExcelDataReaderLicense.Text = "View ExcelDataReader License";
            this.ux_viewExcelDataReaderLicense.Visible = false;
            this.ux_viewExcelDataReaderLicense.Click += new System.EventHandler(this.ViewExcelDataReaderLicense);
            // 
            // ux_noButton
            // 
            this.ux_noButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.ux_noButton.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
            this.ux_noButton.Location = new System.Drawing.Point(528, 8);
            this.ux_noButton.Name = "ux_noButton";
            this.ux_noButton.Size = new System.Drawing.Size(88, 24);
            this.ux_noButton.TabIndex = 2;
            this.ux_noButton.Text = "&No";
            this.ux_noButton.Click += new System.EventHandler(this.NoButton_Click);
            // 
            // ux_yesButton
            // 
            this.ux_yesButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.ux_yesButton.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
            this.ux_yesButton.Location = new System.Drawing.Point(432, 8);
            this.ux_yesButton.Name = "ux_yesButton";
            this.ux_yesButton.Size = new System.Drawing.Size(88, 24);
            this.ux_yesButton.TabIndex = 1;
            this.ux_yesButton.Text = "&Yes";
            this.ux_yesButton.Click += new System.EventHandler(this.YesButton_Click);
            // 
            // ux_cancelButton
            // 
            this.ux_cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.ux_cancelButton.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
            this.ux_cancelButton.Location = new System.Drawing.Point(336, 8);
            this.ux_cancelButton.Name = "ux_cancelButton";
            this.ux_cancelButton.Size = new System.Drawing.Size(88, 24);
            this.ux_cancelButton.TabIndex = 3;
            this.ux_cancelButton.Text = "C&ancel";
            this.ux_cancelButton.Click += new System.EventHandler(this.CancelButton_Click);
            // 
            // ux_okButton
            // 
            this.ux_okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.ux_okButton.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
            this.ux_okButton.Location = new System.Drawing.Point(240, 8);
            this.ux_okButton.Name = "ux_okButton";
            this.ux_okButton.Size = new System.Drawing.Size(88, 24);
            this.ux_okButton.TabIndex = 0;
            this.ux_okButton.Text = "&OK";
            this.ux_okButton.Click += new System.EventHandler(this.OkButton_Click);
            // 
            // ux_buildInfo
            // 
            this.ux_buildInfo.AutoSize = true;
            this.ux_buildInfo.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.ux_buildInfo.Location = new System.Drawing.Point(8, 8);
            this.ux_buildInfo.Name = "ux_buildInfo";
            this.ux_buildInfo.Size = new System.Drawing.Size(161, 32);
            this.ux_buildInfo.TabIndex = 4;
            this.ux_buildInfo.Text = "CAFE Model (Version)\r\nBuild Date";
            this.ux_buildInfo.Visible = false;
            // 
            // RtfDialog
            // 
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
            this.ClientSize = new System.Drawing.Size(624, 441);
            this.Controls.Add(this.ux_rtf);
            this.Controls.Add(this.ux_buttons);
            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.FixedDialog;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "RtfDialog";
            this.ShowInTaskbar = false;
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.Text = "CAFE Model";
            this.ux_buttons.ResumeLayout(false);
            this.ux_buttons.PerformLayout();
            this.ResumeLayout(false);

        }
        void InitializeOther()
        {
            this.Icon = Program.GetAppIcon();
            this.MaximumSize = GlobalSettings.DialogSize;
            this.Size = GlobalSettings.DialogSize;
            this.MinimumSize = GlobalSettings.DialogSize;
            this.PromptOption = PromptOption.Ok;
            this.ShowBuildInfo = false;
            this.ShowLicenseButtons = false;

            // 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.ux_buildInfo.Font = new Font(this.Font, FontStyle.Bold);
            this.ux_buildInfo.Text =
                $"{ApplicationInfo.ProductName} ({ApplicationInfo.ProductVersion})\n" +
                $"Build Date: {ApplicationInfo.ProductBuildDate}";
        }

        #endregion

        #region < ShowDialog static methods >

        /// <summary>
        /// Displays the <see cref="RtfDialog"/> with the specified caption, text, and prompt-options.
        /// </summary>
        /// <param name="caption">The text to display in the <see cref="RtfDialog"/>'s title bar.</param>
        /// <param name="text">The text to display in the <see cref="RtfDialog"/>'s body.</param>
        /// <param name="font">The font to apply to the body of the text.</param>
        /// <param name="fontColor">The font color to apply to the body of the text.</param>
        /// <param name="promptOption">The buttons to display in the <see cref="RtfDialog"/>.</param>
        /// <param name="showBuildInfo">
        ///     true, to display the build infomartion of the CAFE Model application; false, otherwise.
        /// </param>
        /// <param name="showLicenseButtons">
        ///     true, to display "View LGPLv2.1" and "View ExcelDataReader License" buttons; false, otherwise.
        /// </param>
        /// <returns>The result of a dialog box (usually indicates the button that was selected by user).</returns>
        public static DialogResult ShowDialog(string caption, string text, Font font = null, Color? fontColor = null,
            PromptOption promptOption = PromptOption.Ok, bool showBuildInfo = false, bool showLicenseButtons = false)
        {
            RtfDialog dlg = new RtfDialog();
            dlg.Initialize(caption, text, promptOption, showBuildInfo, showLicenseButtons);

            if (font != null)
                dlg.ux_rtf.Font = font;
            if (fontColor != null && fontColor.Value != Color.Empty)
                dlg.ux_rtf.ForeColor = fontColor.Value;

            return dlg.ShowDialog();
        }

        /// <summary>
        /// Displays the <see cref="RtfDialog"/> with the specified caption and prompt-options, loading the text to use
        /// for the body of the dialog from the specified file path.
        /// </summary>
        /// <param name="caption">The text to display in the <see cref="RtfDialog"/>'s title bar.</param>
        /// <param name="path">The file whose text to load into the <see cref="RtfDialog"/>'s body.</param>
        /// <param name="promptOption">The buttons to display in the <see cref="RtfDialog"/>.</param>
        /// <param name="showBuildInfo">
        ///     true, to display the build infomartion of the CAFE Model application; false, otherwise.
        /// </param>
        /// <param name="showLicenseButtons">
        ///     true, to display "View LGPLv2.1" and "View ExcelDataReader License" buttons; false, otherwise.
        /// </param>
        /// <returns>The result of a dialog box (usually indicates the button that was selected by user).</returns>
        public static DialogResult ShowDialogFromFile(string caption, string path,
            PromptOption promptOption = PromptOption.Ok, bool showBuildInfo = false, bool showLicenseButtons = false)
        {
            FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read);
            DialogResult dr = ShowDialogFromStream(caption, stream, promptOption, showBuildInfo, showLicenseButtons);
            stream.Close();
            return dr;
        }

        /// <summary>
        /// Displays the <see cref="RtfDialog"/> with the specified caption and prompt-options, loading the text to use
        /// for the body of the dialog from the specified <see cref="Stream"/>.
        /// </summary>
        /// <param name="caption">The text to display in the <see cref="RtfDialog"/>'s title bar.</param>
        /// <param name="stream">The stream whose text to load into the <see cref="RtfDialog"/>'s body.</param>
        /// <param name="promptOption">The buttons to display in the <see cref="RtfDialog"/>.</param>
        /// <param name="showBuildInfo">
        ///     true, to display the build infomartion of the CAFE Model application; false, otherwise.
        /// </param>
        /// <param name="showLicenseButtons">
        ///     true, to display "View LGPLv2.1" and "View ExcelDataReader License" buttons; false, otherwise.
        /// </param>
        /// <returns>The result of a dialog box (usually indicates the button that was selected by user).</returns>
        public static DialogResult ShowDialogFromStream(string caption, Stream stream,
            PromptOption promptOption = PromptOption.Ok, bool showBuildInfo = false, bool showLicenseButtons = false)
        {
            RtfDialog dlg = new RtfDialog();
            dlg.Initialize(caption, string.Empty, promptOption, showBuildInfo, showLicenseButtons);
            dlg.ux_rtf.LoadFile(stream, RichTextBoxStreamType.RichText);
            // when loading rich-text (rtf) from file, reset zoom-factor, otherwise text appears too large
            dlg.ux_rtf.ZoomFactor = GlobalSettings.DPIScale;
            return dlg.ShowDialog();
        }

        #endregion

        /// <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)
        {
            this.Focus();
            base.OnLoad(e);
        }

        void Initialize(string caption, string text, PromptOption promptOption, bool showBuildInfo,
            bool showLicenseButtons)
        {
            this.Text = caption;
            this.ux_rtf.Text = text;
            this.PromptOption = promptOption;
            this.ShowBuildInfo = showBuildInfo;
            this.ShowLicenseButtons = showLicenseButtons;
            this.AlignBuildInfoAndLicense();
        }

        void AlignBuildInfoAndLicense()
        {
            this.ux_buttons.Height = (this.ShowBuildInfo && this.ShowLicenseButtons) ? 68 : 48;

            if (this.ShowLicenseButtons)
            {
                this.ux_viewLGPLv21.Location = (this._showBuildInfo) ? new Point(8, 44) : new Point(8, 8);
                this.ux_viewExcelDataReaderLicense.Location = (this._showBuildInfo) ? new Point(144, 44) : new Point(8, 24);
            }
        }

        void SetupButtons(bool okVisbile, bool cancelVisbile, bool yesVisbile, bool noVisbile,
            Button acceptButton, Button cancelButton)
        {
            this.ux_okButton    .Visible = okVisbile;
            this.ux_cancelButton.Visible = cancelVisbile;
            this.ux_yesButton   .Visible = yesVisbile;
            this.ux_noButton    .Visible = noVisbile;
            //
            this.AcceptButton = acceptButton;
            this.CancelButton = cancelButton;
        }

        void ViewLGPLv21_Click(object sender, EventArgs e)
        {
            ResourceViewer.ShowGNULGPLWindow();
        }
        void ViewExcelDataReaderLicense(object sender, EventArgs e)
        {
            ResourceViewer.ShowExcelDataReaderLicenseWindow();
        }

        void RTF_LinkClicked(object sender, LinkClickedEventArgs e)
        {
            Process.Start("iexplore", e.LinkText);
        }

        void OkButton_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.OK;
        }
        void CancelButton_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
        }
        void YesButton_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Yes;
        }
        void NoButton_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.No;
        }

        #endregion

        #region <<< Properties >>>

        /// <summary>Gets or set the prompt options displayed in the <see cref="RtfDialog"/>.</summary>
        [Category("Appearance")]
        [Description("Indicates the prompt options displayed in the RtfDialog.")]
        [DefaultValue(PromptOption.Ok)]
        public PromptOption PromptOption
        {
            get { return this._promptOption; }
            set
            {
                if (this._promptOption == value) { return; }

                this._promptOption = value;
                switch (value)
                {
                    case PromptOption.OkCancel:
                        this.SetupButtons(true, true, false, false, this.ux_okButton, this.ux_cancelButton);
                        this.ux_cancelButton.Left = this.ux_buttons     .Width - 8 - this.ux_cancelButton.Width;
                        this.ux_okButton    .Left = this.ux_cancelButton.Left  - 8 - this.ux_okButton    .Width;
                        break;

                    case PromptOption.YesNo:
                        this.SetupButtons(false, false, true, true, this.ux_yesButton, this.ux_noButton);
                        this.ux_noButton .Left = this.ux_buttons .Width - 8 - this.ux_noButton .Width;
                        this.ux_yesButton.Left = this.ux_noButton.Left  - 8 - this.ux_yesButton.Width;
                        break;

                    case PromptOption.YesNoCancel:
                        this.SetupButtons(false, true, true, true, this.ux_yesButton, this.ux_cancelButton);
                        this.ux_cancelButton.Left = this.ux_buttons     .Width - 8 - this.ux_cancelButton.Width;
                        this.ux_noButton    .Left = this.ux_cancelButton.Left  - 8 - this.ux_noButton    .Width;
                        this.ux_yesButton   .Left = this.ux_noButton    .Left  - 8 - this.ux_yesButton   .Width;
                        break;

                    default:    // show OK-only by default
                        this.SetupButtons(true, false, false, false, this.ux_okButton, this.ux_okButton);
                        this.ux_okButton.Left = this.ux_buttons.Width - 8 - this.ux_cancelButton.Width;
                        break;
                }
            }
        }
        /// <summary>Gets or sets whether the applicaiton build info is displayed in the <see cref="RtfDialog"/>.</summary>
        [Category("Appearance")]
        [Description("Indicates whether the applicaiton build info is displayed in the RtfDialog.")]
        [DefaultValue(true)]
        public bool ShowBuildInfo
        {
            get { return this._showBuildInfo; }
            set
            {
                if (this._showBuildInfo != value)
                {
                    this._showBuildInfo = value;
                    this.ux_buildInfo.Visible = value;
                    this.AlignBuildInfoAndLicense();
                }
            }
        }
        /// <summary>
        /// Gets or sets whether the "View LGPLv2.1" and "View ExcelDataReader License" buttons are displayed in the
        /// <see cref="RtfDialog"/>.
        /// </summary>
        [Category("Appearance")]
        [Description("Indicates whether the \"View LGPLv2.1\" and \"View ExcelDataReader License\" buttons are displayed in the RtfDialog.")]
        [DefaultValue(true)]
        public bool ShowLicenseButtons
        {
            get { return this._showLicenseButtons; }
            set
            {
                if (this._showLicenseButtons != value)
                {
                    this._showLicenseButtons = value;
                    this.ux_viewLGPLv21.Visible = value;
                    this.ux_viewExcelDataReaderLicense.Visible = value;
                    this.AlignBuildInfoAndLicense();
                }
            }
        }

        #endregion

        #region <<< Variables >>>

        #region /* UI Variables */

        RichTextBox ux_rtf;
        Panel       ux_buttons;
        LinkLabel   ux_viewLGPLv21;
        LinkLabel   ux_viewExcelDataReaderLicense;
        Button      ux_okButton;
        Button      ux_cancelButton;
        Button      ux_yesButton;
        Button      ux_noButton;
        Label       ux_buildInfo;

        #endregion

        PromptOption _promptOption;
        bool         _showBuildInfo;
        bool         _showLicenseButtons;

        #endregion

	}
}
