using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DevExpress.XtraBars.Controls;
using NodePinDirPXP.Crawler.API.Utils;
using PXP.Crawler.API.Designers.Controls.Forms;
using PXP.Crawler.API.Model;
using PXP.Crawler.API.Utils;

namespace PXP.Crawler.API.Designers.Controls
{
    public class ProgramNodesControl : ScrollableControl
    {

        internal class OverlayControl : Control
        {
            internal ProgramNodesControl prNodesControl;
            private Bitmap prBitmap;
            private bool hasPrBitmap = false;
            private bool internalPaintCall = false;

            public OverlayControl(ProgramNodesControl pnCont)
            {
                prNodesControl = pnCont;
                SetStyle(ControlStyles.Opaque, true);
                SetStyle(ControlStyles.Selectable, true);
                SetStyle(ControlStyles.ContainerControl, true);
                SetStyle(ControlStyles.StandardClick, true);
                SetStyle(ControlStyles.SupportsTransparentBackColor, false);
                SetStyle(ControlStyles.DoubleBuffer, true);
                SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

                UpdateStyles();
                //base.BackColor = Color.Magenta;
            }

            protected override void Dispose(bool disposing)
            {
                if (prBitmap != null)
                {
                    prBitmap.Dispose();
                    prBitmap = null;
                    hasPrBitmap = false;
                }
                
                base.Dispose(disposing);
            }

            protected override void OnResize(EventArgs e)
            {
                base.OnResize(e);


                if (prBitmap != null)
                {
                    prBitmap.Dispose();
                    prBitmap = null;
                    hasPrBitmap = false;
                }

                if (prNodesControl.Width > 0 & prNodesControl.Height > 0)
                {
                    prBitmap = new Bitmap(prNodesControl.Width, prNodesControl.Height, PixelFormat.Format32bppPArgb);
                    hasPrBitmap = true;
                }
            }

            public void DoOverlayBackUpdate()
            {
                if (hasPrBitmap)
                {

                    internalPaintCall = true;
                    try
                    {
                        prNodesControl.DrawToBitmap(prBitmap, prNodesControl.ClientRectangle);
                        prBitmap.MakeTransparent(prNodesControl.BackColor);
                    }
                    catch (ArgumentException argExc)
                    {
                        int d = 10;
                    }
                    internalPaintCall = false;
                }
            }

            protected override void OnPaint(PaintEventArgs e)
            {
                if (internalPaintCall)
                {

                }
                else
                {
                    if (hasPrBitmap)
                    {                        
                        e.Graphics.SetClip(e.ClipRectangle);
                        e.Graphics.Clear(prNodesControl.BackColor);
                        Point adjPos = new Point(-prNodesControl.AutoScrollPosition.X, -prNodesControl.AutoScrollPosition.Y);
                        prNodesControl.connsControl.Draw(e, adjPos, true);
                        e.Graphics.DrawImageUnscaled(prBitmap, 0, 0);

                        base.OnPaint(e);
                    }
                }
            }

            protected override void OnPaintBackground(PaintEventArgs pevent)
            {
                if (!internalPaintCall)
                {
                    //pevent.Graphics.Clear(BackColor);
                }
                else
                {
                    
                }
            }
        }

        internal class ConnsControl : Control
        {
            internal ProgramNodesControl pnCont;
            internal Point tempSourcePos = new Point();
            internal Point tempTargetPos = new Point();
            internal bool tempVisible = false;
            internal bool tempConnEnabled = false;
            internal string tempConnInfo = "";

            private Pen tempConnPen;
            private Pen tempConnBackPen;

            internal bool updateBeziers = true;

            public ConnsControl(ProgramNodesControl progNodesControl)
            {
                pnCont = progNodesControl;

                SetStyle(ControlStyles.UserPaint, true);
                SetStyle(ControlStyles.AllPaintingInWmPaint, true);
                SetStyle(ControlStyles.Opaque, true);
                SetStyle(ControlStyles.Selectable, false);
                SetStyle(ControlStyles.StandardClick, false);
                SetStyle(ControlStyles.SupportsTransparentBackColor, false);
                SetStyle(ControlStyles.DoubleBuffer, true);
                SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

                UpdateStyles();

                //BackColor = Color.FromArgb(111, 111, 111);
                //BackColor = Color.FromArgb(255, 0, 255);
                //BackColor = Color.Transparent;

                tempConnPen = new Pen(Brushes.White, 2);
                tempConnPen.StartCap = LineCap.Flat;
                tempConnPen.EndCap = LineCap.Flat;
                tempConnBackPen = new Pen(Color.FromArgb(80, Color.Black), 5);
                tempConnBackPen.StartCap = LineCap.Flat;
                tempConnBackPen.EndCap = LineCap.Flat;
            }

