using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Xml.Serialization;


namespace VisiMath
{    
    /// <summary>
    /// interface used to access commonly used vertex data
    /// </summary>
    public interface IVertex :IXmlSerializable
    {
        #region Quick acessors for comonly used elements

        /// <summary>
        /// Position vector
        /// </summary>
        Vector3 Position { get; set; }
        /// <summary>
        /// Normal vector
        /// </summary>
        Vector3 Normal { get; set; }
        /// <summary>
        /// Main color
        /// </summary>
        ColorByte Color { get; set; }
        /// <summary>
        /// 2d texture coordinate
        /// </summary>
        Vector2 TexCoord2 { get; set; }

        #endregion

        #region static

        /// <summary>
        /// Creates new vertex
        /// </summary>
        /// <returns>New vertex of the same format</returns>
        IVertex CreateNew();

        /// <summary>
        /// Creates new vertex with specified position
        /// </summary>
        /// <param name="pos">Position</param>
        /// <returns>New vertex of the same format</returns>
        IVertex CreateNew(Vector3 pos);

        /// <summary>
        /// Creates vertex array of this vertex type with specified number of elements
        /// </summary>
        /// <param name="count">Required number of elements</param>
        /// <returns>New vertexarray of this vertex type</returns>
        IVertexArray CreateArray(int count);

        #endregion

        #region Serialization

        void WriteXml(System.Xml.XmlWriter writer, string rootname);

        #endregion
    }
    
    


    #region Standard Vertices types

    /// <summary>
    /// Vertex containg only the position
    /// </summary>
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct PositionVertex :IVertex
    {
        [VertexElement(VertexElementUsage.Position)]
        public Vector3 position;

        public PositionVertex(Vector3 pos)
        {
            position = pos;
        }

        public PositionVertex(ref Vector3 pos)
        {
            position = pos;
        }

        public PositionVertex(float x, float y, float z)
        {
            position = new Vector3(x, y, z);
        }

        #region IVertex Members

        public Vector3 Position
        {
            get
            {
                return position;
            }
            set
            {
                position = value;
            }
        }

        public Vector3 Normal
        {
            get
            {
                return new Vector3();
            }
            set
            {
            }
        }

        public ColorByte Color
        {
            get
            {
                return ColorByte.White;
            }
            set
            {
            }
        }

        public Vector2 TexCoord2
        {
            get
            {
                return new Vector2();
            }
            set
            {
            }
        }

        /// <summary>
        /// Creates new vertex
        /// </summary>
        /// <returns>New vertex of the same format</returns>
        public IVertex CreateNew()
        {
            return new PositionVertex();
        }

        /// <summary>
        /// Creates new vertex with specified position
        /// </summary>
        /// <param name="pos">Position</param>
        /// <returns>New vertex of the same format</returns>
        public IVertex CreateNew(Vector3 pos)
        {
            return new PositionVertex(position);
        }

        /// <summary>
        /// Creates vertex array of this vertex type with specified number of elements
        /// </summary>
        /// <param name="count">Required number of elements</param>
        /// <returns>New vertexarray of this vertex type</returns>
        public IVertexArray CreateArray(int count)
        {
            return new VertexArray<PositionVertex>(count);
        }

        #endregion



        #region IXmlSerializable Members

        /// <summary>
        /// Reqired by IXMLserializable
        /// </summary>
        /// <returns>Null</returns>
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>
        /// Deserializes object from XML
        /// </summary>
        /// <param name="reader">XML reader</param>
        public void ReadXml(System.Xml.XmlReader reader)
        {
            while (reader.Read())
            {
                if (reader.IsStartElement())
                {
                    if (reader.Name == "Position")
                    {
                        position.ReadXml(reader);
                    }
                }
                else return;
            }
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            position.WriteXml(writer, "Position");
        }

        public void WriteXml(System.Xml.XmlWriter writer, string rootname)
        {
            writer.WriteStartElement(rootname);
            WriteXml(writer);
            writer.WriteEndElement();
        }


        #endregion
    } //PositionVertex

