using Oraycn.ChatRendering;
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace ESFramework.Boost.WinForm
{
    public partial class ChatBox : ScrollableControl, IChatControl
    {
        private IChatRender chatRender;
        internal IChatRender ChatRender
        {
            get
            {
                return chatRender;
            }
        }     

        public System.Drawing.Size RenderSize
        {
            get
            {
                return this.Size;
            }
        }
        public event Action<Point> WhenMouseMove;
        public event Action<Point> WhenMouseLeave;
        public event Action<bool, Point> WhenMouseDown;
        public event Action<bool, Point> WhenMouseUp;
        public event Action<Size> RenderSurfaceSizeChanged;
        public event Action<int> RenderSurfaceYScrollChanged;
        public event Action<bool> VisiableChanged;

        private int verticalOffset => this.VerticalScroll.Value;

        public ChatBox()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);

            this.Scroll += ChatBox_Scroll;
            this.SizeChanged += ChatBox_SizeChanged;
            this.MouseWheel += ChatBox_MouseWheel;           
        }

        private void ChatBox_MouseWheel(object sender, MouseEventArgs e)
        {
            if (this.RenderSurfaceYScrollChanged != null)
            {
                this.RenderSurfaceYScrollChanged(-this.AutoScrollPosition.Y);
                this.Invalidate();
            }
        }

        private void ChatBox_SizeChanged(object sender, EventArgs e)
        {
            if (this.RenderSurfaceSizeChanged != null)
            {
                this.RenderSurfaceSizeChanged(this.Size);
            }
        }

        private void ChatBox_Scroll(object sender, ScrollEventArgs e)
        {
            if (this.RenderSurfaceYScrollChanged != null)
            {
                this.RenderSurfaceYScrollChanged(-this.AutoScrollPosition.Y);   
                this.Invalidate();
            }
        }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="chatRender">聊天消息渲染器。</param>
        public void Initialize(IChatRender chatRender)
        {
            this.chatRender = chatRender;
            Graphics graphics = this.CreateGraphics();
            this.chatRender.SetComputeGraphics(graphics);
            this.Paint += ChatBox_Paint;
        }

        private void ChatBox_Paint(object sender, PaintEventArgs e)
        {
            Matrix transform = new Matrix();
            transform.Translate(this.AutoScrollPosition.X, this.AutoScrollPosition.Y);
            e.Graphics.Transform = transform;
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            this.chatRender.Render(e.Graphics);            
        }

        #region IChatControl

        public void SetRenderTotalHeight(int totalHeight)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new Action<int>(this.SetRenderTotalHeight), totalHeight);
            }
            else
            {
                this.AutoScrollMinSize = new Size(this.ClientSize.Width, totalHeight);
                this.Invalidate();
            }
        }            

        public void InvalidateSurface()
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new Action(InvalidateSurface));
            }
            else
            {
                this.Invalidate();
            }
        }
        #endregion

        public void ScrollToBottom()
        {
            this.AutoScrollPosition = new Point(this.AutoScrollPosition.X, this.AutoScrollMinSize.Height - this.Height);
            if (this.RenderSurfaceYScrollChanged != null)
            {
                this.RenderSurfaceYScrollChanged(-this.AutoScrollPosition.Y);
                this.Invalidate();
            }
        }

        public bool IsScrollAtBottom()
        {
            int maxY = this.AutoScrollMinSize.Height - this.Height;
            return maxY - (-this.AutoScrollPosition.Y) <= 5;            
        }

        #region 控件鼠标事件


        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Right)
            {
                if (this.WhenMouseDown != null)
                {
                    Point pt = e.Location;
                    this.WhenMouseDown(e.Button == MouseButtons.Left, new Point(pt.X, pt.Y + verticalOffset));
                }
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            if (this.WhenMouseUp != null)
            {
                Point pt = e.Location;
                if (pt.X < 0 || pt.Y < 0)
                {
                    return;
                }
                this.WhenMouseUp(e.Button == MouseButtons.Left, new Point(pt.X, pt.Y + verticalOffset));
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (this.WhenMouseMove != null)
            {
                Point pt = e.Location;
                this.WhenMouseMove(new Point(pt.X, pt.Y + verticalOffset));
            }
        }

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

            if (this.WhenMouseLeave != null)
            {
                this.WhenMouseLeave(Point.Empty);
            }
        }

        #endregion

    }
}
