using System;
using System.Collections.Generic;
using System.Xml;

namespace Mix.Tool.ModelEditor.Project
{
    /// <summary>
    /// テンプレートクラス
    /// </summary>
    public class Template
    {
        private string filePath = "";
        private string desc = "";
        private Mix.Tool.Graphics.ShaderModels mepShaderModels;
        private Mix.Tool.Graphics.ShaderProcessFlags mepProcFlags;
        private string mepName = "";
        private string mepDirPath = "";
        private List<string> mepSearchDirList = new List<string>();

        /// <summary>
        /// ファイルパスの取得、または設定
        /// </summary>
        public string FilePath
        {
            get { return this.filePath; }
            set { this.filePath = value; }
        }

        /// <summary>
        /// 説明の取得、または設定
        /// </summary>
        public string Desc
        {
            get { return this.desc; }
            set { this.desc = value; }
        }

        /// <summary>
        /// シェーダーモデルの取得、または設定
        /// </summary>
        public Mix.Tool.Graphics.ShaderModels ShaderModels
        {
            get { return this.mepShaderModels; }
            set { this.mepShaderModels = value; }
        }

        /// <summary>
        /// シェーダーエフェクトの設定、または取得
        /// </summary>
        public Mix.Tool.Graphics.ShaderProcessFlags ShaderProcFlags
        {
            get { return this.mepProcFlags; }
            set { this.mepProcFlags = value; }
        }

        /// <summary>
        /// シェーダーパッケージ名の取得、または設定
        /// </summary>
        public string EffectPackageName
        {
            get { return this.mepName; }
            set { this.mepName = value; }
        }

        /// <summary>
        /// シェーダーパッケージのディレクトリパスの取得、または設定
        /// </summary>
        public string EffectPackageDirectoryPath
        {
            get { return this.mepDirPath; }
            set { this.mepDirPath = value; }
        }

        /// <summary>
        /// クリーンアップ時のエフェクト検索ディレクトリコレクション
        /// </summary>
        public List<string> EffectSearchDirCollection
        {
            get { return this.mepSearchDirList; }
        }

        /// <summary>
        /// プロジェクトテンプレートが有効かどうかの取得
        /// </summary>
        public bool Available
        {
            get
            {
                if (this.filePath.Length == 0)
                {
                    return false;
                }

                if (this.desc.Length == 0)
                {
                    return false;
                }

                if (this.mepShaderModels == Mix.Tool.Graphics.ShaderModels.Init)
                {
                    return false;
                }

                if (this.mepName.Length == 0)
                {
                    return false;
                }

                if (this.mepDirPath.Length == 0)
                {
                    return false;
                }

                return true;
            }
        }