            protected override void Dispose(bool disposing)
            {
                tempConnPen.Dispose();
                tempConnBackPen.Dispose();
                base.Dispose(disposing);
            }

            protected override void WndProc(ref Message m)
            {
                if (m.Msg == (int)Win32.WindowsMessage.NCHITTEST)
                {
                    m.Result = (IntPtr)Win32.HitTest.TRANSPARENT;
                }
                else
                {
                    base.WndProc(ref m);
                }
            }

            /*protected override CreateParams CreateParams
            {
                get
                {
                    CreateParams cp = base.CreateParams;
                    cp.ExStyle |= 0x20;
                    return cp;
                }
            }*/
            
            /*protected override void OnPaintBackground(PaintEventArgs pevent)
            {
                pevent.Graphics.Clear(Parent.BackColor);
            }*/

            public Point srcHandPoint = new Point();
            public Point targHandPoint = new Point();

            public void Draw(PaintEventArgs e, bool clearBack = true)
            {
                Draw(e, new Point(), clearBack);
            }

            public void Draw(PaintEventArgs e, Point adjPos, bool clearBack = true)
            {
                if (DesignMode)
                    return;

                //e.Graphics.Clear(Color.Transparent);
                if (clearBack)
                    e.Graphics.Clear(BackColor);

                e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

                if (tempVisible)
                {
                    tempSourcePos.X -= pnCont.AutoScrollPosition.X;
                    tempSourcePos.Y -= pnCont.AutoScrollPosition.Y;
                    tempTargetPos.X -= pnCont.AutoScrollPosition.X;
                    tempTargetPos.Y -= pnCont.AutoScrollPosition.Y;

                    Point tsCPoint = tempSourcePos;
                    Point ttCPoint = tempTargetPos;

                    int yDiff = Math.Abs(tempSourcePos.Y - tempTargetPos.Y) / 2;
                    if (tempSourcePos.Y < tempTargetPos.Y)
                    {
                        tsCPoint.Y += yDiff;
                        ttCPoint.Y -= yDiff;
                        srcHandPoint.Y = yDiff;
                        targHandPoint.Y = -yDiff;
                    }
                    else
                    {
                        tsCPoint.Y -= yDiff;
                        ttCPoint.Y += yDiff;
                        srcHandPoint.Y = -yDiff;
                        targHandPoint.Y = yDiff;
                    }


                    e.Graphics.DrawBezier(tempConnBackPen, tempSourcePos, tsCPoint, ttCPoint, tempTargetPos);

                    if (tempConnEnabled)
                    {
                        tempConnPen.Color = Color.FromArgb(255, Color.GreenYellow);
                    }
                    else
                    {
                        tempConnPen.Color = Color.FromArgb(255, Color.Red);
                    }

                    e.Graphics.DrawBezier(tempConnPen, tempSourcePos, tsCPoint, ttCPoint, tempTargetPos);


                    PointF bp = Misc.BezierPoint(0.5f, tempSourcePos, tsCPoint, ttCPoint, tempTargetPos);
                    SizeF infoSizeF = e.Graphics.MeasureString(tempConnInfo, Font);
                    bp.X -= infoSizeF.Width * 0.5f;


                    e.Graphics.DrawString(tempConnInfo, Font, Brushes.Black, new PointF(bp.X + 1, bp.Y + 1));
                    if (tempConnEnabled)
                    {
                        e.Graphics.DrawString(tempConnInfo, Font, Brushes.GreenYellow, bp);
                    }
                    else
                    {
                        e.Graphics.DrawString(tempConnInfo, Font, Brushes.LightGray, bp);
                    }

                    //e.Graphics.DrawRectangle(Pens.Orange, new Rectangle(tsCPoint, new Size(3, 3)));
                    //e.Graphics.DrawRectangle(Pens.Orange, new Rectangle(ttCPoint, new Size(3, 3)));
                }

                tempConnPen.Color = Color.DarkGray;

                if (pnCont.program != null)
                {
                    foreach (NodeConnection nConn in pnCont.program.connections.Values)
                    {
                        if (nConn.target.designer != null)
                        {
                            if (nConn.target.designer.control.Visible && nConn.source.designer.control.Visible)
                            {
                                nConn.Draw(e.Graphics, tempConnBackPen, tempConnPen, pnCont.sHandleBrush, pnCont.tHandleBrush, adjPos, updateBeziers);
                            }                            
                        }
                    }
                }
            }

