using System;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using DevComponents.DotNetBar;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
namespace DevComponents.AdvTree
{
    internal class ColumnHeaderControl : Control
    {
        #region Constructor
        /// 
        /// Initializes a new instance of the ColumnHeaderControl class.
        /// 
        public ColumnHeaderControl()
        {
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.Opaque, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.Selectable, false);
            this.SetStyle(ControlStyles.StandardDoubleClick | ControlStyles.StandardClick, true);
        }
        #endregion
        #region Internal Implementation
        protected override void OnPaint(PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            DisplayHelp.FillRectangle(g, this.ClientRectangle, this.BackColor);
            if (_Columns == null)
            {
                return;
            }
            AdvTree tree = GetTree();
            if (tree != null)
            {
                SmoothingMode sm = g.SmoothingMode;
                TextRenderingHint th = g.TextRenderingHint;
                if (tree.AntiAlias)
                {
                    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                    g.TextRenderingHint = DisplayHelp.AntiAliasTextRenderingHint;
                }
                //Creates the drawing matrix with the right zoom;
                if (tree.Zoom != 1)
                {
                    System.Drawing.Drawing2D.Matrix mx = GetTranslationMatrix(tree.Zoom);
                    //use it for drawing
                    g.Transform = mx;
                }
                tree.NodeDisplay.PaintColumnHeaders(_Columns, g, true);
                int columnMoveMarkerIndex = _ColumnMoveMarkerIndex;
                if (columnMoveMarkerIndex >= 0)
                    DevComponents.AdvTree.Display.ColumnHeaderDisplay.PaintColumnMoveMarker(g, tree, columnMoveMarkerIndex, _Columns);
                if (tree.AntiAlias)
                {
                    g.SmoothingMode = sm;
                    g.TextRenderingHint = th;
                }
            }
            base.OnPaint(e);
        }
        private int _ColumnMoveMarkerIndex = -1;
        /// 
        /// Gets or sets the column move marker that marks insertion point for column that is dragged. Marker is drawn before the column specified by this index.
        /// 
        internal int ColumnMoveMarkerIndex
        {
            get { return _ColumnMoveMarkerIndex; }
            set
            {
                _ColumnMoveMarkerIndex = value;
                this.Invalidate();
            }
        }
        