    /// <summary>
    /// Vertex containg only the position and texture coordinates
    /// </summary>
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct SimpleTexturedVertex : IVertex
    {
        [VertexElement(VertexElementUsage.Position)]
        public Vector3 position;

        [VertexElement(VertexElementUsage.TexCoord)]
        public Vector2 texCoord;

        public SimpleTexturedVertex(Vector3 pos) : this(pos, new Vector2())
        {
        }

        public SimpleTexturedVertex(Vector3 pos, Vector2 tex)
        {
            position = pos;
            texCoord = tex;
        }


        #region IVertex Members

        public Vector3 Position
        {
            get
            {
                return position;
            }
            set
            {
                position = value;
            }
        }

        public Vector3 Normal
        {
            get
            {
                return Vector3.UnitZ;
            }
            set
            {
            }
        }

        public ColorByte Color
        {
            get
            {
                return ColorByte.White;
            }
            set
            {
            }
        }

        public Vector2 TexCoord2
        {
            get
            {
                return texCoord;
            }
            set
            {
                texCoord = value;
            }
        }

        /// <summary>
        /// Creates new vertex
        /// </summary>
        /// <returns>New vertex of the same format</returns>
        public IVertex CreateNew()
        {
            return new SimpleTexturedVertex();
        }

        /// <summary>
        /// Creates new vertex with specified position
        /// </summary>
        /// <param name="pos">Position</param>
        /// <returns>New vertex of the same format</returns>
        public IVertex CreateNew(Vector3 pos)
        {
            return new SimpleTexturedVertex(position);
        }

        /// <summary>
        /// Creates vertex array of this vertex type with specified number of elements
        /// </summary>
        /// <param name="count">Required number of elements</param>
        /// <returns>New vertexarray of this vertex type</returns>
        public IVertexArray CreateArray(int count)
        {
            return new VertexArray<SimpleTexturedVertex>(count);
        }


        #endregion

        #region IXmlSerializable Members

        /// <summary>
        /// Reqired by IXMLserializable
        /// </summary>
        /// <returns>Null</returns>
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>
        /// Deserializes object from XML
        /// </summary>
        /// <param name="reader">XML reader</param>
        public void ReadXml(System.Xml.XmlReader reader)
        {
            while (reader.Read())
            {
                if (reader.IsStartElement())
                {
                    if (reader.Name == "Position")
                    {
                        position.ReadXml(reader);
                    }
                    else if (reader.Name == "UV")
                    {
                        texCoord.ReadXml(reader);
                    }
                }
                else return;
            }
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            position.WriteXml(writer, "Position");
            texCoord.WriteXml(writer, "UV");
        }

        public void WriteXml(System.Xml.XmlWriter writer, string rootname)
        {
            writer.WriteStartElement(rootname);
            WriteXml(writer);
            writer.WriteEndElement();
        }


        #endregion

    }

    /// <summary>
    /// Vertex containing position and normal vector
    /// </summary>
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct NormalVertex : IVertex
    {
        [VertexElement(VertexElementUsage.Position)]
        public Vector3 position;

        [VertexElement(VertexElementUsage.Normal)]
        public Vector3 normal;


        public NormalVertex(Vector3 pos, Vector3 norm)
        {
            position = pos;
            normal = norm;
        }

        public NormalVertex(Vector3 pos)
        {
            position = pos;
            normal = Vector3.UnitZ;
        }


        #region IVertex Members

        public Vector3 Position
        {
            get
            {
                return position;
            }
            set
            {
                position = value;
            }
        }

        public Vector3 Normal
        {
            get
            {
                return normal;
            }
            set
            {
                normal = value;
            }
        }

        public ColorByte Color
        {
            get
            {
                return ColorByte.White;
            }
            set
            {
            }
        }

        public Vector2 TexCoord2
        {
            get
            {
                return new Vector2();
            }
            set
            {
            }
        }

        /// <summary>
        /// Creates new vertex
        /// </summary>
        /// <returns>New vertex of the same format</returns>
        public IVertex CreateNew()
        {
            return new NormalVertex();
        }

        /// <summary>
        /// Creates new vertex with specified position
        /// </summary>
        /// <param name="pos">Position</param>
        /// <returns>New vertex of the same format</returns>
        public IVertex CreateNew(Vector3 pos)
        {
            return new NormalVertex(position);
        }

        /// <summary>
        /// Creates vertex array of this vertex type with specified number of elements
        /// </summary>
        /// <param name="count">Required number of elements</param>
        /// <returns>New vertexarray of this vertex type</returns>
        public IVertexArray CreateArray(int count)
        {
            return new VertexArray<NormalVertex>(count);
        }

        #endregion

        #region IXmlSerializable Members

        /// <summary>
        /// Reqired by IXMLserializable
        /// </summary>
        /// <returns>Null</returns>
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>
        /// Deserializes object from XML
        /// </summary>
        /// <param name="reader">XML reader</param>
        public void ReadXml(System.Xml.XmlReader reader)
        {
            while (reader.Read())
            {
                if (reader.IsStartElement())
                {
                    if (reader.Name == "Position")
                    {
                        position.ReadXml(reader);
                    }
                    else if (reader.Name == "Normal")
                    {
                        normal.ReadXml(reader);
                    }
                }
                else return;
            }
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            position.WriteXml(writer, "Position");
            normal.WriteXml(writer, "Normal");
        }

        public void WriteXml(System.Xml.XmlWriter writer, string rootname)
        {
            writer.WriteStartElement(rootname);
            WriteXml(writer);
            writer.WriteEndElement();
        }


        #endregion


    } //NormalVertex
    

