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 SphereCreation : ObjectCreationBasePhysical
    {
        public float Radius;
        public Vector3 Center;

        public SphereCreation() : base()
        {
            InitializeComponent();
            labelObjectName.Text = "Sphere Mesh";
            textBoxName.Text = "Sphere";
            Radius = 1;
            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;

            Sphere sph = new Sphere(Center, Radius);

            if ((bounding == BoundingObjectType.BestFit) || (bounding == BoundingObjectType.Sphere))
            {
                boundobject = sph;
            }
            else if (bounding == BoundingObjectType.Box)
            {
                AABox box = new AABox();
                box.Minimum = Center; box.Minimum.Substract(Radius, Radius, Radius);
                box.Maximum = Center; box.Maximum.Add(Radius, Radius, Radius);
                boundobject = box;
            }

            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.CreateInertiaSphere(Radius, physsettings.Mass);
                rb.BoundingObject = boundobject;
                rb.PhysicalBody = sph;

                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;
                name = "renderable" + name;
                pickable = false;
                rval = rb;
            }

            if (DoVisual(physbody))
            {

                float quality = 0.01f * this.trackBar1.Value;
                GeometryNode gn = new GeometryNode(sph, VertexType, mat, quality);
                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 = sph;
                sc.GeoType = StaticCollisionType.ImplicitConvex;
                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 = "Sphere";
            Radius = 1;
            this.textBoxSphereCenter.Text = string.Format("{0} : {1} : {2}",
                Center.X.ToString("F"), Center.Y.ToString("F"), Center.Z.ToString("F"));
            this.textBoxSphereRadius.Text = Radius.ToString("F");
            this.trackBar1.Value = 10;
        }

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

        private void CheckRadius()
        {
            try
            {
                float rad = (float)Convert.ToDouble(textBoxSphereRadius.Text);
                Radius = rad;
            }
            catch
            {
                textBoxSphereRadius.Text = Radius.ToString();
                MessageBox.Show("Invalid radius format!");
            }
        }

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

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

        private void RadiusFocusLeave(object sender, EventArgs e)
        {
            CheckRadius();
        }

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

    public class CreateSphereItem : CreateNewItem
    {
        public CreateSphereItem(MainBuilderForm boss) : base(boss, "Sphere", "Spherical mesh with settable center, radius and quality")
        {
                        RefreshBaseCreator();
        }

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

}
