using System.ComponentModel;
using System.IO;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;


namespace MikuMikuDance.XNA.Model
{
    /// <summary>
    /// /// コンテント・パイプライン内の中間データであるNodeContentから
    /// アニメーションデータを含んだModelContentへ変換するプロセッサ(Reach用)
    /// </summary>
    [ContentProcessor]
    internal class SkinnedModelProcessorReach : ModelProcessor
    {
        
        /// <summary>
        /// コンテント・パイプライン内の中間データであるNodeContentから
        /// アニメーションデータを含んだModelContentへ変換するProcessメソッド。
        /// メイン処理はMMDProcessorに任せて、ここではエフェクト周りのプロセスを行う
        /// </summary>
        public override ModelContent Process(NodeContent input, ContentProcessorContext context)
        {
            // ベースクラスのProcessメソッドを呼び出してモデルデータを変換する
            return base.Process(input, context);
        }

        /// <summary>
        /// 全てのマテリアルがスキンモデル用のエフェクトを使うように変更する
        /// </summary>
        protected override MaterialContent ConvertMaterial(MaterialContent material,
                                                        ContentProcessorContext context)
        {
            BasicMaterialContent basicMaterial = material as BasicMaterialContent;
            EffectMaterialContent effectMaterial;
            // スキンメッシュエフェクトを参照する
            
            ExternalReference<EffectContent> effect;
            //リソースからファイルを作成して読み込むという超セコイ方法……
            if (!Directory.Exists("ext"))
                Directory.CreateDirectory("ext");
            FileStream fs = new FileStream(Path.Combine("ext", "MMDModelReach.fx"), FileMode.Create);
            BinaryWriter bw = new BinaryWriter(fs);
            bw.Write(Resource1.MMDModelReach);
            bw.Close();
            effect = new ExternalReference<EffectContent>(Path.Combine("ext", "MMDModelReach.fx"));
            
            if (basicMaterial == null)
            {
                effectMaterial = material as EffectMaterialContent;
                if (effectMaterial == null)
                    throw new InvalidContentException(string.Format(
                    "MMDProcessorはEffectMaterialContentのみをサポートします" +
                    "入力メッシュは{0}を使用しています。", material.GetType()));
                // スキンメッシュエフェクトを埋め込む
                effectMaterial.Effect = effect;
                //　ModelProcessorのConvertMaterialを呼ぶ
                return base.ConvertMaterial(effectMaterial, context);
            }
            else
            {
                
                effectMaterial = new EffectMaterialContent();

                // スキンメッシュエフェクトを埋め込む
                effectMaterial.Effect = effect;
                //データのコピー
                foreach (var i in basicMaterial.OpaqueData)
                {
                    effectMaterial.OpaqueData.Add(i.Key, i.Value);
                }
                
                effectMaterial.Name = basicMaterial.Name;
                effectMaterial.Identity = basicMaterial.Identity;
                // BasicMaterialContentのテクスチャを新しいマテリアルに設定する
                foreach (var i in basicMaterial.Textures)
                {
                    effectMaterial.Textures.Add(i.Key, i.Value);
                }
                //　ModelProcessorのConvertMaterialを呼ぶ
                return base.ConvertMaterial(effectMaterial, context);
            }
        }
        protected override void ProcessGeometryUsingMaterial(MaterialContent material, System.Collections.Generic.IEnumerable<GeometryContent> geometryCollection, ContentProcessorContext context)
        {
            //どのエフェクトを使うのかの種別判定
            foreach (var i in geometryCollection)
            {
                bool Color = false;
                bool UseTexture = false;
                bool Normal = false;
                foreach (var channel in i.Vertices.Channels)
                {
                    if (channel.Name == VertexChannelNames.TextureCoordinate(0)
                        && i.Material.Textures.Count > 0)
                    {
                        UseTexture = true;
                    }
                    else if (channel.Name == VertexChannelNames.Color(0))
                        Color = true;
                    else if (channel.Name == VertexChannelNames.Normal(0))
                    {
                        Normal = true;
                        
                    }
                }
                //シェーダ番号の判別
                int ShaderIndex = 0;
                if (Color)
                    ShaderIndex += 1;
                if (UseTexture)
                    ShaderIndex += 2;
                if (Normal)
                    ShaderIndex += 4;
                i.Material.OpaqueData.Add("ShaderIndex", ShaderIndex);
            }
            base.ProcessGeometryUsingMaterial(material, geometryCollection, context);
        }
    }
}