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 VisiMath;
using VisiMath.Geometry;
using VisimBox;
using VisimBox.Renderer;
using VisimBox.Scene;
using VisimBox.Physics;

namespace VisimBuilder.ObjectCreation
{
    public partial class QuadCreation : ObjectCreationBasePhysical
    {
        public Vector3 Center;
        float QuadWidth, QuadHeight;
        int Orientation;

        public QuadCreation() : base()
        {
            InitializeComponent();
            labelObjectName.Text = "Quad Mesh";
            textBoxName.Text = "Quad";
            QuadWidth = 1;
            QuadHeight = 1;
            Orientation = 0;
            Center = new Vector3();
        }


        public override Node ObjectCreation(string name, ITransformation itrans, Type VertexType, PhysBodyType physbody, PhysSettingsEdit physsettings, BoundingObjectType bounding, IRenderMaterial mat, Node owner)
        {
            IGeometry boundobject = null;

            Vector3 normal;
            switch (Orientation)
            {
                case 0:
                    normal = Vector3.UnitX;
                    break;
                case 1:
                    normal = Vector3.UnitY;
                    break;
                case 2:
                    normal = Vector3.UnitZ;
                    break;
                case 3:
                    normal = -Vector3.UnitX;
                    break;
                case 4:
                    normal = -Vector3.UnitY;
                    break;
                default:
                    normal = -Vector3.UnitZ;
                    break;
            }

            QuadList ql = GeoFactory.CreateQuad(VertexType, Center, QuadWidth, QuadHeight, normal);

            if (bounding == BoundingObjectType.BestFit)
            {
                boundobject = GeoFactory.CreateBoundingObject(ql);
            }
            else if (bounding == BoundingObjectType.Sphere)
            {
                boundobject = GeoFactory.CreateBoundingSphere(ql);
            }
            else if (bounding == BoundingObjectType.Box)
            {
                boundobject = GeoFactory.CreateBoundingBox(ql);
            }

            ConvexHull cv = new ConvexHull(ql.ToIndexedMesh());

            bool pickable = true;

            Node rval = null;

            if (DoRigid(physbody))
            {

                RigidBody rb = new RigidBody(null as Node);

                rb.Mass = physsettings.Mass;
                rb.Material = new PhysMaterial(physsettings.DynamicFriction, physsettings.StaticFriction, physsettings.Restitution);

                rb.Sleeping = physsettings.Sleeping;
                rb.DampingType = DampingType.Timed;
                rb.Damping = physsettings.Damping;
                rb.AngularDampingType = DampingType.Timed;
                rb.AngularDamping = physsettings.AngDamping;

                rb.Velocity = physsettings.Velocity;
                rb.Acceleration = physsettings.Acceleration;
                rb.AngularVelocity = physsettings.AngularVelocity;
                rb.AngularAcceleration = physsettings.AngularAcceleration;

                switch (Orientation)
                {
                    case 0:
                    case 3:
                        rb.InertiaTensor = Matrix3.CreateInertiaCuboid(0, QuadWidth, QuadHeight, physsettings.Mass);
                        break;
                    case 1:
                    case 4:
                        rb.InertiaTensor = Matrix3.CreateInertiaCuboid(QuadWidth, 0, QuadHeight, physsettings.Mass);
                        break;
                    case 2:
                    case 5:
                        rb.InertiaTensor = Matrix3.CreateInertiaCuboid(QuadWidth, QuadHeight, 0, physsettings.Mass);
                        break;
                }

                rb.BoundingObject = boundobject;
                rb.PhysicalBody = cv;

                rb.Trans = itrans;
                owner.AddNode(rb, name);
                owner = rb;

                //have to be done after node is in hierarchy!
                rb.HasStandardGravity = physsettings.GravityEnabled;

                itrans = null;
                boundobject = null;
                pickable = false;
                name = "renderable" + name;
                rval = rb;
            }

            if (DoVisual(physbody))
            {
                GeometryNode gn = new GeometryNode(ql, VertexType, mat);    //todo - replace by single quad?
                gn.CreateMesh();
                gn.BoundingObject = boundobject;
                gn.Trans = itrans;
                gn.Pickable = pickable;
                owner.AddNode(gn, name);
                owner = gn;
            }

            if (DoStatic(physbody))
            {
                StaticCollision sc = new StaticCollision();
                sc.Material = new PhysMaterial(physsettings.DynamicFriction, physsettings.StaticFriction, physsettings.Restitution);
                sc.StaticGeometry = cv;
                sc.GeoType = StaticCollisionType.ExplicitConvex;
                sc.Pickable = !DoVisual(physbody);

                owner.AddNode(sc, "staticcol_" + name);
                if (rval == null)
                    rval = sc;
            }
            return rval;
        }


