#if NETFX || NETCORE

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Drawing2D;

namespace Apewer.Surface
{

    internal class BlockShadow : BaseForm
    {

        #region definition

        private BlockForm _parent;

        #endregion

        #region this

        public void Constructor()
        {
            this.Optimize();

            _parent.TopMost = TopMost = _parent.TopMost;
            _parent.BringToFront();

            this.Location = new Point(_parent.Location.X - 100, _parent.Location.Y - 100);
            this.Width = _parent.Width + 200;
            this.Height = _parent.Height + 200;

            this.TopMost = _parent.TopMost;
            this.ShowInTaskbar = false;
            this.FormBorderStyle = FormBorderStyle.None;
            this.Icon = _parent.Icon;
            this.ShowIcon = _parent.ShowIcon;
            this.Text = _parent.Text;

            FormsUtility.UpdateShadow(this, ShadowImage(Width, Height));
            FormsUtility.MousePenetration(this);

            this.Paint += Event_This_Paint;

            _parent.LocationChanged += new EventHandler(Main_LocationChanged);
            _parent.SizeChanged += new EventHandler(Main_SizeChanged);
            _parent.VisibleChanged += new EventHandler(Main_VisibleChanged);
            _parent.ResizeBegin += Event_Form_ResizeBegin;
            _parent.ResizeEnd += Event_Form_Resizeend;
        }

        public BlockShadow(BlockForm argGraceForm)
        {
            _parent = argGraceForm;
            Constructor();
        }

        #endregion

