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 BoxCreation : ObjectCreationBasePhysical
    {
        public Vector3 Center;
        public Vector3 BoxSize;


        public BoxCreation() : base()
        {
            InitializeComponent();
            labelObjectName.Text = "Box Mesh";
            textBoxName.Text = "Box";
            Center = new Vector3();
            BoxSize = new Vector3(1);
            this.textBoxBoxSize.Text = "1 : 1 : 1";
        }


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

            AABox aabox;

            Vector3 Minimum, Maximum;
            Vector3 halfsize = BoxSize;
            halfsize.Mul(0.5f);
            Minimum = Maximum = Center;
            Minimum.Substract(ref halfsize);
            Maximum.Add(ref halfsize);

            aabox = new AABox(Minimum, Maximum);
            //var boxobj = GeoFactory.CreateBox(VertexType, Minimum, Maximum, out aabox);           

            if ((bounding == BoundingObjectType.BestFit) ||(bounding == BoundingObjectType.Box))
            {
                boundobject = aabox;
            }
            else if (bounding == BoundingObjectType.Sphere)
            {
                float radius = halfsize.X;
                if (halfsize.Y > radius)
                    radius = halfsize.Y;
                if (halfsize.Z > radius)
                    radius = halfsize.Z;
                boundobject = new Sphere(Center, radius);
            }

            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;

                rb.InertiaTensor = Matrix3.CreateInertiaCuboid(2 * halfsize.X, 2 * halfsize.Y, 2 * halfsize.Z, physsettings.Mass);
                rb.BoundingObject = boundobject;
                rb.PhysicalBody = aabox;

                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(aabox, VertexType, mat);
                gn.CreateMesh();
                gn.BoundingObject = boundobject;
                gn.Trans = itrans;
                gn.Pickable = pickable;
                owner.AddNode(gn, name);
                owner = gn;

                if (rval == null)
                    rval = gn;

            }
            
            if (DoStatic(physbody))
            {
                StaticCollision sc = new StaticCollision();
                sc.Material = new PhysMaterial(physsettings.DynamicFriction, physsettings.StaticFriction, physsettings.Restitution);
                sc.StaticGeometry = aabox;
                sc.GeoType = StaticCollisionType.ExplicitConvex;
                owner.AddNode(sc, "staticcol_" + name);
                sc.Pickable = !DoVisual(physbody);
                if (rval == null)
                    rval = sc;
            }
            return rval;
        }

        public override void SetDefault()
        {
            base.SetDefault();
            Center = new Vector3();
            textBoxName.Text = "Box";
            this.textBoxBoxCenter.Text = string.Format("{0} : {1} : {2}",
                Center.X.ToString("F"), Center.Y.ToString("F"), Center.Z.ToString("F"));
            this.textBoxBoxSize.Text = string.Format("{0} : {1} : {2}",
                BoxSize.X.ToString("F"), BoxSize.Y.ToString("F"), BoxSize.Z.ToString("F"));
        }

        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(textBoxBoxCenter.Text);
            if (vec.IsValid())
            {
                Center = vec;
            }
            else
            {
                MessageBox.Show("Invalid vector format!");
                this.textBoxBoxCenter.Text = string.Format("{0} : {1} : {2}",
                    Center.X.ToString("F"), Center.Y.ToString("F"), Center.Z.ToString("F"));
            }
        }

        private void CheckBoxSize()
        {
            Vector3 vec = ParseString(textBoxBoxSize.Text);
            if (vec.IsValid())
            {
                BoxSize = vec;
            }
            else
            {
                MessageBox.Show("Invalid vector format!");
                this.textBoxBoxSize.Text = string.Format("{0} : {1} : {2}",
                    BoxSize.X.ToString("F"), BoxSize.Y.ToString("F"), BoxSize.Z.ToString("F"));
            }
        }

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

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

        private void BoxSizeFocusLeave(object sender, EventArgs e)
        {
            CheckBoxSize();
        }

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


    public class CreateBoxItem : CreateNewItem
    {
        public CreateBoxItem(MainBuilderForm boss)
            : base(boss, "Box", "Normal box with settable center and width / height / thickness")
        {
            RefreshBaseCreator();
        }

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