        /// <summary>
        /// プロジェクトテンプレートを読み込みます
        /// </summary>
        public void Load()
        {
            string tempDesc = "";
            Mix.Tool.Graphics.ShaderModels tempShaderModels = Mix.Tool.Graphics.ShaderModels.Init;
            Mix.Tool.Graphics.ShaderProcessFlags tempProcFlags = Mix.Tool.Graphics.ShaderProcessFlags.Init;
            string tempMepName = "";
            string tempMepDirPath = "";
            List<string> tempMepSearchDirList = new List<string>();

            try
            {
                XmlDocument doc = new XmlDocument();
                XmlElement rootElm = null;
                XmlAttribute attr = null;

                doc.Load(filePath);

                if (doc.ChildNodes.Count != 1)
                {
                    throw new System.Exception();
                }

                rootElm = doc.FirstChild as XmlElement;
                if (rootElm == null)
                {
                    throw new System.Exception();
                }

                if (rootElm.Name.Equals(Properties.Resources.XML_PT_ROOT) == false)
                {
                    throw new System.Exception();
                }

                attr = rootElm.Attributes[Properties.Resources.XML_PT_VERSION];
                if ((attr.Name.Equals(Properties.Resources.XML_PT_VERSION) == false) ||
                    (attr.Value.Equals(Properties.Resources.XML_PT_VERSION_VALUE) == false))
                {
                    throw new System.Exception();
                }

                foreach (XmlElement elm in rootElm.ChildNodes)
                {
                    if (elm.Name.Equals(Properties.Resources.XML_PT_DESC_STR) == true)
                    {
                        tempDesc = elm.Attributes[Properties.Resources.XML_PT_VALUE].Value;
                    }
                    else if (elm.Name.Equals(Properties.Resources.XML_PT_MEP) == true)
                    {
                        foreach (XmlElement elmMep in elm.ChildNodes)
                        {
                            if (elmMep.Name.Equals(Properties.Resources.XML_PT_NAME) == true)
                            {
                                tempMepName = elmMep.Attributes[Properties.Resources.XML_PT_VALUE].Value;
                            }
                            else if (elmMep.Name.Equals(Properties.Resources.XML_PT_DIRPATH) == true)
                            {
                                tempMepDirPath = elmMep.Attributes[Properties.Resources.XML_PT_VALUE].Value;
                            }
                            else if (elmMep.Name.Equals(Properties.Resources.XML_PT_SHADERMODEL3) == true)
                            {
                                if (bool.Parse(elmMep.Attributes[Properties.Resources.XML_PT_VALUE].Value) == true)
                                {
                                    tempShaderModels |= Mix.Tool.Graphics.ShaderModels.DirectX9_3_0;
                                }
                            }
                            else if (elmMep.Name.Equals(Properties.Resources.XML_PT_SHADERMODEL4) == true)
                            {
                                if (bool.Parse(elmMep.Attributes[Properties.Resources.XML_PT_VALUE].Value) == true)
                                {
                                    tempShaderModels |= Mix.Tool.Graphics.ShaderModels.DirectX10_4_0;
                                }
                            }
                            else if (elmMep.Name.Equals(Properties.Resources.XML_PT_SHADERMODEL5) == true)
                            {
                                if (bool.Parse(elmMep.Attributes[Properties.Resources.XML_PT_VALUE].Value) == true)
                                {
                                    tempShaderModels |= Mix.Tool.Graphics.ShaderModels.DirectX11_5_0;
                                }
                            }
                            else if (elmMep.Name.Equals(Properties.Resources.XML_PT_PROCESS_FOG) == true)
                            {
                                if (bool.Parse(elmMep.Attributes[Properties.Resources.XML_PT_VALUE].Value) == true)
                                {
                                    tempProcFlags |= Mix.Tool.Graphics.ShaderProcessFlags.Fog;
                                }
                            }
                            else if (elmMep.Name.Equals(Properties.Resources.XML_PT_PROCESS_SHADOW) == true)
                            {
                                if (bool.Parse(elmMep.Attributes[Properties.Resources.XML_PT_VALUE].Value) == true)
                                {
                                    tempProcFlags |= Mix.Tool.Graphics.ShaderProcessFlags.Shadow;
                                }
                            }
                            else if (elmMep.Name.Equals(Properties.Resources.XML_PT_PROCESS_REFRACT) == true)
                            {
                                if (bool.Parse(elmMep.Attributes[Properties.Resources.XML_PT_VALUE].Value) == true)
                                {
                                    tempProcFlags |= Mix.Tool.Graphics.ShaderProcessFlags.Refract;
                                }
                            }
                            else if (elmMep.Name.Equals(Properties.Resources.XML_PT_PROCESS_SCATTERING) == true)
                            {
                                if (bool.Parse(elmMep.Attributes[Properties.Resources.XML_PT_VALUE].Value) == true)
                                {
                                    tempProcFlags |= Mix.Tool.Graphics.ShaderProcessFlags.Atmosphere;
                                }
                            }
                            else if (elmMep.Name.Equals(Properties.Resources.XML_PT_PROCESS_SSAO) == true)
                            {
                                if (bool.Parse(elmMep.Attributes[Properties.Resources.XML_PT_VALUE].Value) == true)
                                {
                                    tempProcFlags |= Mix.Tool.Graphics.ShaderProcessFlags.SSAO;
                                }
                            }
                            else if (elmMep.Name.Equals(Properties.Resources.XML_PT_CLEANUP_NAME) == true)
                            {
                                foreach (XmlElement elmCU in elmMep.ChildNodes)
                                {
                                    if (elmCU.Name.Equals(Properties.Resources.XML_PT_DIRPATH) == true)
                                    {
                                        tempMepSearchDirList.Add(elmCU.Attributes[Properties.Resources.XML_PT_VALUE].Value);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch
            {
                throw;
            }

            this.desc = tempDesc;
            this.mepShaderModels = tempShaderModels;
            this.mepProcFlags = tempProcFlags;
            this.mepName = tempMepName;
            this.mepDirPath = tempMepDirPath;
            this.mepSearchDirList = tempMepSearchDirList;
        }

        /// <summary>
        /// プロジェクトテンプレートを保存します
        /// </summary>
        public void Save()
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                XmlElement rootElm = null;
                XmlElement mepElm = null;
                XmlElement mepCleanupElm = null;
                XmlElement elm = null;
                XmlAttribute attr = null;

                ////////////////////////////////////////////////////////////////////////////////////////////////////

                rootElm = doc.CreateElement(Properties.Resources.XML_PT_ROOT);
                attr = doc.CreateAttribute(Properties.Resources.XML_PT_VERSION);
                attr.Value = Properties.Resources.XML_PT_VERSION_VALUE;
                rootElm.Attributes.Append(attr);
                doc.AppendChild(rootElm);

                elm = doc.CreateElement(Properties.Resources.XML_PT_DESC_STR);
                attr = doc.CreateAttribute(Properties.Resources.XML_PT_VALUE);
                attr.Value = this.desc;
                elm.Attributes.Append(attr);
                rootElm.AppendChild(elm);

                ////////////////////////////////////////////////////////////////////////////////////////////////////

                mepElm = doc.CreateElement(Properties.Resources.XML_PT_MEP);
                rootElm.AppendChild(mepElm);

                elm = doc.CreateElement(Properties.Resources.XML_PT_NAME);
                attr = doc.CreateAttribute(Properties.Resources.XML_PT_VALUE);
                attr.Value = this.mepName;
                elm.Attributes.Append(attr);
                mepElm.AppendChild(elm);

                elm = doc.CreateElement(Properties.Resources.XML_PT_DIRPATH);
                attr = doc.CreateAttribute(Properties.Resources.XML_PT_VALUE);
                attr.Value = this.mepDirPath;
                elm.Attributes.Append(attr);
                mepElm.AppendChild(elm);

                elm = doc.CreateElement(Properties.Resources.XML_PT_SHADERMODEL3);
                attr = doc.CreateAttribute(Properties.Resources.XML_PT_VALUE);
                attr.Value = ((this.mepShaderModels & Mix.Tool.Graphics.ShaderModels.DirectX9_3_0) == Mix.Tool.Graphics.ShaderModels.DirectX9_3_0).ToString();
                elm.Attributes.Append(attr);
                mepElm.AppendChild(elm);

                elm = doc.CreateElement(Properties.Resources.XML_PT_SHADERMODEL4);
                attr = doc.CreateAttribute(Properties.Resources.XML_PT_VALUE);
                attr.Value = ((this.mepShaderModels & Mix.Tool.Graphics.ShaderModels.DirectX10_4_0) == Mix.Tool.Graphics.ShaderModels.DirectX10_4_0).ToString();
                elm.Attributes.Append(attr);
                mepElm.AppendChild(elm);

                elm = doc.CreateElement(Properties.Resources.XML_PT_SHADERMODEL5);
                attr = doc.CreateAttribute(Properties.Resources.XML_PT_VALUE);
                attr.Value = ((this.mepShaderModels & Mix.Tool.Graphics.ShaderModels.DirectX11_5_0) == Mix.Tool.Graphics.ShaderModels.DirectX11_5_0).ToString();
                elm.Attributes.Append(attr);
                mepElm.AppendChild(elm);

                elm = doc.CreateElement(Properties.Resources.XML_PT_PROCESS_FOG);
                attr = doc.CreateAttribute(Properties.Resources.XML_PT_VALUE);
                attr.Value = ((this.mepProcFlags & Mix.Tool.Graphics.ShaderProcessFlags.Fog) == Mix.Tool.Graphics.ShaderProcessFlags.Fog).ToString();
                elm.Attributes.Append(attr);
                mepElm.AppendChild(elm);

                elm = doc.CreateElement(Properties.Resources.XML_PT_PROCESS_SHADOW);
                attr = doc.CreateAttribute(Properties.Resources.XML_PT_VALUE);
                attr.Value = ((this.mepProcFlags & Mix.Tool.Graphics.ShaderProcessFlags.Shadow) == Mix.Tool.Graphics.ShaderProcessFlags.Shadow).ToString();
                elm.Attributes.Append(attr);
                mepElm.AppendChild(elm);

                elm = doc.CreateElement(Properties.Resources.XML_PT_PROCESS_REFRACT);
                attr = doc.CreateAttribute(Properties.Resources.XML_PT_VALUE);
                attr.Value = ((this.mepProcFlags & Mix.Tool.Graphics.ShaderProcessFlags.Refract) == Mix.Tool.Graphics.ShaderProcessFlags.Refract).ToString();
                elm.Attributes.Append(attr);
                mepElm.AppendChild(elm);

                elm = doc.CreateElement(Properties.Resources.XML_PT_PROCESS_SCATTERING);
                attr = doc.CreateAttribute(Properties.Resources.XML_PT_VALUE);
                attr.Value = ((this.mepProcFlags & Mix.Tool.Graphics.ShaderProcessFlags.Atmosphere) == Mix.Tool.Graphics.ShaderProcessFlags.Atmosphere).ToString();
                elm.Attributes.Append(attr);
                mepElm.AppendChild(elm);

                elm = doc.CreateElement(Properties.Resources.XML_PT_PROCESS_SSAO);
                attr = doc.CreateAttribute(Properties.Resources.XML_PT_VALUE);
                attr.Value = ((this.mepProcFlags & Mix.Tool.Graphics.ShaderProcessFlags.SSAO) == Mix.Tool.Graphics.ShaderProcessFlags.SSAO).ToString();
                elm.Attributes.Append(attr);
                mepElm.AppendChild(elm);

                ////////////////////////////////////////////////////////////////////////////////////////////////////

                if (mepSearchDirList.Count > 0)
                {
                    mepCleanupElm = doc.CreateElement(Properties.Resources.XML_PT_CLEANUP_NAME);
                    mepElm.AppendChild(mepCleanupElm);

                    foreach (string dirPath in this.mepSearchDirList)
                    {
                        elm = doc.CreateElement(Properties.Resources.XML_PT_DIRPATH);
                        attr = doc.CreateAttribute(Properties.Resources.XML_PT_VALUE);
                        attr.Value = dirPath;
                        elm.Attributes.Append(attr);
                        mepCleanupElm.AppendChild(elm);
                    }
                }

                ////////////////////////////////////////////////////////////////////////////////////////////////////

                doc.Save(this.filePath);
            }
            catch
            {
                throw;
            }
        }
    }
}