        public override void SetDefault()
        {
            base.SetDefault();
            Center = new Vector3();
            textBoxName.Text = "Quad";
            QuadWidth = 1; QuadHeight = 1;
            Orientation = 0;
            this.textBoxQuadCenter.Text = string.Format("{0} : {1} : {2}",
                Center.X.ToString("F"), Center.Y.ToString("F"), Center.Z.ToString("F"));
            textBoxWidth.Text = QuadWidth.ToString("F");
            textBoxHeight.Text = QuadHeight.ToString("F");
            radioButton1.Checked = true;
        }

        public Vector3 ParseString(string str)
        {
            StringParser parser = new StringParser(str, ':');
            if (parser.WordCount != 3)
                return Vector3.Invalid;
            if (!parser.IsFloat(0) || !parser.IsFloat(1) || !parser.IsFloat(2))
                return Vector3.Invalid;

            return new Vector3(parser.GetFloat(0), parser.GetFloat(1), parser.GetFloat(2));
        }
        
        private void CheckCenter()
        {
            Vector3 vec = ParseString(textBoxQuadCenter.Text);
            if (vec.IsValid())
            {
                Center = vec;
            }
            else
            {
                MessageBox.Show("Invalid vector format!");
                this.textBoxQuadCenter.Text = string.Format("{0} : {1} : {2}",
                    Center.X.ToString("F"), Center.Y.ToString("F"), Center.Z.ToString("F"));
            }
        }

        private void CenterKeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)13)
            {
                CheckCenter();
            }

        }

        private void CheckWidth()
        {
            try
            {
                float rad = (float)Convert.ToDouble(textBoxWidth.Text);
                QuadWidth = rad;
            }
            catch
            {
                textBoxWidth.Text = QuadWidth.ToString("F");
                MessageBox.Show("Invalid size format!");
            }
        }

        private void CheckHeight()
        {
            try
            {
                float rad = (float)Convert.ToDouble(textBoxHeight.Text);
                QuadHeight = rad;
            }
            catch
            {
                textBoxHeight.Text = QuadWidth.ToString("F");
                MessageBox.Show("Invalid size format!");
            }
        }


        private void CenterFocusLeave(object sender, EventArgs e)
        {
            CheckCenter();
        }

        private void KeyPressWidth(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)13)
            {
                CheckWidth();
            }
        }

        private void KeyPressHeight(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)13)
            {
                CheckHeight();
            }
        }

        private void FocusLeaveHeight(object sender, EventArgs e)
        {
            CheckHeight();
        }

        private void FocusLeaveWidth(object sender, EventArgs e)
        {
            CheckWidth();
        }

        private void Radio0Check(object sender, EventArgs e)
        {
            Orientation = 0;
        }

        private void Radio1Check(object sender, EventArgs e)
        {
            Orientation = 1;
        }

        private void Radio2Check(object sender, EventArgs e)
        {
            Orientation = 2;
        }

        private void Radio3Check(object sender, EventArgs e)
        {
            Orientation = 3;
        }

        private void Radio4Check(object sender, EventArgs e)
        {
            Orientation = 4;
        }

        private void Radio5Check(object sender, EventArgs e)
        {
            Orientation = 5;
        }
    }


    public class CreateQuadItem : CreateNewItem
    {
        public CreateQuadItem(MainBuilderForm boss)
            : base(boss, "Quad", "3D Rectangle with settable width and height")
        {
            RefreshBaseCreator();
        }

        protected override void RefreshBaseCreator()
        {
            BaseCreator = new QuadCreation();
            BaseCreator.Init(Boss);
        }
    }
}