    /// <summary>
    /// Vertex containg position and color
    /// </summary>
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct ColoredVertex : IVertex
    {
        [VertexElement(VertexElementUsage.Position)]
        public Vector3 position;

        [VertexElement(VertexElementUsage.Color)]
        public ColorByte color;

        public ColoredVertex(Vector3 pos, ColorByte col)
        {
            position = pos;
            color = col;
        }

        public ColoredVertex(Vector3 pos) : this(pos, ColorByte.White)
        {            
        }

        #region IVertex Members

        public Vector3 Position
        {
            get
            {
                return position;
            }
            set
            {
                position = value;
            }
        }

        public Vector3 Normal
        {
            get
            {
                return Vector3.UnitX;
            }
            set
            {
            }
        }

        public ColorByte Color
        {
            get
            {
                return color;
            }
            set
            {
                color = Color;
            }
        }

        public Vector2 TexCoord2
        {
            get
            {
                return new Vector2();
            }
            set
            {
            }
        }

        /// <summary>
        /// Creates new vertex
        /// </summary>
        /// <returns>New vertex of the same format</returns>
        public IVertex CreateNew()
        {
            return new ColoredVertex();
        }

        /// <summary>
        /// Creates new vertex with specified position
        /// </summary>
        /// <param name="pos">Position</param>
        /// <returns>New vertex of the same format</returns>
        public IVertex CreateNew(Vector3 pos)
        {
            return new ColoredVertex(position);
        }

        /// <summary>
        /// Creates vertex array of this vertex type with specified number of elements
        /// </summary>
        /// <param name="count">Required number of elements</param>
        /// <returns>New vertexarray of this vertex type</returns>
        public IVertexArray CreateArray(int count)
        {
            return new VertexArray<ColoredVertex>(count);
        }

        #endregion

        #region IXmlSerializable Members

        /// <summary>
        /// Reqired by IXMLserializable
        /// </summary>
        /// <returns>Null</returns>
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>
        /// Deserializes object from XML
        /// </summary>
        /// <param name="reader">XML reader</param>
        public void ReadXml(System.Xml.XmlReader reader)
        {
            while (reader.Read())
            {
                if (reader.IsStartElement())
                {
                    if (reader.Name == "Position")
                    {
                        position.ReadXml(reader);
                    }
                    else if (reader.Name == "Color")
                    {
                        color.ReadXml(reader);
                    }
                }
                else return;
            }
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            position.WriteXml(writer, "Position");
            color.WriteXml(writer, "Color"); 
        }

        public void WriteXml(System.Xml.XmlWriter writer, string rootname)
        {
            writer.WriteStartElement(rootname);
            WriteXml(writer);
            writer.WriteEndElement();
        }


        #endregion

    } //ColoredVertex

