using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using CommonLang.Geometry.SceneGraph2D;
using CommonLang.Geometry;
using CommonLang;

namespace CommonFroms.SceneGraph2D
{
    public partial class Win32ScenePanel : UserControl
    {
        static Win32ScenePanel()
        {
            Win32SceneGraphFactory.Init();
        }
        private DisplayRoot root;
        private int fps = 30;
        private SystemTimeRecoder update_time = new SystemTimeRecoder();

        public DisplayRoot RootNode { get { return root; } }
        public PictureBox RootCanvas { get { return canvas; } }
        public int Tick { get; private set; }
        public int FPS
        {
            get { return fps; }
            set
            {
                if (fps != value)
                {
                    timer.Interval = 1000 / fps;
                }
            }
        }
        public int CurrentIntervalMS { get { return update_time.CurrentIntervalMS; } }
        public bool AutoUpdate
        {
            get { return timer.Enabled; }
            set
            {
                if (timer.Enabled != value)
                {
                    timer.Enabled = value;
                    update_time.Reset();
                    if (value)
                    {
                        timer.Start();
                    }
                    else
                    {
                        timer.Stop();
                    }
                }
            }
        }

        public Win32ScenePanel()
        {
            InitializeComponent();

            this.canvas.MouseDown += this.camera_MouseDown;
            this.canvas.MouseUp += this.camera_MouseUp;
            this.canvas.MouseMove += this.camera_MouseMove;
            this.canvas.MouseWheel += camera_MouseWheel;

            this.canvas.Paint += canvas_Paint;
            this.timer.Interval = 1000 / fps;
            this.timer.Tick += Timer1_Tick;
            this.MouseRightMoveCamera = true;
        }


        //-----------------------------------------------------------------------------------------------------

        public Vector2 CanvasMouseToRoot(System.Drawing.Point mpos)
        {
            var rpos = root.ParentToLocal(new Vector2(mpos.X, mpos.Y));
            return rpos;
        }
        public Vector2 ScreenMouseToRoot()
        {
            var rpos = canvas.PointToClient(MousePosition);
            return CanvasMouseToRoot(rpos);
        }

        protected virtual DisplayRoot CreateRoot()
        {
            return new DisplayRoot();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            this.root = CreateRoot();
            this.AutoUpdate = true;
        }

        protected virtual void Timer1_Tick(object sender, EventArgs e)
        {
            canvas.Refresh();
            Tick++;
        }

        protected virtual void canvas_Paint(object sender, PaintEventArgs e)
        {
            int intervalMS = update_time.Update();
            OnCanvasUpdate?.Invoke(intervalMS);
            var g = e.Graphics;
            var st = g.Save();
            try
            {
                if (root != null)
                {
                    root.Visit(new Win32Graphics(g));
                }
            }
            catch (Exception err)
            {
                Console.WriteLine(err.Message);
            }
            finally
            {
                g.Restore(st);
            }
            OnCanvasDraw?.Invoke(g);
        }

        protected virtual void canvas_MouseDown(object sender, MouseEventArgs e)
        {
        }
        protected virtual void canvas_MouseMove(object sender, MouseEventArgs e)
        {
        }
        protected virtual void canvas_MouseUp(object sender, MouseEventArgs e)
        {
        }


        public delegate void CanvasDraw(Graphics g);
        public event CanvasDraw OnCanvasDraw;
        public delegate void CanvasUpdate(int intervalMS);
        public event CanvasUpdate OnCanvasUpdate;

        //-----------------------------------------------------------------------------------------------------
        #region Camera

        private bool is_last_mouse_down = false;
        private Vector2 last_mouse_pos;
        private Vector2 last_camera_pos;

        public bool MouseRightMoveCamera { get; set; }

        public Vector2 CameraPos
        {
            get { return -root.Translation; }
            set { this.root.Translation = -value; }
        }
        public float CameraZoom
        {
            get { return root.Scale.X; }
            set { this.root.Scale = new Vector2(value, value); }
        }

        private void camera_MouseDown(object sender, MouseEventArgs e)
        {
            if (MouseRightMoveCamera)
            {
                canvas.Focus();
                if (e.Button == MouseButtons.Right)
                {
                    is_last_mouse_down = true;
                    last_mouse_pos = new Vector2(e.Location.X, e.Location.Y);
                    last_camera_pos = this.CameraPos;
                }
            }
            RefreshCanvas();
        }
        private void camera_MouseMove(object sender, MouseEventArgs e)
        {
            if (MouseRightMoveCamera)
            {
                if (is_last_mouse_down && e.Button == MouseButtons.Right)
                {
                    var offset = new Vector2(
                        last_mouse_pos.X - e.Location.X,
                        last_mouse_pos.Y - e.Location.Y);
                    this.CameraPos = last_camera_pos + offset;
                }
            }
            RefreshCanvas();
        }
        private void camera_MouseUp(object sender, MouseEventArgs e)
        {
            is_last_mouse_down = false;
            RefreshCanvas();
        }
        private void camera_MouseWheel(object sender, MouseEventArgs e)
        {
            if (MouseRightMoveCamera)
            {
                this.CameraZoom += CMath.getDirect(e.Delta) * 0.1f;
            }
            RefreshCanvas(); 
        }

        public void RefreshCanvas()
        {
            if (timer.Enabled == false)
            {
                canvas.Refresh();
            }
        }

        #endregion
        //-----------------------------------------------------------------------------------------------------



    }
}