        /// 
        /// Returns mouse position which is translated if control Zoom is not equal 1
        /// 
        /// X coordinate
        /// Y coordinate
        /// 
        private Point GetLayoutPosition(float zoom, int x, int y)
        {
            if (zoom == 1)
                return new Point(x, y);
            Point[] p = new Point[] { new Point(x, y) };
            using (System.Drawing.Drawing2D.Matrix mx = GetTranslationMatrix(zoom))
            {
                mx.Invert();
                mx.TransformPoints(p);
            }
            return p[0];
        }
        private System.Drawing.Drawing2D.Matrix GetTranslationMatrix(float zoom)
        {
            System.Drawing.Drawing2D.Matrix mx = new System.Drawing.Drawing2D.Matrix(zoom, 0, 0, zoom, 0, 0);
            return mx;
        }
        private AdvTree GetTree()
        {
            return this.Parent as AdvTree;
        }
        private ColumnHeaderCollection _Columns = null;
        /// 
        /// Gets or sets the column header collection to be rendered.
        /// 
        public ColumnHeaderCollection Columns
        {
            get { return _Columns; }
            set { _Columns = value; }
        }
        private Cursor _OldCursor = null;
        private ColumnHeader _MouseOverColumnHeader = null;
        protected override void OnMouseMove(MouseEventArgs e)
        {
            AdvTree tree = GetTree();
            Point p = GetLayoutPosition(tree.Zoom, e.X, e.Y);
            ColumnHeader ch = tree.GetColumnAt(p.X, p.Y, _Columns);
            if (_MouseOverColumnHeader != ch)
            {
                if (_MouseOverColumnHeader != null)
                    _MouseOverColumnHeader.InternalMouseLeave(e);
                _MouseOverColumnHeader = ch;
                if (_MouseOverColumnHeader != null)
                {
                    _MouseOverColumnHeader.InternalMouseEnter(e);
                    Interop.WinApi.ResetHover(this);
                }
            }
            if (ch != null)
            {
                ch.InternalMouseMove(e);
            }
            if (e.Button == MouseButtons.Left && _MouseDownHeader != null && tree.AllowUserToReorderColumns && (Math.Abs(_MouseDownPoint.X-e.X)>1))
            {
                tree.StartColumnReorder(p.X, p.Y);
                return;
            }
            if (tree == null || e.Button != MouseButtons.None || !tree.AllowUserToResizeColumns) return;
            
            if (tree.CanResizeColumnAt(p.X, p.Y))
            {
                if (_OldCursor == null)
                {
                    _OldCursor = this.Cursor;
                    this.Cursor = Cursors.VSplit;
                }
            }
            else 
            {
                ReleaseCursor();
            }
            base.OnMouseMove(e);
        }
        ColumnHeader _MouseDownHeader = null;
        private Point _MouseDownPoint = Point.Empty;
        protected override void OnMouseDown(MouseEventArgs e)
        {
            AdvTree tree = GetTree();
            Point p = Point.Empty;
            
            bool canResize = false;
            _MouseDownPoint = e.Location;
            if (tree != null)
            {
                p = GetLayoutPosition(tree.Zoom, e.X, e.Y);
            }
            if (tree != null && tree.AllowUserToResizeColumns && e.Button == MouseButtons.Left)
                canResize = tree.CanResizeColumnAt(p.X, p.Y);
            if (tree != null)
            {
                p = GetLayoutPosition(tree.Zoom, e.X, e.Y);
                ColumnHeader ch = tree.GetColumnAt(p.X, p.Y, _Columns);
                if (ch != null)
                {
                    _MouseDownHeader = ch;
                    if (!canResize)
                        ch.OnMouseDown(e);
                }
            }
            if (tree == null || e.Button != MouseButtons.Left || !tree.AllowUserToResizeColumns) return;
            if (canResize)
            {
                tree.StartColumnResize(p.X, p.Y);
            }
            this.Invalidate();
            base.OnMouseDown(e);
        }
        protected override void OnMouseHover(EventArgs e)
        {
            if (Control.MouseButtons == MouseButtons.None)
            {
                AdvTree tree = GetTree();
                Point p = this.PointToClient(Control.MousePosition);
                p = GetLayoutPosition(tree.Zoom, p.X, p.Y);
                ColumnHeader ch = tree.GetColumnAt(p.X, p.Y, _Columns);
                if (ch != null)
                {
                    ch.InternalMouseHover(e);
                }
            }
            base.OnMouseHover(e);
        }
        protected override void OnMouseUp(MouseEventArgs e)
        {
            ReleaseCursor();
            _MouseDownPoint = Point.Empty;
            if (_MouseDownHeader!=null)
            {
                _MouseDownHeader.OnMouseUp(e);
                _MouseDownHeader = null;
            }
            this.Invalidate();
            base.OnMouseUp(e);
        }
        protected override void OnClick(EventArgs e)
        {
            AdvTree tree = GetTree();
            Point p = Point.Empty;
            if (tree != null)
            {
                Point tp = tree.PointToClient(Control.MousePosition);
                p = GetLayoutPosition(tree.Zoom, tp.X, tp.Y);
                ColumnHeader ch = tree.GetColumnAt(p.X, p.Y, _Columns);
                if (ch != null)
                {
                    ch.OnClick(e);
                }
            }
            this.Invalidate();
            base.OnClick(e);
        }
        internal DateTime IgnoreDoubleClickTime = DateTime.MinValue;
        
        protected override void OnDoubleClick(EventArgs e)
        {
            AdvTree tree = GetTree();
            Point p = Point.Empty;
            if (tree != null)
            {
                Point tp = tree.PointToClient(Control.MousePosition);
                p = GetLayoutPosition(tree.Zoom, tp.X, tp.Y);
                ColumnHeader ch = tree.GetColumnAt(p.X, p.Y, _Columns);
                if (ch != null)
                {
                    DateTime now = DateTime.Now;
                    if (IgnoreDoubleClickTime != DateTime.MinValue && now.Subtract(IgnoreDoubleClickTime).TotalMilliseconds <= SystemInformation.DoubleClickTime)
                    {
                        IgnoreDoubleClickTime = DateTime.MinValue;
                        return;
                    }
                    IgnoreDoubleClickTime = DateTime.MinValue;
                    ch.OnDoubleClick(e);
                }
            }
            this.Invalidate();
            base.OnDoubleClick(e);
        }
        private void ReleaseCursor()
        {
            if (_OldCursor != null)
            {
                this.Cursor = _OldCursor;
                _OldCursor = null;
            }
        }
        protected override void OnMouseLeave(EventArgs e)
        {
            if (_MouseOverColumnHeader != null)
            {
                _MouseOverColumnHeader.InternalMouseLeave(e);
                _MouseOverColumnHeader = null;
            }
            if (Control.MouseButtons != MouseButtons.Left)
                ReleaseCursor();
            base.OnMouseLeave(e);
        }
        #endregion
    }
}