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

namespace VisimBox.Physics
{

    public enum StaticCollisionType
    {
        /// <summary>
        /// Only for XML reading failure, DONOT use
        /// </summary>
        Unknown,
        /// <summary>
        /// Explicit vertex based object (can be pretransformed)
        /// </summary>
        ExplicitConvex,
        /// <summary>
        /// Implicit convex object (sphere, cone...) - can't be pretransformed
        /// </summary>
        ImplicitConvex,
        /// <summary>
        /// List of explicit convex objects
        /// </summary>
        ListOfExplicit,
        /// <summary>
        /// List of implicit objects
        /// </summary>
        ListOfImplicit,
        /// <summary>
        /// Polygon soup, just a lot of triangles
        /// </summary>
        PolygonSoup
    }
    
    /// <summary>
    /// Clas for static physical collisions 
    /// </summary>
    public class StaticCollision : PhysNode
    {
        /// <summary>
        /// Material describing the surface of the body
        /// </summary>
        public PhysMaterial Material;

        /// <summary>
        /// IGeometry describing the collision
        /// Note, only types describable by StaticCollisionType should be used. For geometry type which won't fit 
        /// in either cathegory geometry must be divided
        /// </summary>
        public IGeometry StaticGeometry;

        /// <summary>
        /// Descriptor of static geometry for quick choosing, should be set to correct value!
        /// </summary>
        public StaticCollisionType GeoType;

        public override RenderFlags DefaultRenderFlags
        {
            get
            {
                return Scene.RenderFlags.PhysicalCollision;
            }
        }

        public StaticCollision()
        {
        }

        /// <summary>
        /// XML reader constructor
        /// </summary>
        /// <param name="reader">XML reader</param>
        public StaticCollision(XmlReader reader)
            : base(reader)
        {
        }


        public override bool ReadInternalData(XmlReader reader)
        {
            if (base.ReadInternalData(reader))
                return true;

            if (reader.Name == "StaticGeo")
            {
                StaticGeometry = GeoFactory.ReadXml(reader);
                return true;
            }
            else if (reader.Name == "Material")
            {
                Material = new PhysMaterial(reader);
                return true;
            }
            else if (reader.Name == "StaticGeoType")
            {
                string geoname = reader.ReadString();
                try
                {
                    GeoType = (StaticCollisionType)(Enum.Parse(typeof(StaticCollisionType), geoname));
                }
                catch
                {
                    VisimBox.Console.DebugLine("Static geometry loading - static geo type failure, unknown type " + geoname);
                    return false;
                }                
                return true;
            }
            else return false;
        }

        public override void WriteInternalData(XmlWriter writer)
        {
            base.WriteInternalData(writer);
            if (Material != null)
            {
                Material.WriteXml(writer, "Material");
            }
            if (StaticGeometry == null)
                return;
            writer.WriteElementString("StaticGeoType", GeoType.ToString());
            writer.WriteStartElement("StaticGeo");
            StaticGeometry.WriteXml(writer);
            writer.WriteEndElement();
        }

        protected override void CopyData(Node targetNode)
        {
            base.CopyData(targetNode);

            StaticCollision mynode = targetNode as StaticCollision;
            if (mynode == null)
            {
                VisimBox.Console.DebugLine(FullName + " asked to do copy to different node type!");
                return;
            }

            if (StaticGeometry == null)
                return;
            mynode.GeoType = GeoType;
            mynode.StaticGeometry = StaticGeometry.GetCopy();
            if (Material != null)
                mynode.Material = new PhysMaterial(Material);
        }


        public override void RenderGeometry(Renderer.RendererEventArgs args)
        {
            //throw new NotImplementedException();
        }
    }
}
