using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VisiMath;
using VisimBox;
using VisimBox.Renderer;
using VisimBox.Scene;
using VisiMath.Geometry;

namespace VisimBuilder
{
    /// <summary>
    /// base class for gizmos
    /// </summary>
    public abstract class Gizmo : Node
    {
        public bool InLocalCoords = false;

        protected MainBuilderForm Boss;
        protected Matrix4 targettrans = new Matrix4();
        protected Matrix4 mytrans = Matrix4.Identitity;
        protected Matrix4 myinverted = Matrix4.Identitity;
        protected IRenderMaterial material;
        protected Ray MyPickingRay;

        public bool Dragging = false;
        /// <summary>
        /// Movement speed modifier for mouse movement
        /// </summary>
        public float MoveSpeed { get; set; }

        public int SelectedPart;




        public Gizmo(MainBuilderForm boss) : base()
        {
            DontSave = true;
            Boss = boss;
        }

        public virtual void CreateMaterial(IRenderContext irc)
        {
            if (material != null)
                return;

            MaterialManager man = irc.Renderer.MaterialMan;

            if (man.Contains("GizmoMaterial"))
            {
                material = man["GizmoMaterial"];
                return;
            }

            material = man.Add("GizmoMaterial", ColorByte.White);
        }


        public virtual void Render(IRenderContext irc)
        {
            Node target = Boss.SelectedNode;
            if (target == null)
                return;

            if (!target.GetWorldTransformation(ref targettrans))
                return;

            if (material == null)
                CreateMaterial(irc);

            RendererEventArgs args = new RendererEventArgs(irc.Renderer, irc, null);

            material.Activate(args);

            bool rv = irc.ZBufferUsing;
            irc.ZBufferUsing = false;

            SetTransform();

            MyRender(irc);


            irc.ZBufferUsing = rv;
        }


        public virtual void SetTransform()
        {
            if (InLocalCoords)
            {
                mytrans = targettrans;
                myinverted = Matrix4.Invert(ref mytrans);
            }
            else
            {
                Vector3 center = targettrans.Translation;
                mytrans = Matrix4.CreateTranslation(ref center);
                myinverted = Matrix4.CreateTranslation(-center);
            }
        }

        public abstract void MyRender(IRenderContext irc);

        public virtual bool MouseMove(float deltax, float deltay, Ray ray)
        {
            if (Boss.SelectedNode == null)
                return false;
            if (Dragging)
            {
                Vector3 origo = MyPickingRay.Direction;
                UpdateMyRay(ray);

                origo.Substract(ref MyPickingRay.Direction);

                float dist = -MoveSpeed * MathTools.Sqrt(deltax * deltax + deltay * deltay);
                MyMove(dist, origo);

                var light = Boss.SelectedNode as LightNode;
                if (light != null)
                    light.UpdateLight(0);
            }
            return true;
        }

        public abstract void MyMove(float dist, Vector3 origo);

        public virtual bool MouseHover(Ray ray)
        {
            if (Dragging)
                return false;
            if (Boss.SelectedNode == null)
                return false;

            UpdateMyRay(ray);

            SelectedPart = 0;
            return true;
        }

        public virtual bool MouseUp(Ray ray)
        {
            if (Dragging)
            {
                Dragging = false;
                return true;
            }
            return false;
        }

        public virtual void UpdateMyRay(Ray ray)
        {
            if (MyPickingRay == null)
                MyPickingRay = new Ray();
            MyPickingRay.FromDirection(ray.Origin, ray.Direction);
            MyPickingRay.Transform(ref myinverted);
        }

        public virtual bool MouseDown(Ray ray)
        {
            if (SelectedPart != 0)
                Dragging = true;
            else Dragging = false;
            return Dragging;
        }

    }
}
