using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using MikuMikuDance.Model.Ver1;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework;
using System.IO;

namespace MikuMikuDance.XNA.ModelReach
{
    static class MMDMeshBuilderReach
    {
        public static MeshContent BuildMesh(MMDModel1 model, string filename, ContentIdentity Identity)
        {
            MeshBuilder meshBuilder = MeshBuilder.StartMesh(model.Header.ModelName);
            //頂点や面をチェック
            if (model.Vertexes == null || model.Vertexes.Length == 0)
                return null;
            if (model.FaceVertexes == null || model.FaceVertexes.Length == 0)
                return null;
            meshBuilder.MergeDuplicatePositions = true;

            //ここからメッシュ情報を登録していく

            //頂点を登録
            int[] Positions = new int[model.Vertexes.LongLength];// + border.Vertexes.LongLength];
            for (long i = 0; i < model.Vertexes.LongLength; i++)
            {
                //頂点登録(座標系変換込み)
                Positions[i] = meshBuilder.CreatePosition(MMDMath.VectorFromArray(model.Vertexes[i].Pos));
            }

            //テクスチャー座標および法線用の頂点チャンネルを追加
            int texCoordinateIndex = meshBuilder.CreateVertexChannel<Vector2>(VertexChannelNames.TextureCoordinate(0));
            int normalDataIndex = meshBuilder.CreateVertexChannel<Vector3>(VertexChannelNames.Normal(0));
            int weightDataIndex = meshBuilder.CreateVertexChannel<BoneWeightCollection>(VertexChannelNames.Weights(0));

            long FaceIndex = 0;

            //マテリアル
            for (long i = 0; i < model.Materials.LongLength; i++)
            {
                EffectMaterialContent material = new EffectMaterialContent();
                //BasicMaterialContent material = new BasicMaterialContent();
                //名前設定
                material.Name = "material" + i.ToString();

                bool HasTexture = false;
                //テクスチャ読み込み
                if (!string.IsNullOrEmpty(model.Materials[i].TextureFileName))
                {
                    string path = model.Materials[i].TextureFileName;
                    if (!Path.IsPathRooted(path))
                    {
                        path = Path.Combine(Path.GetDirectoryName(filename), path);
                    }
                    if (!File.Exists(path))
                        throw new InvalidContentException(
                            "Cannot find texture file:" + path, Identity);
                    //テクスチャのセット
                    material.Textures.Add("Texture", new ExternalReference<TextureContent>(path));
                    HasTexture = true;
                }
                //カラー設定
                material.OpaqueData.Add("DiffuseColor", MMDMath.VectorFromArray(model.Materials[i].DiffuseColor));
                material.OpaqueData.Add("EmissiveColor", MMDMath.VectorFromArray(model.Materials[i].MirrorColor));
                material.OpaqueData.Add("SpecularColor", MMDMath.VectorFromArray(model.Materials[i].SpecularColor));
                material.OpaqueData.Add("Alpha", model.Materials[i].Alpha);
                material.OpaqueData.Add("SpecularPower", model.Materials[i].Specularity);
                //シェーダ番号設定はプロセッサ側で判定
                /*if (HasTexture)
                    material.OpaqueData.Add("ShaderIndex", 7);
                else
                    material.OpaqueData.Add("ShaderIndex", 5);*/
                //頂点設定
                for (long k = FaceIndex; k < FaceIndex + model.Materials[i].FaceVertCount; k++)
                {
                    //マテリアルをセット
                    meshBuilder.SetMaterial(material);
                    //頂点index取得
                    int VecIndex = model.FaceVertexes[k];
                    //UV座標を0番にセット
                    if (HasTexture)
                        meshBuilder.SetVertexChannelData(texCoordinateIndex, new Vector2(model.Vertexes[VecIndex].UV[0], model.Vertexes[VecIndex].UV[1]));
                    else
                        meshBuilder.SetVertexChannelData(texCoordinateIndex, Vector2.Zero);
                    //法線セット
                    meshBuilder.SetVertexChannelData(normalDataIndex,
                        MMDMath.VectorFromArray(model.Vertexes[VecIndex].NormalVector));
                    //ボーンウェイト
                    BoneWeightCollection boneWeight = new BoneWeightCollection();
                    int boneNum = model.Vertexes[VecIndex].BoneNum[0];
                    if (boneNum >= 0 && boneNum < model.Bones.Length)
                        boneWeight.Add(new BoneWeight(model.Bones[boneNum].BoneName, model.Vertexes[VecIndex].BoneWeight / 100f));
                    boneNum = model.Vertexes[VecIndex].BoneNum[1];
                    if (boneNum >= 0 && boneNum < model.Bones.Length)
                        boneWeight.Add(new BoneWeight(model.Bones[boneNum].BoneName, 1.0f - model.Vertexes[VecIndex].BoneWeight / 100f));

                    meshBuilder.SetVertexChannelData(weightDataIndex, boneWeight);

                    
                    //面を生成
                    meshBuilder.AddTriangleVertex(Positions[VecIndex]);
                }
                FaceIndex += model.Materials[i].FaceVertCount;
            }

            //メッシュを作成
            MeshContent meshContent = meshBuilder.FinishMesh();
            //メッシュの設定
            meshContent.Identity = Identity;
            meshContent.Name = model.Header.ModelName;

            return meshContent;
        }
    }
}