    /// <summary>
    /// Vertex containg position, normal and color
    /// </summary>
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct ColoredNormalVertex : IVertex
    {
        [VertexElement(VertexElementUsage.Position)]
        public Vector3 position;

        [VertexElement(VertexElementUsage.Normal)]
        public Vector3 normal;

        [VertexElement(VertexElementUsage.Color)]
        public ColorByte color;


        public ColoredNormalVertex(Vector3 pos)
        {
            position = pos;
            normal = Vector3.UnitZ;
            color = ColorByte.White;        
        }

        public ColoredNormalVertex(Vector3 pos, Vector3 norm, ColorByte col)
        {
            position = pos;
            normal = norm;
            color = col;
        }

        #region IVertex Members

        public Vector3 Position
        {
            get
            {
                return position;
            }
            set
            {
                position = value;
            }
        }

        public Vector3 Normal
        {
            get
            {
                return normal;
            }
            set
            {
                normal = value;
            }
        }

        public ColorByte Color
        {
            get
            {
                return color;
            }
            set
            {
                color = value;
            }
        }

        public Vector2 TexCoord2
        {
            get
            {
                return new Vector2();
            }
            set
            {
            }
        }

        /// <summary>
        /// Creates new vertex
        /// </summary>
        /// <returns>New vertex of the same format</returns>
        public IVertex CreateNew()
        {
            return new ColoredNormalVertex();
        }

        /// <summary>
        /// Creates new vertex with specified position
        /// </summary>
        /// <param name="pos">Position</param>
        /// <returns>New vertex of the same format</returns>
        public IVertex CreateNew(Vector3 pos)
        {
            return new ColoredNormalVertex(position);
        }

        /// <summary>
        /// Creates vertex array of this vertex type with specified number of elements
        /// </summary>
        /// <param name="count">Required number of elements</param>
        /// <returns>New vertexarray of this vertex type</returns>
        public IVertexArray CreateArray(int count)
        {
            return new VertexArray<ColoredNormalVertex>(count);
        }
        
        #endregion

        #region IXmlSerializable Members

        /// <summary>
        /// Reqired by IXMLserializable
        /// </summary>
        /// <returns>Null</returns>
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>
        /// Deserializes object from XML
        /// </summary>
        /// <param name="reader">XML reader</param>
        public void ReadXml(System.Xml.XmlReader reader)
        {
            while (reader.Read())
            {
                if (reader.IsStartElement())
                {
                    if (reader.Name == "Position")
                    {
                        position.ReadXml(reader);
                    }
                    else if (reader.Name == "Normal")
                    {
                        normal.ReadXml(reader);
                    }
                    else if (reader.Name == "Color")
                    {
                        color.ReadXml(reader);
                    }
                }
                else return;
            }
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            position.WriteXml(writer, "Position");
            normal.WriteXml(writer, "Normal");
            color.WriteXml(writer, "Color");
        }

        public void WriteXml(System.Xml.XmlWriter writer, string rootname)
        {
            writer.WriteStartElement(rootname);
            WriteXml(writer);
            writer.WriteEndElement();
        }


        #endregion


    } //ColoredNormalVertex
    
    /// <summary>
    /// Vertex containg position, normal and texture 2d coordinates
    /// </summary>
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct TexturedVertex : IVertex
    {
        [VertexElement(VertexElementUsage.Position)]
        public Vector3 position;

        [VertexElement(VertexElementUsage.Normal)]
        public Vector3 normal;

        [VertexElement(VertexElementUsage.TexCoord)]
        public Vector2 texCoord;

        public TexturedVertex(Vector3 pos) : this(pos, Vector3.UnitZ, new Vector2())
        {
        }

        public TexturedVertex(Vector3 pos, Vector3 norm, Vector2 tex)
        {
            position = pos;
            normal = norm;
            texCoord = tex;
        }

        public TexturedVertex(ref Vector3 pos, ref Vector3 norm, ref Vector2 texc)
        {
            position = pos;
            normal = norm;
            texCoord = texc;
        }

        #region IVertex Members

        public Vector3 Position
        {
            get
            {
                return position;
            }
            set
            {
                position = value;
            }
        }

        public Vector3 Normal
        {
            get
            {
                return normal;
            }
            set
            {
                normal = value;
            }
        }

        public ColorByte Color
        {
            get
            {
                return ColorByte.White;
            }
            set
            {
            }
        }

        public Vector2 TexCoord2
        {
            get
            {
                return texCoord;
            }
            set
            {
                texCoord = value;
            }
        }

        /// <summary>
        /// Creates new vertex
        /// </summary>
        /// <returns>New vertex of the same format</returns>
        public IVertex CreateNew()
        {
            return new TexturedVertex();
        }

        /// <summary>
        /// Creates new vertex with specified position
        /// </summary>
        /// <param name="pos">Position</param>
        /// <returns>New vertex of the same format</returns>
        public IVertex CreateNew(Vector3 pos)
        {
            return new TexturedVertex(position);
        }

        /// <summary>
        /// Creates vertex array of this vertex type with specified number of elements
        /// </summary>
        /// <param name="count">Required number of elements</param>
        /// <returns>New vertexarray of this vertex type</returns>
        public IVertexArray CreateArray(int count)
        {
            return new VertexArray<TexturedVertex>(count);
        }


        #endregion

        #region IXmlSerializable Members

        /// <summary>
        /// Reqired by IXMLserializable
        /// </summary>
        /// <returns>Null</returns>
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>
        /// Deserializes object from XML
        /// </summary>
        /// <param name="reader">XML reader</param>
        public void ReadXml(System.Xml.XmlReader reader)
        {
            while (reader.Read())
            {
                if (reader.IsStartElement())
                {
                    if (reader.Name == "Position")
                    {
                        position.ReadXml(reader);
                    }
                    else if (reader.Name == "Normal")
                    {
                        normal.ReadXml(reader);
                    }
                    else if (reader.Name == "UV")
                    {
                        texCoord.ReadXml(reader);
                    }
                }
                else return;
            }
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            position.WriteXml(writer, "Position");
            normal.WriteXml(writer, "Normal");
            texCoord.WriteXml(writer, "UV");
        }

        public void WriteXml(System.Xml.XmlWriter writer, string rootname)
        {
            writer.WriteStartElement(rootname);
            WriteXml(writer);
            writer.WriteEndElement();
        }


        #endregion


    } //TexturedVertex

