using System.Reflection;
using Direct3D = Microsoft.DirectX.Direct3D;

using System.Runtime.InteropServices;
using MTV3D65;

namespace OctreeRendering
{
    static class VertexHelper
    {
        const string VertexElementsFieldName = "VertexElements";

        public static Direct3D.VertexElement[] GetElements<T>()
        {
            return (Direct3D.VertexElement[]) typeof(T).GetField(VertexElementsFieldName, BindingFlags.Static | BindingFlags.Public).GetValue(null);
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    struct PositionInstance : IVertex, IInstancedVertex
    {
        public static readonly Direct3D.VertexElement[] VertexElements;
        static PositionInstance()
        {
            VertexElements = new[] 
            {
                new Direct3D.VertexElement(0, 0, Direct3D.DeclarationType.Float3, Direct3D.DeclarationMethod.Default, Direct3D.DeclarationUsage.Position, 0),
                new Direct3D.VertexElement(0, 12, Direct3D.DeclarationType.Float1, Direct3D.DeclarationMethod.Default, Direct3D.DeclarationUsage.TextureCoordinate, 3),
                Direct3D.VertexElement.VertexDeclarationEnd
            };
        }

        public Vector3f Position { get; set; }
        public float InstanceIndex { get; set; }

        public PositionInstance(Vector3f position) : this()
        {
            Position = position;
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    struct PositionNormalTextureColorInstance : IVertex, ILitVertex, IInstancedVertex, ITexturedVertex, IColoredVertex
    {
        public static readonly Direct3D.VertexElement[] VertexElements;
        static PositionNormalTextureColorInstance()
        {
            VertexElements = new[] 
            {
                new Direct3D.VertexElement(0, 0, Direct3D.DeclarationType.Float3, Direct3D.DeclarationMethod.Default, Direct3D.DeclarationUsage.Position, 0),
                new Direct3D.VertexElement(0, 12, Direct3D.DeclarationType.Float3, Direct3D.DeclarationMethod.Default, Direct3D.DeclarationUsage.Normal, 0),
                new Direct3D.VertexElement(0, 24, Direct3D.DeclarationType.Float2, Direct3D.DeclarationMethod.Default, Direct3D.DeclarationUsage.TextureCoordinate, 0),
                new Direct3D.VertexElement(0, 32, Direct3D.DeclarationType.Color, Direct3D.DeclarationMethod.Default, Direct3D.DeclarationUsage.Color, 0),
                new Direct3D.VertexElement(0, 36, Direct3D.DeclarationType.Float1, Direct3D.DeclarationMethod.Default, Direct3D.DeclarationUsage.TextureCoordinate, 3),
                Direct3D.VertexElement.VertexDeclarationEnd
            };
        }

        public Vector3f Position { get; set; }
        public Vector3f Normal { get; set; }
        public Vector2f TextureCoordinate { get; set; }
        public int Color { get; set; }
        public float InstanceIndex { get; set; }

        public PositionNormalTextureColorInstance(Vector3f position, Vector3f normal, Vector2f textureCoordinate, TV_COLOR color) : this()
        {
            Position = position;
            Normal = normal;
            TextureCoordinate = textureCoordinate;
            Color = color.GetIntColor();
        }
    }

    interface IVertex
    {
        Vector3f Position { get; set; }
    }
    interface ILitVertex
    {
        Vector3f Normal { get; set; }
    }
    interface IInstancedVertex
    {
        float InstanceIndex { get; set; }
    }
    interface ITexturedVertex
    {
        Vector2f TextureCoordinate { get; set; }
    }
    interface IColoredVertex
    {
        int Color { get; set; }
    }
}