        #region base

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cParms = base.CreateParams;
                cParms.ExStyle |= 0x00080000; // WS_EX_LAYERED
                return cParms;
            }
        }

        #endregion

        #region event

        private void Event_This_Paint(object sender, PaintEventArgs e)
        {
        }

        private void Event_Form_Resizeend(object sender, EventArgs e)
        {
            //this.Visible = true;
        }

        private void Event_Form_ResizeBegin(object sender, EventArgs e)
        {
            //this.Visible = false;
        }

        private void Main_LocationChanged(object sender, EventArgs e)
        {
            Location = new Point(_parent.Left - 100, _parent.Top - 100);
        }

        private void Main_SizeChanged(object sender, EventArgs e)
        {
            this.Size = new Size(_parent.Width + 200, _parent.Height + 200);
            FormsUtility.UpdateShadow(this, ShadowImage(Width, Height));
        }

        private void Main_VisibleChanged(object sender, EventArgs e)
        {
            this.Visible = _parent.Visible;
        }

        #endregion

        #region shadow

        private Bitmap ShadowImage(int argWidth, int argHeight, bool argFocus = true)
        {
            return ShadowImage_1(argWidth, argHeight, argFocus);
        }

        private Bitmap ShadowImage_2(int argWidth, int argHeight, bool argFocus = true)
        {
            var vbitmap = new Bitmap(argWidth, argHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            var vg = Graphics.FromImage(vbitmap);
            vg.Clear(Color.FromArgb(0, 0, 0, 0));
            vg.SmoothingMode = SmoothingMode.HighQuality;
            vg.CompositingMode = CompositingMode.SourceCopy;

            int vwidth = _parent.Width + 200;
            int vheight = _parent.Height + 200;
            if ((vwidth > Screen.PrimaryScreen.Bounds.Width) || (vheight > Screen.PrimaryScreen.Bounds.Height))
            {
                //using (var vp = new Pen(bordercolor)) vg.DrawRectangle(vp, 100, 100, Width - 200, Height - 200);
                vg.Dispose();
                return vbitmap;
            }

            for (int i = 0; i < 100; i++)
            {
                var vrect = new Rectangle(i, i, vwidth - (i * 2), vheight - (i * 2));
                var vpath = FormsUtility.CreatePath(vrect, 99 - i);
                var valpha = GetAlpha(99 - i);
                var vpen = new Pen(Color.FromArgb(valpha, 0, 0, 0));
                // var vbrush = new SolidBrush(Color.FromArgb(valpha, 0, 0, 0));
                vg.DrawRectangle(vpen, vrect);
                //vg.DrawPath(vpen, vpath);
                //vg.FillPath(vbrush, vpath);
                //vbrush.Dispose();
                vpen.Dispose();
                vpath.Dispose();
            }

            //for (int i = 0; i < 100; i++)
            //{
            //    var vrect = new Rectangle(i, i, 100 - i, 100 - i);
            //    var valpha = getalpha(99 - i);
            //    using (var vbrush = new SolidBrush(Color.FromArgb(valpha, 0, 0, 0)))
            //    {
            //        vg.FillPie(vbrush, vrect, 180, 90);
            //        vg.FillPie(vbrush, new Rectangle(0,0,100,100));
            //    }
            //}

            //using (var vbrush = new SolidBrush(Color.Transparent))
            //{

            //    vg.FillRectangle(vbrush, new Rectangle(100, 100, vwidth - 200, vheight - 200));
            //}

            //using (var vbrush = new SolidBrush(Color.Transparent))
            //{
            //    vg.FillRectangle(vbrush, new Rectangle(100, 100, vwidth - 200, vheight - 200));
            //}

            vg.Dispose();
            return vbitmap;
        }

        private Bitmap ShadowImage_1(int argWidth, int argHeight, bool argFocus = true)
        {
            var vbitmap = new Bitmap(argWidth, argHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            var vg = Graphics.FromImage(vbitmap);
            vg.Clear(Color.FromArgb(0, 0, 0, 0));

            int vwidth = _parent.Width + 200;
            int vheight = _parent.Height + 200;
            if ((vwidth > Screen.PrimaryScreen.Bounds.Width) || (vheight > Screen.PrimaryScreen.Bounds.Height))
            {
                //using (var vp = new Pen(bordercolor)) vg.DrawRectangle(vp, 100, 100, Width - 200, Height - 200);
                vg.Dispose();
                return vbitmap;
            }

            // 边角距离补偿
            int vcorneroffset = 2;

            // 上
            for (int y = 0; y <= 99; y++)
            {
                double vl = 100 - y;
                using (var vp = new Pen(Color.FromArgb(GetAlpha(vl), 0, 0, 0))) vg.DrawLine(vp, 100, y, argWidth - 101, y);
            }

            // 下
            for (int y = argHeight - 100; y <= argHeight - 2; y++)
            {
                double vl = y - (argHeight - 101);
                using (var vp = new Pen(Color.FromArgb(GetAlpha(vl), 0, 0, 0))) vg.DrawLine(vp, 100, y, argWidth - 101, y);
            }

            // 左
            for (int x = 0; x <= 99; x++)
            {
                double vl = 100 - x;
                using (var vp = new Pen(Color.FromArgb(GetAlpha(vl), 0, 0, 0))) vg.DrawLine(vp, x, 100, x, argHeight - 101);
            }

            // 右
            for (int x = argWidth - 100; x <= argWidth - 2; x++)
            {
                double vl = x - (argWidth - 101);
                using (var vp = new Pen(Color.FromArgb(GetAlpha(vl), 0, 0, 0))) vg.DrawLine(vp, x, 100, x, argHeight - 101);
            }

            // 左上
            for (int x = 0; x <= 99; x++)
            {
                for (int y = 0; y <= 99; y++)
                {
                    double vx = 100 - x; double vy = 100 - y;
                    double vl = Math.Sqrt((vx * vx) + (vy * vy)) + vcorneroffset;
                    vbitmap.SetPixel(x, y, Color.FromArgb(GetAlpha(vl), 0, 0, 0));
                }
            }

            // 右上
            for (int x = argWidth - 100; x <= argWidth - 1; x++)
            {
                for (int y = 0; y <= 99; y++)
                {
                    double vx = 100 - (argWidth - x); double vy = 100 - y;
                    double vl = Math.Sqrt((vx * vx) + (vy * vy)) + vcorneroffset;
                    vbitmap.SetPixel(x, y, Color.FromArgb(GetAlpha(vl), 0, 0, 0));
                }
            }

            // 左下
            for (int x = 0; x <= 99; x++)
            {
                for (int y = argHeight - 100; y <= argHeight - 1; y++)
                {
                    double vx = 100 - x; double vy = 100 - (argHeight - y);
                    double vl = Math.Sqrt((vx * vx) + (vy * vy)) + vcorneroffset;
                    vbitmap.SetPixel(x, y, Color.FromArgb(GetAlpha(vl), 0, 0, 0));
                }
            }

            // 右下
            for (int x = argWidth - 100; x <= argWidth - 1; x++)
            {
                for (int y = argHeight - 100; y <= argHeight - 1; y++)
                {
                    double vx = 100 - (argWidth - x); double vy = 100 - (argHeight - y);
                    double vl = Math.Sqrt((vx * vx) + (vy * vy)) + vcorneroffset;
                    vbitmap.SetPixel(x, y, Color.FromArgb(GetAlpha(vl), 0, 0, 0));
                }
            }

            vg.Dispose();
            return vbitmap;
        }

        private static int GetAlpha(double argLength, bool argFocus = true)
        {
            // 返回值。
            double valpha = 0;

            // 参数。
            double vl = argLength;
            if (vl < 0) vl = 0;
            if (vl > 100) vl = 100;

            // 常数。
            double alphamax = 0; // 0 <= x <=255

            // 过程变量。
            double x = 0, y = 0, xmax = 0, ymax = 0, lmax = 0, tanmax = 0, ratio = 0; ;

            // 选择方法。
            int vmethod = 1; // flat from 4

            switch (vmethod)
            {

                case 0: // 穷举
                    ratio = 0.5;
                    int vlint = (int)argLength;
                    switch (vlint)
                    {
                        #region switch block
                        case 0: return 40;
                        case 1: return 39;
                        case 2: return 38;
                        case 3: return 37;
                        case 4: return 36;
                        case 5: return 36;
                        case 6: return 35;
                        case 7: return 34;
                        case 8: return 33;
                        case 9: return 33;
                        case 10: return 32;
                        case 11: return 31;
                        case 12: return 30;
                        case 13: return 30;
                        case 14: return 29;
                        case 15: return 28;
                        case 16: return 28;
                        case 17: return 27;
                        case 18: return 26;
                        case 19: return 26;
                        case 20: return 25;
                        case 21: return 24;
                        case 22: return 24;
                        case 23: return 23;
                        case 24: return 23;
                        case 25: return 22;
                        case 26: return 21;
                        case 27: return 21;
                        case 28: return 20;
                        case 29: return 20;
                        case 30: return 19;
                        case 31: return 19;
                        case 32: return 18;
                        case 33: return 17;
                        case 34: return 17;
                        case 35: return 16;
                        case 36: return 16;
                        case 37: return 15;
                        case 38: return 15;
                        case 39: return 14;
                        case 40: return 14;
                        case 41: return 13;
                        case 42: return 13;
                        case 43: return 12;
                        case 44: return 12;
                        case 45: return 12;
                        case 46: return 11;
                        case 47: return 11;
                        case 48: return 10;
                        case 49: return 10;
                        case 50: return 10;
                        case 51: return 9;
                        case 52: return 9;
                        case 53: return 8;
                        case 54: return 8;
                        case 55: return 8;
                        case 56: return 7;
                        case 57: return 7;
                        case 58: return 7;
                        case 59: return 6;
                        case 60: return 6;
                        case 61: return 6;
                        case 62: return 5;
                        case 63: return 5;
                        case 64: return 5;
                        case 65: return 4;
                        case 66: return 4;
                        case 67: return 4;
                        case 68: return 4;
                        case 69: return 3;
                        case 70: return 3;
                        case 71: return 3;
                        case 72: return 3;
                        case 73: return 2;
                        case 74: return 2;
                        case 75: return 2;
                        case 76: return 2;
                        case 77: return 2;
                        case 78: return 1;
                        case 79: return 1;
                        case 80: return 1;
                        case 81: return 1;
                        case 82: return 1;
                        case 83: return 1;
                        case 84: return 1;
                        case 85: return 0;
                        case 86: return 0;
                        case 87: return 0;
                        case 88: return 0;
                        case 89: return 0;
                        case 90: return 0;
                        case 91: return 0;
                        case 92: return 0;
                        case 93: return 0;
                        case 94: return 0;
                        case 95: return 0;
                        case 96: return 0;
                        case 97: return 0;
                        case 98: return 0;
                        case 99: return 0;
                        case 100: return 0;
                            #endregion
                    }
                    break;

                case 1: // 正比例
                    ratio = 0.2;
                    valpha = (100 - vl) * ratio;
                    break;

                case 2: // 正切函数
                    alphamax = 55;
                    tanmax = 0.45; // 0 < x < 0.5
                    valpha = (Math.Tan(Math.PI * tanmax * ((100 - vl) / 100)) / Math.Tan(Math.PI * tanmax)) * alphamax;
                    break;

                case 3: // 正弦函数
                    lmax = 40;
                    if (vl <= lmax)
                    {
                        y = (lmax - vl) * (lmax - vl);
                        alphamax = 30;
                        xmax = Math.PI / 2;
                        x = ((lmax - vl) / lmax) * xmax;
                        if (x < 0) x = 0;
                        if (x > Math.PI / 2) x = Math.PI / 2;
                        valpha = (Math.Sin(Math.PI * 1.5 + x) + 1) * alphamax;
                    }
                    else valpha = 0;
                    break;

                case 4: // 平方函数
                    lmax = 100;
                    if (vl <= lmax)
                    {
                        alphamax = 40;
                        y = (lmax - vl) * (lmax - vl);
                        valpha = (y / (lmax * lmax)) * alphamax;
                    }
                    else valpha = 0;
                    break;

                case 5: // 幂函数
                    lmax = 40;
                    if (vl <= lmax)
                    {
                        alphamax = 1;
                        ratio = 1.1;
                        x = lmax - vl;
                        y = Math.Pow(ratio, x);
                        ymax = Math.Pow(ratio, lmax);
                        valpha = (y / ymax) * alphamax;
                    }
                    else valpha = 0;
                    break;

                case 6:
                    if (vl <= 40) valpha = 40 - vl;
                    else valpha = 0;
                    break;
            }
            if (valpha < 0) valpha = 0; if (valpha > 255) valpha = 255;
            return (int)valpha;
        }

        #endregion

    }

}

#endif