using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace VisiMath.Geometry
{
    /// <summary>
    /// Base vertex based class for all geometries
    /// </summary>
    public abstract class Geometry : BaseGeometry
    {
        /// <summary>
        /// Vertices of the geometry
        /// </summary>
        public IVertexArray Vertices;

        #region Constructors

        /// <summary>
        /// default constructor
        /// </summary>
        protected Geometry()
        {
        }

        /// <summary>
        /// Constructs Geometry with vertex array with specified number of vertices
        /// Uses basic Vertex type
        /// </summary>
        /// <param name="count">Number of vertices</param>
        protected Geometry(int count)
        {
            Vertices = new VertexArray<Vertex>(count);
        }

        /// <summary>
        /// Construct geometry from vertexarray of vertices
        /// </summary>
        /// <param name="vert">Vertex array with vertices</param>
        protected Geometry(IVertexArray vert)
        {
            Vertices = vert;
        }

        /// <summary>
        /// Construct geometry from vertexarray of vertices with different type
        /// </summary>
        /// <param name="vert">Vertex array with vertices</param>
        /// <param name="VertexType">Required type of the vertex</param>
        protected Geometry(Type VertexType, IVertexArray vert)
        {
            VertexFactory.CopyVertexArray(VertexType, vert, out Vertices);
        }

        /// <summary>
        /// Constructs geometry with specified count of the vertices
        /// </summary>
        /// <param name="vertextype">Required type of the vertex</param>
        /// <param name="count">Number of vertices</param>
        protected Geometry(Type vertextype, int count)
        {
            Vertices = VertexFactory.CreateArray(vertextype, count);
        }

        /// <summary>
        /// Constructs geometry with specified count of the vertices
        /// </summary>
        /// <param name="count">Number of vertices</param>
        /// <typeparam name="T">Type of the vertex</typeparam>
        protected void Construct<T>(int count)
            where T : IVertex
        {
            Vertices = new VertexArray<T>(count);
        }

        /// <summary>
        /// XML reader constructor
        /// </summary>
        /// <param name="reader">XML reader</param>
        public Geometry(System.Xml.XmlReader reader)
            : base(reader)
        {
        }

        #endregion

        #region IGeometry Members


        /// <summary>
        /// Center of the object
        /// </summary>        
        public override Vector3 Center { 
            get
            {
                Vector3 vec = new Vector3();
                for (int i = 0; i < Vertices.Count; i++)
                {
                    vec.Add(Vertices.Positions[i]);
                }
                vec.Divide(Vertices.Count);                
                return vec;
            }
        }

        #endregion


        /// <summary>
        /// Returns position of the vertex on specified index
        /// </summary>
        /// <param name="index">Vertex index</param>
        /// <returns>Position data</returns>
        public virtual Vector3 GetPosition(int index)
        {
            Vector3 rval;
            GetPosition(index, out rval);
            return rval;
        }

        /// <summary>
        /// Returns all positional vertices in simple array
        /// </summary>
        /// <returns>Array of all positional vertices</returns>
        public virtual Vector3[] GetAllPositions()
        {
            int size = Vertices.Count;
            Vector3[] rval = new Vector3[size];

            for (int i = 0; i < Vertices.Count; i++)
            {
                GetPosition(i, out rval[i]);
            }
            return rval;
        }

        /// <summary>
        /// Returns position of the vertex on specified index
        /// </summary>
        /// <param name="index">Vertex index</param>
        /// <param name="vec">Position data</param>
        public virtual void GetPosition(int index, out Vector3 vec)
        {
            vec = Vertices[index].Position;
        }

        /// <summary>
        /// Returns vertex on the specified index
        /// </summary>
        /// <param name="index">Index of the vertex</param>
        /// <returns>Vertex</returns>
        public virtual IVertex GetVertex(int index)
        {
            return Vertices[index];
        }

        /// <summary>
        /// Preferred type of the vertex
        /// </summary>
        public override Type PreferredVertexType
        {
            get { 
                if (Vertices!=null)
                    return Vertices[0].GetType();
                return typeof(NormalVertex);
            }
        }

        /// <summary>
        /// Deserializes object from XML
        /// </summary>
        /// <param name="reader">XML reader</param>
        public override void ReadXml(System.Xml.XmlReader reader)
        {
            if (reader["type"] != this.GetType().Name)
                throw new ArgumentException("Geometry:ReadXML - wrong type specified!");

            while (reader.Read())
            {
                if (reader.IsStartElement("Vertices"))
                {
                    Vertices = VertexFactory.ReadFromXml(reader);
                }
                else return;
            }
        }

        /// <summary>
        /// Serializes object to XML
        /// </summary>
        /// <param name="writer">XML writer to save values</param>
        public override void WriteXml(System.Xml.XmlWriter writer)
        {
            writer.WriteAttributeString("type", this.GetType().Name);
           
            writer.WriteStartElement("Vertices");
            Vertices.WriteXml(writer);
            writer.WriteEndElement();
        }

    }
    
}
