using DevExpress.Utils.Drawing;
using DevExpress.Utils.Extensions;
using DevExpress.XtraSplashScreen;
using DevExpress.XtraWaitForm;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DxHelper
{
    /// <summary>
    /// 等待窗体帮助类,包含WaitForm、OverlayForm、
    /// </summary>
    public static class WaitHelper
    {
        #region private field
        private static IOverlaySplashScreenHandle _handle;
        private static OverlayTextPainter _overlayLabel = new OverlayTextPainterEx();
        private static List<string> _tips = new List<string>();
        private static Random _random = new Random();
        private static DateTime _updateTime;
        #endregion

        #region public function
        /// <summary>
        /// 显示等待窗体
        /// </summary>
        /// <param name="title">标题</param>
        /// <param name="caption">文本</param>
        /// <param name="owner">等待窗体的父窗体,默认值为激活的主程序窗体</param>
        public static void ShowWaitForm(string title, string caption, Form owner = null)
        {
            SplashScreenManager.ShowForm(owner, typeof(MyWaitForm), true, true, false);
            SplashScreenManager.Default.SetWaitFormCaption(title);//标题
            SplashScreenManager.Default.SetWaitFormDescription(caption);//描述    
        }

        /// <summary>
        /// 显示等待窗体(文本固定为请稍后和加载中...)
        /// </summary>
        /// <param name="owner">等待窗体的父窗体,默认值为激活的主程序窗体</param>
        public static void ShowWaitForm(Form owner = null)
        {
            SplashScreenManager.ShowForm(owner, typeof(MyWaitForm), true, true, false);
            SplashScreenManager.Default.SetWaitFormCaption("请稍后");//标题 
            SplashScreenManager.Default.SetWaitFormDescription("加载中...");//描述

        }

        /// <summary>
        /// 关闭等待窗体和程序启动画面窗体
        /// </summary>
        public static void CloseForm()
        {
            SplashScreenManager.CloseForm(false, 0, null);
        }

        /// <summary>
        /// 在某个control上显示半透明遮罩层
        /// </summary>
        /// <param name="owner">遮罩层覆盖的Control</param>
        public static void ShowOverlayForm(Control owner)
        {
            int opacity = 180;
            if (SystemInformation.TerminalServerSession)
                opacity = 255; //远程桌面(RDP)下禁用opacity,否则网络可能会卡断
            if (owner == null || !owner.Visible) return;
            _overlayLabel.Font = new Font(owner.Font.FontFamily, 18);
            _overlayLabel.Text = null;
            _handle = SplashScreenManager.ShowOverlayForm(owner, opacity: opacity, fadeIn: false, fadeOut: false, customPainter: new OverlayWindowCompositePainter(_overlayLabel));
        }

        /// <summary>
        /// 更新遮罩层上的文本
        /// </summary>
        /// <param name="text"></param>
        public static void UpdateOverlyText(string text)
        {
            _overlayLabel.Text = text;
        }

        /// <summary>
        /// 关闭上一次显示的半透明遮罩层
        /// </summary>
        public static void CloseOverlayForm()
        {
            if (_handle == null) return;
            if (!string.IsNullOrWhiteSpace(_overlayLabel.Text))
            {
                Task.Run(() =>
                {
                    Thread.Sleep(1000);

                    SplashScreenManager.CloseOverlayForm(_handle);

                });
            }
            else
                SplashScreenManager.CloseOverlayForm(_handle);
        }
        /// <summary>
        /// 显示程序启动画面
        /// </summary>
        public static void ShowSplashScreen(string title, string company)
        {
            SplashScreenManager.ShowForm(typeof(MySplashScreen)); //调用
            SplashScreenManager.Default?.SendCommand(SplashScreenCommand.UpdateTitle, title);
            SplashScreenManager.Default?.SendCommand(SplashScreenCommand.UpdateCompany, company);
            _updateTime = DateTime.Now;
            Task.Run(() =>
            {
                var tips = _tips.Skip(0).ToList();
                while (true)
                {
                    while ((DateTime.Now - _updateTime).TotalMilliseconds < 2000)
                    {
                        Thread.Sleep(100);
                    }
                    var tipsIdx = _random.Next(0, tips.Count);
                    var res = UpdateSplashMessage(_tips[tipsIdx]);
                    if (!res) break;
                    tips.RemoveAt(tipsIdx);
                    if (!tips.Any()) break;
                }
            });
        }

        /// <summary>
        /// 更新启动画面窗体的文本消息
        /// </summary>
        /// <param name="msg"></param>
        /// <returns>如果启动窗体已关闭返回false,否则返回true</returns>
        public static bool UpdateSplashMessage(string msg)
        {
            _updateTime = DateTime.Now;
            if (SplashScreenManager.Default == null || !SplashScreenManager.Default.IsSplashFormVisible) return false;
            SplashScreenManager.Default?.SendCommand(SplashScreenCommand.UpdateMessage, msg);
            return true;
        }

        public static void SetSplashTips(IEnumerable<string> tips)
        {

            _tips.Clear();
            _tips.AddRange(tips);
        }
        public static void SetSplashTips(string tipsFile)
        {
            _tips.Clear();
            if (File.Exists(tipsFile))
                _tips.AddRange(File.ReadAllLines(tipsFile));
        }
        #endregion

        #region internal class
        class OverlayTextPainterEx : OverlayTextPainter
        {
            protected override Rectangle CalcTextBounds(OverlayLayeredWindowObjectInfoArgs drawArgs)
            {
                Size textSz = CalcTextSize(drawArgs);
                return textSz.AlignWith(drawArgs.Bounds).WithY(drawArgs.ImageBounds.GetCenterPoint().Y - textSz.Height / 2);
            }
        }
        partial class MyWaitForm : WaitForm
        {
            private Form owner;
            public MyWaitForm()
            {
                InitializeComponent();
                this.progressPanel1.AutoHeight = true;
                this.StartPosition = FormStartPosition.CenterParent;
            }

            #region Overrides

            public override void SetCaption(string caption)
            {
                base.SetCaption(caption);
                this.progressPanel1.Caption = caption;
            }
            public override void SetDescription(string description)
            {
                base.SetDescription(description);
                this.progressPanel1.Description = description;
            }
            public override void ProcessCommand(Enum cmd, object arg)
            {
                base.ProcessCommand(cmd, arg);
            }

            #endregion

            public enum WaitFormCommand
            {
            }
            public void ShowWaitForm(Form owner, string description, string caption)
            {
                SplashScreenManager.ShowForm(owner, typeof(WaitHelper), true, true, false);
                SplashScreenManager.Default.SetWaitFormDescription(description);//描述
                SplashScreenManager.Default.SetWaitFormCaption(caption);//标题    
            }


            public void ShowWaitForm(Form owner)
            {
                this.owner = owner;
                SplashScreenManager.ShowForm(owner, typeof(WaitHelper), true, true, false);
            }

            public void CloseWaitForm()
            {
                SplashScreenManager.CloseForm(false, 0, owner);
            }

        }
        partial class MyWaitForm
        {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;

            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }

            #region Windows Form Designer generated code

            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                this.progressPanel1 = new DevExpress.XtraWaitForm.ProgressPanel();
                this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
                this.tableLayoutPanel1.SuspendLayout();
                this.SuspendLayout();
                // 
                // progressPanel1
                // 
                this.progressPanel1.Appearance.BackColor = System.Drawing.Color.Transparent;
                this.progressPanel1.Appearance.Options.UseBackColor = true;
                this.progressPanel1.AppearanceCaption.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F);
                this.progressPanel1.AppearanceCaption.Options.UseFont = true;
                this.progressPanel1.AppearanceDescription.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F);
                this.progressPanel1.AppearanceDescription.Options.UseFont = true;
                this.progressPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
                this.progressPanel1.ImageHorzOffset = 20;
                this.progressPanel1.Location = new System.Drawing.Point(0, 17);
                this.progressPanel1.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
                this.progressPanel1.Name = "progressPanel1";
                this.progressPanel1.Size = new System.Drawing.Size(246, 39);
                this.progressPanel1.TabIndex = 0;
                this.progressPanel1.Text = "progressPanel1";
                // 
                // tableLayoutPanel1
                // 
                this.tableLayoutPanel1.AutoSize = true;
                this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
                this.tableLayoutPanel1.BackColor = System.Drawing.Color.Transparent;
                this.tableLayoutPanel1.ColumnCount = 1;
                this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
                this.tableLayoutPanel1.Controls.Add(this.progressPanel1, 0, 0);
                this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
                this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
                this.tableLayoutPanel1.Name = "tableLayoutPanel1";
                this.tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(0, 14, 0, 14);
                this.tableLayoutPanel1.RowCount = 1;
                this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
                this.tableLayoutPanel1.Size = new System.Drawing.Size(246, 73);
                this.tableLayoutPanel1.TabIndex = 1;
                // 
                // Form1
                // 
                this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.AutoSize = true;
                this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
                this.ClientSize = new System.Drawing.Size(246, 73);
                this.Controls.Add(this.tableLayoutPanel1);
                this.DoubleBuffered = true;
                this.Name = "Form1";
                this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
                this.Text = "Form1";
                this.tableLayoutPanel1.ResumeLayout(false);
                this.ResumeLayout(false);
                this.PerformLayout();
            }

            #endregion

            private DevExpress.XtraWaitForm.ProgressPanel progressPanel1;
            private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
        }

        partial class MySplashScreen : SplashScreen
        {
            public MySplashScreen()
            {
                InitializeComponent();
                this.labMsg.Text = "";
                peImage.Properties.Appearance.Font = new Font(peImage.Properties.Appearance.Font.FontFamily, 16);
                peImage.Properties.NullText = "某系统";
                this.labelCopyright.Text = $"Copyright © {DateTime.Now.Year} 总参第五十七研究所";
            }
            #region Overrides

            public override void ProcessCommand(Enum cmd, object arg)
            {
                var command = (SplashScreenCommand)cmd;
                base.ProcessCommand(cmd, arg);
                if (command == SplashScreenCommand.UpdateMessage)
                {
                    this.labMsg.Text = arg.ToString();
                }
                else if (command == SplashScreenCommand.UpdateTitle)
                {
                    peImage.Properties.NullText = arg?.ToString();
                }
                else if (command == SplashScreenCommand.UpdateCompany && arg != null && !string.IsNullOrWhiteSpace(arg.ToString()))
                {
                    this.labelCopyright.Text = $"Copyright © {DateTime.Now.Year} {arg}";
                }
                else if (command == SplashScreenCommand.UpdateCompany && (arg == null || string.IsNullOrWhiteSpace(arg.ToString())))
                {
                    this.labelCopyright.Visible = false;
                }
            }

            #endregion


        }
        enum SplashScreenCommand
        {
            UpdateMessage,
            UpdateTitle,
            UpdateCompany
        }
        partial class MySplashScreen
        {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;

            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }

            #region Windows Form Designer generated code

            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                this.progressBarControl = new DevExpress.XtraEditors.MarqueeProgressBarControl();
                this.labelCopyright = new DevExpress.XtraEditors.LabelControl();
                this.labMsg = new DevExpress.XtraEditors.LabelControl();
                this.peImage = new DevExpress.XtraEditors.PictureEdit();
                this.tablePanel1 = new DevExpress.Utils.Layout.TablePanel();
                ((System.ComponentModel.ISupportInitialize)(this.progressBarControl.Properties)).BeginInit();
                ((System.ComponentModel.ISupportInitialize)(this.peImage.Properties)).BeginInit();
                ((System.ComponentModel.ISupportInitialize)(this.tablePanel1)).BeginInit();
                this.tablePanel1.SuspendLayout();
                this.SuspendLayout();
                // 
                // progressBarControl
                // 
                this.progressBarControl.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
                | System.Windows.Forms.AnchorStyles.Right)));
                this.progressBarControl.EditValue = 0;
                this.progressBarControl.Location = new System.Drawing.Point(24, 230);
                this.progressBarControl.Name = "progressBarControl";
                this.progressBarControl.Size = new System.Drawing.Size(402, 11);
                this.progressBarControl.TabIndex = 5;
                // 
                // labelCopyright
                // 
                this.labelCopyright.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
                this.tablePanel1.SetColumn(this.labelCopyright, 1);
                this.labelCopyright.Location = new System.Drawing.Point(191, 8);
                this.labelCopyright.Name = "labelCopyright";
                this.tablePanel1.SetRow(this.labelCopyright, 0);
                this.labelCopyright.Size = new System.Drawing.Size(66, 20);
                this.labelCopyright.TabIndex = 6;
                this.labelCopyright.Text = "Copyright";
                // 
                // labMsg
                // 
                this.labMsg.Location = new System.Drawing.Point(24, 198);
                this.labMsg.Margin = new System.Windows.Forms.Padding(3, 3, 3, 1);
                this.labMsg.Name = "labMsg";
                this.labMsg.Size = new System.Drawing.Size(62, 20);
                this.labMsg.TabIndex = 7;
                this.labMsg.Text = "Starting...";
                // 
                // peImage
                // 
                this.peImage.Dock = System.Windows.Forms.DockStyle.Top;
                this.peImage.Location = new System.Drawing.Point(1, 1);
                this.peImage.Name = "peImage";
                this.peImage.Properties.AllowFocused = false;
                this.peImage.Properties.Appearance.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(128)))), ((int)(((byte)(255)))));
                this.peImage.Properties.Appearance.Options.UseBackColor = true;
                this.peImage.Properties.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
                this.peImage.Properties.NullText = "系统名称";
                this.peImage.Properties.ShowEditMenuItem = DevExpress.Utils.DefaultBoolean.False;
                this.peImage.Properties.ShowMenu = false;
                this.peImage.Size = new System.Drawing.Size(448, 185);
                this.peImage.TabIndex = 9;
                // 
                // tablePanel1
                // 
                this.tablePanel1.Appearance.BackColor = System.Drawing.Color.Transparent;
                this.tablePanel1.Appearance.Options.UseBackColor = true;
                this.tablePanel1.Columns.AddRange(new DevExpress.Utils.Layout.TablePanelColumn[] {
            new DevExpress.Utils.Layout.TablePanelColumn(DevExpress.Utils.Layout.TablePanelEntityStyle.Relative, 1F),
            new DevExpress.Utils.Layout.TablePanelColumn(DevExpress.Utils.Layout.TablePanelEntityStyle.AutoSize, 0F),
            new DevExpress.Utils.Layout.TablePanelColumn(DevExpress.Utils.Layout.TablePanelEntityStyle.Relative, 1F)});
                this.tablePanel1.Controls.Add(this.labelCopyright);
                this.tablePanel1.Dock = System.Windows.Forms.DockStyle.Bottom;
                this.tablePanel1.Location = new System.Drawing.Point(1, 250);
                this.tablePanel1.Name = "tablePanel1";
                this.tablePanel1.Padding = new System.Windows.Forms.Padding(1);
                this.tablePanel1.Rows.AddRange(new DevExpress.Utils.Layout.TablePanelRow[] {
            new DevExpress.Utils.Layout.TablePanelRow(DevExpress.Utils.Layout.TablePanelEntityStyle.Relative, 1F)});
                this.tablePanel1.Size = new System.Drawing.Size(448, 37);
                this.tablePanel1.TabIndex = 10;
                this.tablePanel1.UseSkinIndents = true;
                // 
                // SplashScreen1
                // 
                this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.ClientSize = new System.Drawing.Size(450, 288);
                this.Controls.Add(this.tablePanel1);
                this.Controls.Add(this.peImage);
                this.Controls.Add(this.labMsg);
                this.Controls.Add(this.progressBarControl);
                this.Name = "SplashScreen1";
                this.Padding = new System.Windows.Forms.Padding(1);
                this.Text = "SplashScreen1";
                ((System.ComponentModel.ISupportInitialize)(this.progressBarControl.Properties)).EndInit();
                ((System.ComponentModel.ISupportInitialize)(this.peImage.Properties)).EndInit();
                ((System.ComponentModel.ISupportInitialize)(this.tablePanel1)).EndInit();
                this.tablePanel1.ResumeLayout(false);
                this.tablePanel1.PerformLayout();
                this.ResumeLayout(false);
                this.PerformLayout();

            }

            #endregion

            private DevExpress.XtraEditors.MarqueeProgressBarControl progressBarControl;
            private DevExpress.XtraEditors.LabelControl labelCopyright;
            private DevExpress.XtraEditors.LabelControl labMsg;
            private DevExpress.XtraEditors.PictureEdit peImage;
            private DevExpress.Utils.Layout.TablePanel tablePanel1;
        }
        #endregion
    }


}