    /// <summary>
    /// "Universal" vertex format - Position, normal, color and 2d texture coordinates
    /// </summary>
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct Vertex : IVertex
    {
        [VertexElement(VertexElementUsage.Position)]
        public Vector3 position;

        [VertexElement(VertexElementUsage.Normal)]
        public Vector3 normal;

        [VertexElement(VertexElementUsage.Color)]
        public ColorByte color;

        [VertexElement(VertexElementUsage.TexCoord)]
        public Vector2 texCoord;


        public Vertex(Vector3 pos)
        {
            position = pos;
            normal = Vector3.UnitZ;
            color = ColorByte.White;
            texCoord = new Vector2();
        }

        public Vertex(Vector3 pos, Vector3 norm, ColorByte col, Vector2 tex)
        {
            position = pos;
            normal = norm;
            color = col;
            texCoord = tex;
        }

        #region IVertex Members

        public Vector3 Position
        {
            get
            {
                return position;
            }
            set
            {
                position = value;
            }
        }

        public Vector3 Normal
        {
            get
            {
                return normal;
            }
            set
            {
                normal = value;
            }
        }

        public ColorByte Color
        {
            get
            {
                return color;
            }
            set
            {
                color = value;
            }
        }

        public Vector2 TexCoord2
        {
            get
            {
                return texCoord;
            }
            set
            {
                texCoord = value;
            }
        }

        #endregion

        #region IVertex Members


        /// <summary>
        /// Creates new vertex
        /// </summary>
        /// <returns>New vertex of the same format</returns>
        public IVertex CreateNew()
        {
            return new Vertex();
        }

        /// <summary>
        /// Creates new vertex with specified position
        /// </summary>
        /// <param name="pos">Position</param>
        /// <returns>New vertex of the same format</returns>
        public IVertex CreateNew(Vector3 pos)
        {
            return new Vertex(position);
        }

        /// <summary>
        /// Creates vertex array of this vertex type with specified number of elements
        /// </summary>
        /// <param name="count">Required number of elements</param>
        /// <returns>New vertexarray of this vertex type</returns>
        public IVertexArray CreateArray(int count)
        {
            return new VertexArray<Vertex>(count);
        }

        #endregion

        #region IXmlSerializable Members

        /// <summary>
        /// Reqired by IXMLserializable
        /// </summary>
        /// <returns>Null</returns>
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>
        /// Deserializes object from XML
        /// </summary>
        /// <param name="reader">XML reader</param>
        public void ReadXml(System.Xml.XmlReader reader)
        {
            while (reader.Read())
            {
                if (reader.IsStartElement())
                {
                    if (reader.Name == "Position")
                    {
                        position.ReadXml(reader);
                    }
                    else if (reader.Name == "Normal")
                    {
                        normal.ReadXml(reader);
                    }
                    else if (reader.Name == "UV")
                    {
                        texCoord.ReadXml(reader);
                    }
                    else if (reader.Name == "Color")
                    {
                        color.ReadXml(reader);
                    }
                }
                else return;
            }
        }

        /// <summary>
        /// Serializes object to XML
        /// </summary>
        /// <param name="writer">XML writer to save values</param>
        public void WriteXml(System.Xml.XmlWriter writer)
        {
            position.WriteXml(writer, "Position");
            normal.WriteXml(writer, "Normal");
            texCoord.WriteXml(writer, "UV");
            color.WriteXml(writer, "Color");
        }

        /// <summary>
        /// Serializes object to XML
        /// </summary>
        /// <param name="writer">XML writer to save values</param>
        /// <param name="rootname">Node to save value to</param>
        public void WriteXml(System.Xml.XmlWriter writer, string rootname)
        {
            writer.WriteStartElement(rootname);
            WriteXml(writer);
            writer.WriteEndElement();
        }


        #endregion

    }

    #endregion

}