            protected override void OnPaint(PaintEventArgs e)
            {
                Draw(e);
            }
        }

        internal Program program;

        public Point oldScrollPos = new Point();

        private float prW = 150;
        private float prH;

        internal bool previewVisible = true;
        private bool hasPreviewBitmap = false;

        internal OverlayControl overlayControl;
        internal ConnsControl connsControl;
        internal bool isInit = false;

        private Brush sHandleBrush;
        private Brush tHandleBrush;

        private Color prevBackColor;

        ColorMatrix transColorMatrix = new ColorMatrix(new float[][] { 
            new float[] {1, 0, 0, 0, 0},
            new float[] {0, 1, 0, 0, 0},
            new float[] {0, 0, 1, 0, 0},
            new float[] {0, 0, 0, 0.8f, 0}, 
            new float[] {0, 0, 0, 0, 1}});
        
        ImageAttributes transImageAtt = new ImageAttributes();

        public ProgramNodesControl()
        {
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.Selectable, true);
            SetStyle(ControlStyles.DoubleBuffer, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.StandardClick, true);
            SetStyle(ControlStyles.ContainerControl, true);

            UpdateStyles();

            InitializeComponent();

            VerticalScroll.Enabled = false;
            VerticalScroll.Visible = false;
            VerticalScroll.Maximum = 0;
            HorizontalScroll.Enabled = false;
            HorizontalScroll.Visible = false;
            HorizontalScroll.Maximum = 0;

            transImageAtt.SetColorMatrix(
               transColorMatrix,
               ColorMatrixFlag.Default,ColorAdjustType.Bitmap);

            sHandleBrush = new SolidBrush(Color.FromArgb(150, Color.ForestGreen));
            tHandleBrush = new SolidBrush(Color.FromArgb(150, Color.DodgerBlue));

            connsControl = new ConnsControl(this);
            Controls.Add(connsControl);
            connsControl.Size = ClientRectangle.Size;
            connsControl.Dock = DockStyle.Fill;

            overlayControl = new OverlayControl(this);
            Controls.Add(overlayControl);
            overlayControl.Size = ClientRectangle.Size;
            //overlayControl.Dock = DockStyle.Fill;
            overlayControl.Visible = false;

            //connsControl.BackColor = BackColor;
            connsControl.Visible = true;



            isInit = true;
        }
      

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            ((HandledMouseEventArgs) e).Handled = true;
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            connsControl.Size = ClientRectangle.Size;
            overlayControl.Size = ClientRectangle.Size;
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // ProgramNodesControl
            // 
            this.AutoScroll = true;
            this.ResumeLayout(false);

        }

        protected override void Dispose(bool disposing)
        {
            
            hasPreviewBitmap = false;
            sHandleBrush.Dispose();
            tHandleBrush.Dispose();
            base.Dispose(disposing);
        }


        protected override void WndProc(ref Message m)
        {
            Win32.ShowScrollBar(Handle, (int) Win32.ScrollBarDirection.SB_BOTH, false);
            base.WndProc(ref m);
        }


        protected override void OnControlAdded(ControlEventArgs e)
        {
            base.OnControlAdded(e);
            UpdatePreview();

            //if (connsControl != null)
             //   Controls.SetChildIndex(connsControl, 0);
            if (overlayControl != null)
                Controls.SetChildIndex(overlayControl, 0);
            if (connsControl != null)
                Controls.SetChildIndex(connsControl, Controls.Count - 1);
        }

        protected override void OnControlRemoved(ControlEventArgs e)
        {
            base.OnControlRemoved(e);
            UpdatePreview();
           // if (connsControl != null)
           //     Controls.SetChildIndex(connsControl, 0);

            if (overlayControl != null)
                Controls.SetChildIndex(overlayControl, 0);
            if (connsControl != null)
                Controls.SetChildIndex(connsControl, Controls.Count - 1);
        }

        public void UpdatePreview()
        {
        }
        

  

    }
}

