using System;
using System.Collections.Generic;
using System.Text;
using Yanesdk.Draw;
using Yanesdk.Ytl;
using Yanesdk.Sound;
using Yamalib.Util;
using Yanesdk.System;
using Yamalib.Yanesdkext.Draw;
using Yamalib.Model;
using System.Diagnostics;
using Yamalib.Scenario;
using Yamalib.Logger;

namespace Yamalib.Scenario.YaneScript
{

    /// <summary>
    /// シナリオビュー
    /// ITexture系での実装であることを注意すること
    /// </summary>
    public class YaneScenarioView : IScnarioView
    {
        #region 定数値
        private static readonly int SHADOW_TEXT_OFFSET_X = 2;
        private static readonly int SHADOW_TEXT_OFFSET_Y = 1;
        #endregion


        /// <summary>
        /// 描画のあとに自由に設定できるようにする
        /// </summary>
        /// <param name="screen"></param>
        /// <returns></returns>
        public delegate YanesdkResult PostPaintExcec(IScreen screen, YaneScenarioView view);

        #region メンバフィールド

        private IScenarioModel scenarioModel;
        private int offsetx = 0;
        private int offsety = 0;
        private int textOffsetx = 0;
        private int textOffsety = 0;

        private PostPaintExcec postPaintBG;
        private PostPaintExcec postPaintCharacter;
        private PostPaintExcec postPaintText;

        #endregion


        public IScenarioModel Model
        {
            get { return scenarioModel; }
            set { scenarioModel = value; }
        }

        public PostPaintExcec PostPaintBG
        {
            get { return postPaintBG; }
            set { postPaintBG = value; }
        }

        public PostPaintExcec PostPaintCharacter
        {
            get { return postPaintCharacter; }
            set { postPaintCharacter = value; }
        }

        public PostPaintExcec PostPaintText
        {
            get { return postPaintText; }
            set { postPaintText = value; }
        }

        public virtual YanesdkResult OnPaint(IScreen screen)
        {
            OnPaintBG(screen);
            if (null != PostPaintBG)
            {
                PostPaintBG(screen, this);
            }
            OnPaintCharacter(screen);
            if (null != PostPaintCharacter)
            {
                PostPaintCharacter(screen, this);
            }
            OnPaintText(screen);
            if (null != PostPaintText)
            {
                PostPaintText(screen, this);
            }

            //: TODO:
            return YanesdkResult.NoError;
        }

        public void SetViewOffsetXY(int ox, int oy)
        {
            offsetx = ox;
            offsety = oy;
        }

        public void GetViewOffsetXY(out int ox, out int oy)
        {
            ox = offsetx;
            oy = offsety;
        }

        public void SetTextOffsetXY(int ox, int oy)
        {
            textOffsetx = ox;
            textOffsety = oy;
        }

        public void GetTextOffsetXY(out int ox, out int oy)
        {
            ox = textOffsetx;
            oy = textOffsety;
        }


        #region 非公開メソッド

        /// <summary>
        /// テキスト画像の描画
        /// </summary>
        /// <param name="screen"></param>
        /// <returns></returns>
        protected YanesdkResult OnPaintText(IScreen screen)
        {
            YaneScenarioModel theModel = Model as YaneScenarioModel;
            if (theModel.IsBackLogMode)
            {
                return PaintDrawLetterBackLog(screen, theModel.BakLogletterData);
            }
            return PaintDrawLetter(screen, Model.LetterData);
        }

        /// <summary>
        /// 文字の描画
        /// </summary>
        /// <param name="screen"></param>
        /// <param name="drawCharaData"></param>
        /// <returns></returns>
        protected YanesdkResult PaintDrawLetter(IScreen screen, List<ILetterDeta> drawCharaData)
        {
            for (int i = 0; i < Model.ShowTextCount && i < drawCharaData.Count; ++i)
            {
                // 影の描画
                screen.SetColor(YanesdkUtil.BLOCK_COLOR);
                // 本文影
                PaintShadowDrawLetter(screen, drawCharaData[i]);
                // 本文字の描画
                PaintDrawLetter(screen, drawCharaData[i]);

                // ルビ影の描画
                screen.SetColor(YanesdkUtil.BLOCK_COLOR);
                List<ILetterDeta> rubi = drawCharaData[i].RubiChara;
                foreach (ScenarioParser.DrawLetter dc in rubi)
                {
                    PaintShadowDrawLetter(screen, dc);
                }

                // ルビの描画
                screen.SetColor(YanesdkUtil.WHITE_COLOR);
                foreach (ScenarioParser.DrawLetter dc in rubi)
                {
                    PaintDrawLetter(screen, dc);
                }
            }

            return YanesdkResult.NoError;
        }

        /// <summary>
        /// 文字の描画
        /// </summary>
        /// <param name="screen"></param>
        /// <param name="drawCharaData"></param>
        /// <returns></returns>
        protected YanesdkResult PaintDrawLetterBackLog(IScreen screen, List<ILetterDeta> drawCharaData)
        {
            for (int i = 0; i < drawCharaData.Count; ++i)
            {
                // 影の描画
                screen.SetColor(YanesdkUtil.BLOCK_COLOR);
                // 本文影
                PaintShadowDrawLetter(screen, drawCharaData[i]);
                // 本文字の描画
                PaintDrawLetter(screen, drawCharaData[i]);

                // ルビ影の描画
                screen.SetColor(YanesdkUtil.BLOCK_COLOR);
                List<ILetterDeta> rubi = drawCharaData[i].RubiChara;
                foreach (ScenarioParser.DrawLetter dc in rubi)
                {
                    PaintShadowDrawLetter(screen, dc);
                }

                // ルビの描画
                screen.SetColor(YanesdkUtil.WHITE_COLOR);
                foreach (ScenarioParser.DrawLetter dc in rubi)
                {
                    PaintDrawLetter(screen, dc);
                }
            }

            return YanesdkResult.NoError;
        }

        /// <summary>
        /// 引数で指定したDrawCharデータを描画します
        /// </summary>
        /// <param name="screen">描画先Screen</param>
        /// <param name="drawChar">描画データクラス</param>
        /// <returns></returns>
        private YanesdkResult PaintDrawLetter(IScreen screen, ILetterDeta drawChar)
        {
            screen.SetColor(drawChar.Color);
            return PaintDrawLetter(screen, drawChar,
                    (int)drawChar.Pos.X,
                    (int)drawChar.Pos.Y);
        }

        /// <summary>
        /// 引数で指定したDrawCharデータを影として描画する。
        /// 描画位置はオフセット位置分ずらしたものになる。
        /// </summary>
        /// <param name="screen"></param>
        /// <param name="drawChar"></param>
        /// <returns></returns>
        private YanesdkResult PaintShadowDrawLetter(IScreen screen, ILetterDeta drawChar)
        {
            screen.SetColor(YanesdkUtil.BLOCK_COLOR);
            return PaintDrawLetter(screen, drawChar,
                    (int)drawChar.Pos.X + SHADOW_TEXT_OFFSET_X,
                    (int)drawChar.Pos.Y + SHADOW_TEXT_OFFSET_Y);
        }

        /// <summary>
        /// 引数で指定したDrawChar をそれに指定されたsizeで
        /// 引数で指定されたx,yに描画する
        /// </summary>
        /// <param name="screen">描画先Screen</param>
        /// <param name="drawChar">描画データクラス</param>
        /// <param name="X">描画位置</param>
        /// <param name="Y">描画位置</param>
        /// <returns></returns>
        private YanesdkResult PaintDrawLetter(IScreen screen, ILetterDeta drawChar, int x, int y)
        {
            if (0.0f >= drawChar.Size)
            {
                return YanesdkResult.InvalidParameter;
            }
            if (1.0f != drawChar.Size || 0 != drawChar.Angle)
            {
                int basePos = 0 != drawChar.Angle ? 6 : 0;
                screen.BltRotate(
                    drawChar.ImgObj as ITexture,	// テクスチャ 
                    textOffsetx + offsetx + x,
                    textOffsety + offsety + y, 	// X,Y 位置
                    drawChar.Angle, 	// 回転角
                    drawChar.Size, 		// 拡大率
                    basePos			// 描画ベース位置（左上）
                    );
            }
            else
            {
                screen.Blt(drawChar.ImgObj as ITexture, textOffsetx + offsetx + x, textOffsety + offsety + y);
            }

            return YanesdkResult.NoError;
        }

        /// <summary>
        /// 背景を描画する
        /// </summary>
        /// <param name="screen"></param>
        /// <returns></returns>
        protected YanesdkResult OnPaintBG(IScreen screen)
        {
            if (null == Model.BgImgMgr)
            {
                // 背景を使用しないもOK
                return YanesdkResult.NoError;
            }
            ITexture surfaceTexture = Model.BgImgMgr.GetTexture();
            ITexture backTexture = Model.BgImgMgr.GetEffectOutTexture();
            int effectNo = Model.BgImgMgr.EffectNo;
            int effectPhase = Model.BgImgMgr.EffectPhase;

            if (null != backTexture)
            {
                screen.Blt(backTexture, 0, 0);
            }

            if (null != surfaceTexture)
            {
                if (effectNo >= 0 && TransBltter.PAHSE_MAX != effectPhase)
                {
                    TransBltter.Blt(effectNo, screen, surfaceTexture, offsetx, offsety, effectPhase);
                }
                else
                {
                    screen.Blt(surfaceTexture, 0, 0);
                }
            }

            return YanesdkResult.NoError;
        }


        /// <summary>
        /// キャラクターを描画する
        /// </summary>
        /// <param name="screen"></param>
        /// <returns></returns>
        protected YanesdkResult OnPaintCharacter(IScreen screen)
        {
            if (null == Model.CharacterImgMgr)
            {
                // キャラクターを使用しないのもOK
                return YanesdkResult.NoError;
            }
            YaneCharacterManager characterMgr = Model.CharacterImgMgr as YaneCharacterManager;
            if (null == characterMgr)
            {
                return YanesdkResult.PreconditionError;
            }

            Character[] characters = characterMgr.CharacterContainer;
            foreach (Character chara in characters)
            {
                chara.OnPaint(screen, true);
            }

            //チェック
            for (int i = 0; i < characters.Length; i++)
            {
                for (int j = 0; j < characters.Length; j++)
                {
                    if (i == j || characters[i].GetCharId() == null)
                    {
                        continue;
                    }
                    Debug.Assert(characters[i].GetCharId() != characters[j].GetCharId(), "キャラクターIDが重複:" + characters[i].GetCharId());
                }
            }


            return YanesdkResult.NoError;
        }

        #endregion

    }

    /// <summary>
    /// シナリオモデルを提供する
    /// </summary>
    public class YaneScenarioModel : IScenarioModel, IDisposable
    {

        #region 定数値フィールド

        private static readonly List<ILetterDeta> NULL_LETTER_DATA = new List<ILetterDeta>();

        #endregion

        #region メンバフィールド

        private IScenarioState scenarioState;
        /// <summary>
        /// シナリオパーサ
        /// 固有のクラスなので、インターフェースも検討すること
        /// </summary>
        private ScenarioParser scenarioParser;
        private ICommandHandlerFactory commandFactory;
        private ICharacterImageManager characterImgMgr;
        private IBgImageManager bgImgMgr;
        private IBgmResourceManager bgmManager;
        private ISeResourceManager seManager;
        private IVoiceResourceManager voiceManager;
        private List<ILetterDeta> letterData;
        private List<ILetterDeta> bakLogletterData;
        private MouseInputHandler mouseInputHandler;
        private KeyInputHandler keyInputHandler;
        protected readonly List<ICommandHandler> currentPageTags = new List<ICommandHandler>();
        private readonly List<IViewLayler> viewLayers = new List<IViewLayler>();
        private int readSpeed = 1;
        private int backLogDepth = 0;
        private bool backLogMode = false;

        private readonly RootCounterS textPhaseCounter = new RootCounterS(0, int.MaxValue, 1);
        private bool autoRead = false;
        private bool enableReadStop = true;

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public YaneScenarioModel()
        {
            scenarioState = new YaneScenarioState();
        }

        /// <summary>
        /// リソースの破棄を行う
        /// </summary>
        public void Dispose()
        {
            YamalibUtility.Dispose(characterImgMgr);
            YamalibUtility.Dispose(bgImgMgr);
            YamalibUtility.Dispose(seManager);
            YamalibUtility.Dispose(voiceManager);
        }

        /// <summary>
        /// シナリオスクリプトでのコマンドハンドラファクトリの設定・取得
        /// </summary>
        public ICommandHandlerFactory CommandFactory
        {
            get { return commandFactory; }
            set { commandFactory = value; }
        }

        /// <summary>
        /// シナリオ動作におけるマウス入力ハンドラを設定
        /// </summary>
        public MouseInputHandler MouseInputHandler
        {
            get { return mouseInputHandler; }
            set { mouseInputHandler = value; }
        }

        /// <summary>
        /// シナリオ動作におけるキー入力ハンドラを設定
        /// </summary>
        public KeyInputHandler KeyInputHandler
        {
            get { return keyInputHandler; }
            set { keyInputHandler = value; }
        }

        /// <summary>
        /// シナリオの状態
        /// </summary>
        public IScenarioState ScenarioState
        {
            get { return scenarioState; }
            set { scenarioState = value; }
        }

        /// <summary>
        /// リセット。以下の処理を行う
        /// 現在ページの文字データ破棄
        /// 現在ページのタグデータは破棄
        /// pageend、readstopフラグをおろす
        /// </summary>
        public void Reset()
        {
            letterData = null;
            textPhaseCounter.Set(0, int.MaxValue, 1);
            currentPageTags.Clear();
            ScenarioState.ReadStopFlg = false;
            ScenarioState.PageEndFlg = false;
        }

        /// <summary>
        /// 読み取り専用。読み止まり中かどうか
        /// </summary>
        public bool IsReadStop
        {
            get { return scenarioState.ReadStopFlg; }
        }

        /// <summary>
        /// エフェクトによる待機中か
        /// </summary>
        public bool IsEffectWait
        {
            get { return false; }
        }

        /// <summary>
        /// 現在のシナリオがすべて完了したか
        /// </summary>
        public bool IsScenarioFinish
        {
            get { return scenarioState.ScenarioEndFlg; }
        }

        /// <summary>
        /// ページ表示がすべて完了したか
        /// </summary>
        public bool IsPageEnd
        {
            get { return scenarioState.PageEndFlg; }
        }

        /// <summary>
        /// 自動読みにするか
        /// </summary>
        public bool IsAutoRead
        {
            get { return autoRead; }
            set { autoRead = value; }
        }

        /// <summary>
        /// バックログ表示にするかどうか
        /// </summary>
        public bool IsBackLogMode
        {
            get { return backLogMode; }
            set
            {
                backLogMode = value;
                if (backLogMode)
                {
                    scenarioParser.SetBackLogMode(true);
                    scenarioState.InputLockFlg = true;
                    backLogDepth = 0;

                    // scenarioParser から取得した LetterData の参照をもっているとデータがこわれる
                    List<ILetterDeta> tmpLetterData = new List<ILetterDeta>();
                    for (int i = 0; i < letterData.Count; i++)
                    {
                        tmpLetterData.Add(letterData[i].Clone());
                    }
                    letterData = tmpLetterData;

                    PrevBackLog();
                }
                else
                {
                    scenarioParser.SetBackLogMode(false);
                    scenarioState.InputLockFlg = false;
                }
            }
        }

        /// <summary>
        /// 前のバックログへ
        /// </summary>
        public void PrevBackLog()
        {
            if (IsBackLogMode)
            {
                UpdateTextBackPrev();
            }
        }

        /// <summary>
        /// 次のバックログへ
        /// </summary>
        public void NextBackLog()
        {
            if (IsBackLogMode)
            {
                UpdateTextBackNext();
            }
        }


        /// <summary>
        /// ページ内のReadStopコマンドが有効かどうか
        /// </summary>
        public bool IsEnableReadStop
        {
            get { return enableReadStop; }
            set { enableReadStop = value; }
        }

        /// <summary>
        /// 表示中の文字の数
        /// </summary>
        public int ShowTextCount
        {

            get { return textPhaseCounter.Value(); }
        }

        /// <summary>
        /// リストア専用
        /// </summary>
        /// <param name="count"></param>
        /// <returns></returns>
        public void SetShowTextCountForRestore(int count)
        {
            if (count > textPhaseCounter.EndValue)
            {
                textPhaseCounter.Set(textPhaseCounter.EndValue, textPhaseCounter.EndValue, textPhaseCounter.StepValue);
            }
            else
            {
                textPhaseCounter.Set(count, textPhaseCounter.EndValue, textPhaseCounter.StepValue);
            }

            for (int i = 0; i < currentPageTags.Count; i++)
            {
                if (currentPageTags[i].ExecPosition <= textPhaseCounter.StartValue)
                {
                    // 終わったものとして、コマンドを消去
                    currentPageTags[i] = NullCommandHandler.Instance;
                }
            }

        }

        /// <summary>
        /// このページに含まれている文字の数
        /// </summary>
        public int PageTextCount
        {
            get { return textPhaseCounter.EndValue; }
        }

        /// <summary>
        /// キャラクターイメージマネージャを取得する
        /// </summary>
        public ICharacterImageManager CharacterImgMgr
        {
            set { characterImgMgr = value; }
            get { return characterImgMgr; }
        }

        /// <summary>
        /// 背景イメージマネージャを取得する
        /// </summary>
        public IBgImageManager BgImgMgr
        {
            set { bgImgMgr = value; }
            get { return bgImgMgr; }
        }

        /// <summary>
        /// BGMマネージャを取得する
        /// </summary>
        public IBgmResourceManager BgmMgr
        {
            set { bgmManager = value; }
            get { return bgmManager; }
        }

        /// <summary>
        /// SEマネージャを取得する
        /// </summary>
        public ISeResourceManager SeMgr
        {
            set { seManager = value; }
            get { return seManager; }
        }

        /// <summary>
        /// ボイスマネージャを取得する
        /// </summary>
        public IVoiceResourceManager VoiceMgr
        {
            set { voiceManager = value; }
            get { return voiceManager; }
        }

        /// <summary>
        /// 文字表示速度を取得・設定する
        /// </summary>
        public int ReadSpeed
        {
            get { return readSpeed; }
            set { readSpeed = value; }
        }

        /// <summary>
        /// シナリオスクリプトパーサーの取得
        /// </summary>
        public ScenarioParser ScenarioParser
        {
            get { return scenarioParser; }
            set { scenarioParser = value; }
        }

        /// <summary>
        /// テキスト文字データの取得
        /// </summary>
        public List<ILetterDeta> LetterData
        {
            get
            {
                if (null == letterData)
                {
                    // nullチェックとかめんどい
                    return NULL_LETTER_DATA;
                }
                return letterData;
            }
        }

        /// <summary>
        /// バックログ用のテキスト文字データの取得
        /// </summary>
        public List<ILetterDeta> BakLogletterData
        {
            get
            {
                if (null == bakLogletterData)
                {
                    // nullチェックとかめんどい
                    return NULL_LETTER_DATA;
                }
                return bakLogletterData;
            }
        }

        /// <summary>
        /// レイヤー
        /// </summary>
        public List<IViewLayler> ViewLayler
        {
            get { return viewLayers; }
            set { throw new Exception(YanesdkResult.NotImplemented.ToString()); }
        }

        /// <summary>
        /// 移動処理
        /// </summary>
        /// <param name="screen"></param>
        /// <returns></returns>
        public virtual YanesdkResult OnMove(IScreen screen)
        {
            // テキストを薦める
            OnMoveTextPhaseCouner();

            if (mouseInputHandler != null)
            {
                mouseInputHandler.OnHandle(this);
            }

            if (KeyInputHandler != null)
            {
                keyInputHandler.OnHandle(this);
            }

            if (null != characterImgMgr)
            {
                // キャラクター
                Character[] characters = ((YaneCharacterManager)characterImgMgr).CharacterContainer;
                foreach (Character chara in characters)
                {
                    chara.OnMove(screen);
                }
            }

            // レイヤー
            foreach (IViewLayler layer in viewLayers)
            {
                layer.OnMove(screen);
            }

            if (null != bgImgMgr)
            {
                // 背景
                bgImgMgr.OnMove(screen);
            }

            if (null != seManager)
            {
                seManager.Update();
            }

            return YanesdkResult.NoError;
        }


        /// <summary>
        /// 読み続ける
        /// </summary>
        /// <returns></returns>
        public YanesdkResult ContinueRead()
        {
            if (null == letterData)
            {
                UpdateText();
            }

            if (IsPageEnd)
            {
                UpdateText();
            }
            else if (IsNextReadable())
            {
                scenarioState.ReadStopFlg = false;
            }

            return YanesdkResult.NoError;
        }

        /// <summary>
        /// 読みを中断させる
        /// </summary>
        /// <returns></returns>
        public YanesdkResult StopRead()
        {
            return YanesdkResult.NoError;
        }

        #region 非公開メソッド

        /// <summary>
        /// 読み続けることができる状態か
        /// </summary>
        /// <returns></returns>
        private bool IsNextReadable()
        {
            if (scenarioState.ReadSkipFlg)
            {
                return true;
            }
            return !IsEffectWait && IsReadStop;
        }

        /// <summary>
        /// タグIDを取得する
        /// </summary>
        /// <param name="rawCommand"></param>
        /// <returns></returns>
        private static String GetTagId(String rawCommand)
        {
            CSVReader reader = new CSVReader();
            reader.Read(YanesdkUtil.FILE_READ_ON_MEMORY_FLG + rawCommand);
            if (null != reader.CsvData && reader.CsvData.Count != 0 && reader.CsvData[0].Count != 0)
            {
                //Console.WriteLine("FOUND TAG:{0}", reader.CsvData[0][0]);
                return reader.CsvData[0][0];
            }
            Console.Write("UNKOWN TAG:{0}", rawCommand);
            return null;
        }

        /// <summary>
        /// 次のページに移行する
        /// </summary>
        protected virtual void UpdateText()
        {
            scenarioParser.UpdateText();
            letterData = scenarioParser.DrawCharacterData;
            textPhaseCounter.Set(0, letterData.Count, 1);
            UnknownTagToCommand(scenarioParser.UnknownTags);
            if (scenarioParser.IsParseFinish)
            {
                scenarioState.ScenarioEndFlg = true;
            }
            else
            {
                ScenarioState.ReadStopFlg = false;
                ScenarioState.PageEndFlg = false;
            }
        }

        protected virtual void UpdateTextBackPrev()
        {
            if (scenarioParser.UpdateTextBack())
            {
                ++backLogDepth;
                bakLogletterData = scenarioParser.BackLogDrawCharacter;
            }
        }

        protected virtual void UpdateTextBackNext()
        {
            if (backLogDepth > 1 && scenarioParser.UpdateText())
            {
                --backLogDepth;
                bakLogletterData = scenarioParser.BackLogDrawCharacter;
            }
        }

        /// <summary>
        /// テキストを進める
        /// </summary>
        private void OnMoveTextPhaseCouner()
        {
            if (!scenarioState.ReadStopFlg)
            {
                int roopCounter = textPhaseCounter.EndValue < ReadSpeed ? textPhaseCounter.EndValue : ReadSpeed;
                for (int i = 0; i < roopCounter; i++)
                {
                    textPhaseCounter.Inc();
                    // 文字を進めて存在したタグを実行
                    DoCommandHanlder();
                    if (IsAutoRead)
                    {
                        scenarioState.ReadStopFlg = false;
                    }
                    else if (!IsEnableReadStop && !IsPageEnd)
                    {
                        scenarioState.ReadStopFlg = false;
                    }
                    if (scenarioState.ReadStopFlg)
                    {
                        break;
                    }
                }
            }
            else
            {
                // テキストは進めないとしても、ハンドラは動かしておかないと
                DoCommandHanlder();
            }

            if (textPhaseCounter.IsEnd)
            {
                scenarioState.PageEndFlg = true;
                if (scenarioState.ReadSkipFlg || IsAutoRead)
                {
                    // スキップなら自動的に進む
                    ContinueRead();
                }
            }
        }

        /// <summary>
        /// 登録されているコマンドハンドラすべて起動する
        /// </summary>
        private void DoCommandHanlder()
        {
            foreach (ICommandHandler handler in currentPageTags)
            {
                YanesdkResult result = handler.DoCommand(this);
                if (result != YanesdkResult.NoError)
                {
                    PrintDebug(result, "TagHandler");
                }
            }
        }

        /// <summary>
        /// タグからハンドラを生成し保持
        /// </summary>
        /// <param name="tagInfos"></param>
        private void UnknownTagToCommand(List<ScenarioParser.UnknownTagInfo> tagInfos)
        {
            currentPageTags.Clear();
            foreach (ScenarioParser.UnknownTagInfo tag in tagInfos)
            {
                String tagId = GetTagId(tag.Tag);
                if (null != tagId)
                {
                    ICommandHandler handler = commandFactory.Create(tagId.ToLower());
                    handler.SetCommand(tag.Tag);
                    handler.ExecPosition = tag.Pos;
                    currentPageTags.Add(handler);
                }
            }
        }

        private static void PrintDebug(YanesdkResult result, String addMsg)
        {
            Console.WriteLine("Error {0} : result code = {1}", addMsg, result);
        }

        #endregion

    }


    /// <summary>
    /// シナリオの状態を表すデータクラス
    /// </summary>
    public class YaneScenarioState : IScenarioState
    {
        #region メンバフィールド
        private bool readstopFlg;
        private bool pageEndFlg;
        private bool scenarioEndFlg;
        private bool jumpAnotherSceneFlg;
        private bool characterEffectWait;
        private bool bgEffectWait;
        private bool inputLock;
        private bool readSkipFlg;

        #endregion

        public bool ReadStopFlg
        {
            get { return readstopFlg; }
            set { readstopFlg = value; }
        }

        public bool PageEndFlg
        {
            get { return pageEndFlg; }
            set { pageEndFlg = value; }
        }

        public bool ScenarioEndFlg
        {
            get { return scenarioEndFlg; }
            set { scenarioEndFlg = value; }

        }

        public bool JumpAnotherSceneFlg
        {
            get { return jumpAnotherSceneFlg; }
            set { jumpAnotherSceneFlg = value; }
        }

        public bool CharacterEffectWaitFlg
        {
            get
            {
                return characterEffectWait;
            }
            set
            {
                characterEffectWait = value;
            }
        }

        public bool BgEffectWaitFlg
        {
            get
            {
                return bgEffectWait;
            }
            set { bgEffectWait = value; }
        }

        #region IScenarioState メンバ

        /// <summary>
        /// インプットロックフラグ
        /// </summary>
        public bool InputLockFlg
        {
            get
            {
                return inputLock;
            }
            set
            {
                inputLock = value;
            }
        }

        #endregion

        #region IScenarioState メンバ


        public bool ReadSkipFlg
        {
            get
            {
                return readSkipFlg;
            }
            set
            {
                readSkipFlg = value;
            }
        }

        #endregion
    }

    /// <summary>
    /// 背景の管理
    /// </summary>
    public class YaneBgImageManager : IBgImageManager
    {
        #region 定数値
        public static readonly int INVALID_BG_NO = -1;

        #endregion

        #region メンバフィールド

        private bool disableDraw = true;
        private readonly TextureLoader textureLoader;
        private int oldBgImgNo = INVALID_BG_NO;
        private int bgImgNo = INVALID_BG_NO;
        private readonly RootCounterS effectPhaseCounter = new RootCounterS();
        private int effectType;
        private int posx;
        private int posy;
        private float drawSize = 1.0f;
        private Color4ub color = YanesdkUtil.WHITE_COLOR;
        #endregion


        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="loader"></param>
        public YaneBgImageManager(TextureLoader loader)
        {
            this.textureLoader = loader;
            effectPhaseCounter.Set(TransBltter.PAHSE_MAX, TransBltter.PAHSE_MAX, 0);
        }


        /// <summary>
        /// 描画するかどうか
        /// 描画状態は内部で保持する
        /// </summary>
        public bool DrawDisable
        {
            get { return disableDraw; }
            set { disableDraw = value; }
        }

        /// <summary>
        /// このリソースは表示中か
        /// </summary>
        public bool IsShowing
        {
            get { return bgImgNo != INVALID_BG_NO; }
        }

        /// <summary>
        /// エフェクト中か
        /// </summary>
        public bool IsEffecting
        {
            get
            {
                if (IsShowing)
                {
                    return !effectPhaseCounter.IsEnd;
                }
                return false;
            }
        }

        public void SetEffect(int effectNo, int start, int end, int speed)
        {
            this.effectType = effectNo;
            effectPhaseCounter.Set(start, end, speed);
        }

        public int EffectNo
        {
            get { return this.effectType; }
        }

        public int EffectPhase
        {
            get { return effectPhaseCounter.Value(); }
        }

        public int X
        {
            set { posx = value; }
            get { return posx; }
        }
        public int Y
        {
            set { posy = value; }
            get { return posy; }
        }

        public float Size
        {
            set { drawSize = value; }
            get { return drawSize; }
        }

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

        /// <summary>
        /// エフェクトアウトしていくイメージ番号
        /// </summary>
        public int EffectOutBgImgNo
        {
            get { return oldBgImgNo; }
        }

        public int BgImgNo
        {
            set
            {
                oldBgImgNo = bgImgNo;
                bgImgNo = value;
            }
            get
            {
                return bgImgNo;
            }
        }

        /// <summary>
        /// テクスチャの取得
        /// </summary>
        /// <returns></returns>
        public ITexture GetTexture()
        {
            if (!IsShowing)
            {
                return null;
            }
            return textureLoader.GetTexture(bgImgNo);
        }

        /// <summary>
        /// エフェクトアウトしているテクスチャの取得
        /// </summary>
        /// <returns></returns>
        public ITexture GetEffectOutTexture()
        {
            if (EffectOutBgImgNo == INVALID_BG_NO)
            {
                return null;
            }
            return textureLoader.GetTexture(EffectOutBgImgNo);
        }

        /// <summary>
        /// リソースの管理値を次に移行させる
        /// </summary>
        /// <param name="screen"></param>
        /// <returns></returns>
        public YanesdkResult OnMove(IScreen screen)
        {
            if (IsShowing)
            {
                effectPhaseCounter.Inc();
            }
            return YanesdkResult.NoError;
        }

    }

    /// <summary>
    /// 表示キャラクターの管理
    /// </summary>
    public class YaneCharacterManager : ICharacterImageManager, IDisposable
    {
        #region メンバフィールド

        private bool drawDisable = false;
        private List<ICharacterImageResource> charaImgs = new List<ICharacterImageResource>();
        private Character[] character;
        private TextureLoader characterImgTextureLoader;

        #endregion

        public bool DrawDisable
        {
            get { return drawDisable; }
            set { drawDisable = value; }
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public YaneCharacterManager(TextureLoader charaTl, String charaMapDefFile, int maxCharacterContainer)
        {
            character = new Character[maxCharacterContainer];
            Character.SetCharMap(charaMapDefFile);
            for (int i = 0; i < character.Length; ++i)
            {
                character[i] = new Character();
                character[i].SetTextureLoader(charaTl);
            }

            CharacterImgTextureLoader = charaTl;
        }

        public TextureLoader CharacterImgTextureLoader
        {
            get { return characterImgTextureLoader; }
            set
            {
                for (int i = 0; i < character.Length; ++i)
                {
                    character[i].SetTextureLoader(value);
                }
                characterImgTextureLoader = value;
            }
        }


        /// <summary>
        /// リソースの破棄を行う
        /// </summary>
        public void Dispose()
        {
            foreach (Character chara in character)
            {
                YamalibUtility.Dispose(chara);
            }
        }

        /// <summary>
        /// キャラクターコンテナの取得
        /// </summary>
        public Character[] CharacterContainer
        {
            get { return character; }
        }

        /// <summary>
        /// キャラクターイメージの取得
        /// </summary>
        /// <param name="no"></param>
        /// <returns></returns>
        public ICharacterImageResource GetCharacterImage(int no)
        {
            if (charaImgs.Count <= no)
            {
                return null;
            }
            return charaImgs[no];
        }

        public ICharacterImageResource GetNewCharacterImage(string id)
        {
            Character targetCharacter = GetUnuseCharacter() as Character;
            if (null == targetCharacter)
            {
                return null;
            }
            targetCharacter.Reset();
            targetCharacter.SetCharId(id);
            return targetCharacter;
        }

        /// <summary>
        /// キャラクターのキーIDからキャラクタークラスを取得する
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ICharacterImageResource GetCharacterImage(String id)
        {
            return GetCharacterCurrent(id);
        }

        /// <summary>
        /// キャラクターのイメージの取得
        /// </summary>
        /// <param name="no"></param>
        /// <returns></returns>
        public IImageResource GetImage(int no)
        {
            return GetCharacterImage(no);
        }

        #region 非公開メソッド

        /// <summary>
        /// コンテナにidがあればそれを返却する
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        private ICharacterImageResource GetCharacterCurrent(String id)
        {
            if (null == id)
            {
                return null;
            }
            foreach (Character chara in character)
            {
                if (id == chara.GetCharId())
                {
                    return chara;
                }
            }
            return null;
        }

        /// <summary>
        /// コンテナで使用していないキャラクターを取得する
        /// </summary>
        /// <returns></returns>
        private ICharacterImageResource GetUnuseCharacter()
        {
            foreach (Character chara in character)
            {
                if (!chara.IsShowing)
                {
                    return chara;
                }
            }
            /// 全部使っている。フェードアウトしてるキャラクターを返すか...
            foreach (Character chara in character)
            {
                if (chara.IsEffectOut() && !chara.ReplaceFlg)
                {
                    chara.Reset();
                    return chara;
                }
            }

            Debug.Assert(false, "CharacterContainerに空きがない");
            return null;
        }

        #endregion

    }

    /// <summary>
    /// サウンドの管理
    /// </summary>
    public class YaneSoundResourceManager : ISoundResourceManager, IDisposable
    {
        #region メンバフィールド
        private SoundLoader soundLoader;
        private bool disableSound = false;

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="SoundLoader"></param>
        public YaneSoundResourceManager(SoundLoader soundLoader)
        {
            Debug.Assert(soundLoader != null);
            this.soundLoader = soundLoader;
        }

        /// <summary>
        /// リソースの破棄を行う
        /// </summary>
        public void Dispose()
        {
            YamalibUtility.Dispose(SoundLoader);
        }

        /// <summary>
        /// サウンドローダーの設定
        /// </summary>
        public SoundLoader SoundLoader
        {
            get { return soundLoader; }
            set { soundLoader = value; }
        }

        /// <summary>
        /// サウンドを再生するかどうか
        /// 再生状態については内部で保持する
        /// </summary>
        public virtual bool SoundDisable
        {
            get { return disableSound; }
            set
            {
                disableSound = value;
            }
        }

        /// <summary>
        /// 生のデータを取得する
        /// </summary>
        /// <param name="no"></param>
        /// <returns></returns>
        public Sound GetSound(int no)
        {
            return SoundLoader.GetSound(no);
        }

    }

    /// <summary>
    /// BGMを管理する
    /// </summary>
    public class YaneBgmManager : YaneSoundResourceManager, IBgmResourceManager
    {
        #region 定数値

        public static readonly int INVALIDE_BGM_NO = -1;

        #endregion

        #region メンバフィールド

        private int oldPlayBgmNo = INVALIDE_BGM_NO;
        private int playBgmNo = INVALIDE_BGM_NO;
        private float playBgmVolume = 0;
        private float masterVolume = 1.0f;

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="SoundLoader"></param>
        public YaneBgmManager(SoundLoader soundLoader)
            : base(soundLoader)
        {
        }

        /// <summary>
        /// マスターボリュームの設定
        /// </summary>
        public float MasterVolume
        {
            get { return masterVolume; }
            set
            {
                masterVolume = value;
                PlayBgmVolume = PlayBgmVolume;
            }
        }

        public override bool SoundDisable
        {
            get
            {
                return base.SoundDisable;
            }
            set
            {
                if (SoundDisable != value)
                {
                    if (value)
                    {
                        // 新たに無効にする
                        if (INVALIDE_BGM_NO != playBgmNo)
                        {
                            SoundLoader.StopBGM();
                        }
                    }
                    else
                    {
                        // 新たに有効にする
                        if (INVALIDE_BGM_NO != playBgmNo)
                        {
                            SoundLoader.PlayBGM(playBgmNo);
                        }
                    }
                    base.SoundDisable = value;
                }
            }
        }

        /// <summary>
        /// 再生しているBGM番号
        /// </summary>
        public int PlayBgmNo
        {
            get { return playBgmNo; }
            set { playBgmNo = value; }
        }

        /// <summary>
        ///  ボリューム
        /// </summary>
        public float PlayBgmVolume
        {
            get { return playBgmVolume; }
            set
            {
                if (IsPalying)
                {
                    SetVolume(playBgmNo, GetAdjustVolume(value));
                }
            }
        }

        /// <summary>
        /// BGMが再生されているか
        /// ただし、フェード中も停止していると見なす
        /// </summary>
        public bool IsPalying
        {
            get { return playBgmNo != INVALIDE_BGM_NO; }
        }

        /// <summary>
        /// 再生する
        /// </summary>
        /// <param name="playNo"></param>
        /// <param name="volume"></param>
        /// <returns></returns>
        public YanesdkResult PlayBgm(int playNo, float volume)
        {
            YanesdkResult result = SetVolume(playNo, GetAdjustVolume(volume));
            if (YanesdkResult.NoError != result)
            {
                playBgmVolume = 0;
                return YanesdkResult.InvalidParameter;
            }
            playBgmVolume = volume;
            result = SetLoopInfinity(playNo);
            if (YanesdkResult.NoError != result)
            {
                return YanesdkResult.InvalidParameter;
            }
            if (SoundDisable)
            {
                result = YanesdkResult.NoError;
            }
            else
            {
                result = SoundLoader.PlayBGM(playNo);
            }

            CheckPlayResult(result, playNo);
            return result;
        }

        /// <summary>
        /// 再生する
        /// </summary>
        /// <param name="playNo"></param>
        /// <param name="volume"></param>
        /// <param name="fadeTime"></param>
        /// <returns></returns>
        public YanesdkResult PlayBgmFade(int playNo, float volume, int fadeTime)
        {
            YanesdkResult result = SetVolume(playNo, GetAdjustVolume(volume));
            if (YanesdkResult.NoError != result)
            {
                return YanesdkResult.InvalidParameter;
            }
            playBgmVolume = volume;
            result = SetLoopInfinity(playNo);
            if (YanesdkResult.NoError != result)
            {
                return YanesdkResult.InvalidParameter;
            }

            if (SoundDisable)
            {
                result = YanesdkResult.NoError;
            }
            else
            {
                if (PlayBgmNo != INVALIDE_BGM_NO)
                {
                    // クロスフェード
                    result = SoundLoader.PlayBGMCrossFade(playNo, fadeTime);
                }
                else
                {
                    result = SoundLoader.PlayBGMFade(playNo, fadeTime);
                }
            }

            CheckPlayResult(result, playNo);
            return result;
        }

        /// <summary>
        /// 停止
        /// </summary>
        /// <returns></returns>
        public YanesdkResult StopBgm()
        {
            if (PlayBgmNo == INVALIDE_BGM_NO)
            {
                return YanesdkResult.NoError;
            }
            playBgmNo = INVALIDE_BGM_NO;
            return SoundLoader.StopBGM();
        }

        /// <summary>
        /// フェード停止
        /// </summary>
        /// <param name="fadeTime"></param>
        /// <returns></returns>
        public YanesdkResult StopBgmFade(int fadeTime)
        {
            if (PlayBgmNo == INVALIDE_BGM_NO)
            {
                return YanesdkResult.NoError;
            }
            playBgmNo = INVALIDE_BGM_NO;
            return SoundLoader.StopBGMFade(fadeTime);
        }

        /// <summary>
        /// 再生用要求後の結果をチェックし、成功していれば再生中のBGM番号をストアする
        /// </summary>
        /// <param name="result"></param>
        private void CheckPlayResult(YanesdkResult result, int playNo)
        {
            // TODO: ライブラリ側で正常終了でもエラーが帰ってくる(´д`)
            if (YanesdkResult.NoError == result || true)
            {
                OldBgmNo = PlayBgmNo;
                PlayBgmNo = playNo;
            }
        }

        /// <summary>
        ///　停止要求後の結果をチェックし、停止された曲番号をストアする
        /// </summary>
        /// <param name="result"></param>
        private void CheckStopResult(YanesdkResult result)
        {
            // TODO: ライブラリ側で正常終了でもエラーが帰ってくる(´д`)
            if (YanesdkResult.NoError == result)
            {
                OldBgmNo = PlayBgmNo;
                PlayBgmNo = INVALIDE_BGM_NO;
            }
            else
            {
                // 失敗したということだけど...とりあえず止まっているとみなしたほうがいいか
                OldBgmNo = PlayBgmNo;
                PlayBgmNo = INVALIDE_BGM_NO;
            }
        }

        /// <summary>
        /// マスターボリュームで調整した音量を取得する
        /// </summary>
        /// <param name="volume"></param>
        /// <returns></returns>
        private float GetAdjustVolume(float volume)
        {
            return volume * masterVolume;
        }

        /// <summary>
        /// 無限ループに設定する
        /// </summary>
        /// <param name="playNo"></param>
        /// <returns></returns>
        private YanesdkResult SetLoopInfinity(int playNo)
        {
            Sound sound = SoundLoader.GetSound(playNo);
            if (null == sound)
            {
                return YanesdkResult.InvalidParameter;
            }
            sound.Loop = -1;
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// ボリュームを設定する
        /// </summary>
        /// <param name="playNo"></param>
        /// <param name="volume"></param>
        /// <returns></returns>
        private YanesdkResult SetVolume(int playNo, float volume)
        {
            Sound sound = SoundLoader.GetSound(playNo);
            if (null == sound)
            {
                return YanesdkResult.InvalidParameter;
            }
            sound.Volume = volume;
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// 
        /// </summary>
        private int OldBgmNo
        {
            get { return oldPlayBgmNo; }
            set { oldPlayBgmNo = value; }
        }
    }

    /// <summary>
    /// SEを管理する
    /// </summary>
    public class YaneSeManager : YaneSoundResourceManager, ISeResourceManager
    {
        #region 定数値
        public static readonly int INVALID_SE_NO = -1;

        #endregion

        #region メンバフィールド
        private List<int> playSeNo = new List<int>();
        private readonly List<int> playSeList = new List<int>();
        private float masterVolume = 1.0f;

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="SoundLoader"></param>
        public YaneSeManager(SoundLoader soundLoader)
            : base(soundLoader)
        {
        }

        public float MasterVolume
        {
            get { return masterVolume; }
            set { masterVolume = value; }
        }

        public YanesdkResult StopAll()
        {
            foreach (int seNo in playSeNo)
            {
                StopSe(seNo);
            }
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// ボイス無効フラグ
        /// </summary>
        public override bool SoundDisable
        {
            get
            {
                return base.SoundDisable;
            }
            set
            {
                if (SoundDisable != value)
                {
                    if (value)
                    {
                        foreach (int no in playSeNo)
                        {
                            // 新たに無効にする
                            if (INVALID_SE_NO != no)
                            {

                                SoundLoader.Stop(no);
                            }
                        }
                    }
                    else
                    {
                        foreach (int no in playSeNo)
                        {
                            // 新たに有効にする
                            if (INVALID_SE_NO != no)
                            {
                                SoundLoader.Play(no);
                            }
                        }
                    }
                    base.SoundDisable = value;
                }
            }
        }

        /// <summary>
        /// SEの再生状況を更新する
        /// </summary>
        public void Update()
        {
            SoundLoader.UpdateSE();

            playSeList.Clear();
            // 再生しているSEのチェック
            // TODO ここは、se_stop 命令も考慮しないといけない
            foreach (int no in playSeNo)
            {
                if (SoundLoader.GetSound(no).IsPlaying())
                {
                    playSeList.Add(no);
                }
            }
            playSeNo = playSeList;
        }

        /// <summary>
        /// 再生しているSEを取得する
        /// これはUpdate後に更新される
        /// </summary>
        /// <returns>再生しているSEの番号の配列</returns>
        public int[] GetPlayingSeNo()
        {
            return playSeList.ToArray();
        }

        /// <summary>
        /// 効果音を再生する
        /// </summary>
        /// <param name="playNo"></param>
        /// <param name="volume"></param>
        /// <param name="loopTime"></param>
        /// <returns></returns>
        public YanesdkResult PlaySe(int playNo, float volume, int loopTime)
        {
            YanesdkResult result = SetLoopTime(playNo, loopTime);
            if (YanesdkResult.NoError != result)
            {
                return result;
            }
            result = SetVolume(playNo, GetAdjustVolume(volume));
            if (YanesdkResult.NoError != result)
            {
                return result;
            }

            // 再生中にダブって再生させたとしても、
            // 管理上は曲番号なので、どのチャンクで鳴っているかは把握出来ない
            if (!playSeNo.Contains(playNo))
            {
                playSeNo.Add(playNo);
            }

            if (SoundDisable)
            {
                return YanesdkResult.NoError;
            }
            else
            {
                return SoundLoader.PlaySE(playNo);
            }

        }

        /// <summary>
        /// 効果音の再生
        /// </summary>
        /// <param name="playNo"></param>
        /// <param name="volume"></param>
        /// <param name="fadeTime"></param>
        /// <returns></returns>
        public YanesdkResult PlaySeFade(int playNo, float volume, int fadeTime, int loopTime)
        {
            if (playSeNo.Contains(playNo))
            {
                //このフレームで一度きり
                return YanesdkResult.NoError;
            }
            YanesdkResult result = SetLoopTime(playNo, loopTime);
            if (YanesdkResult.NoError != result)
            {
                return result;
            }
            result = SetVolume(playNo, GetAdjustVolume(volume));
            if (YanesdkResult.NoError != result)
            {
                return result;
            }

            // 再生中にダブって再生させたとしても、
            // 管理上は曲番号なので、どのチャンクで鳴っているかは把握出来ない
            if (!playSeNo.Contains(playNo))
            {
                playSeNo.Add(playNo);
            }

            if (SoundDisable)
            {
                return YanesdkResult.NoError;
            }
            else
            {
                return SoundLoader.PlaySE(playNo);
            }

        }

        /// <summary>
        /// 効果音の停止
        /// </summary>
        /// <param name="playNo"></param>
        /// <returns></returns>
        public YanesdkResult StopSe(int playNo)
        {
            return SoundLoader.Stop(playNo);
        }

        /// <summary>
        /// 効果音のフェード停止
        /// </summary>
        /// <param name="playNo"></param>
        /// <param name="fadeTime"></param>
        /// <returns></returns>
        public YanesdkResult StopSeFade(int playNo, int fadeTime)
        {
            return SoundLoader.StopFade(playNo, fadeTime);
        }

        /// <summary>
        /// マスターボリュームで調整した音量を取得する
        /// </summary>
        /// <param name="volume"></param>
        /// <returns></returns>
        private float GetAdjustVolume(float volume)
        {
            return volume * masterVolume;
        }

        /// <summary>
        /// ボリュームの設定（未実装）
        /// </summary>
        /// <param name="playNo"></param>
        /// <param name="voluem"></param>
        /// <returns></returns>
        private YanesdkResult SetVolume(int playNo, float volume)
        {
            Sound sound = SoundLoader.GetSound(playNo);
            if (null == sound)
            {
                return YanesdkResult.InvalidParameter;
            }

            sound.Volume = volume;

            return YanesdkResult.NoError;
        }

        /// <summary>
        /// 繰り返し
        /// </summary>
        /// <param name="playNo"></param>
        /// <param name="loopTime"></param>
        /// <returns></returns>
        private YanesdkResult SetLoopTime(int playNo, int loopTime)
        {
            Sound sound = SoundLoader.GetSound(playNo);
            if (null == sound)
            {
                return YanesdkResult.InvalidParameter;
            }
            sound.Loop = loopTime;
            return YanesdkResult.NoError;
        }
    }

    /// <summary>
    /// ボイスを管理する
    /// </summary>
    public class YaneVoiceManager : YaneSoundResourceManager, IVoiceResourceManager
    {
        #region 定数値
        public static readonly int INVALIDE_VOICE_NO = -1;

        #endregion
        #region メンバフィールド
        private int oldPlayVoiceNo = INVALIDE_VOICE_NO;
        private int playVoiceNo = INVALIDE_VOICE_NO;
        private float volume;
        private int[] sequenceVoiceNo;
        private int sequenceVoiceIndex;
        private float masterVolume = 1.0f;

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="SoundLoader"></param>
        public YaneVoiceManager(SoundLoader soundLoader)
            : base(soundLoader)
        {
        }

        /// <summary>
        /// 一連処理を行う
        /// </summary>
        public void Update()
        {
            if (sequenceVoiceNo != null && sequenceVoiceNo.Length > sequenceVoiceIndex)
            {
                // 再生終了
                if (!SoundLoader.GetSound(sequenceVoiceNo[sequenceVoiceIndex]).IsPlaying())
                {
                    // 次へ
                    if (sequenceVoiceIndex + 1 < sequenceVoiceNo.Length)
                    {
                        ++sequenceVoiceIndex;
                        PlayVoice(sequenceVoiceNo[sequenceVoiceIndex], volume);
                    }
                    else
                    {
                        // 一連処理完了
                        sequenceVoiceNo = null;
                        sequenceVoiceIndex = 0;
                    }
                }
            }
        }

        /// <summary>
        /// マスターボリュームの設定
        /// 設定後の次回の再生から適用される
        /// </summary>
        public float MasterVolume
        {
            get { return masterVolume; }
            set
            {
                masterVolume = value;
            }
        }

        /// <summary>
        /// 再生しているBGM番号
        /// </summary>
        public int PlayVoiceNo
        {
            get { return playVoiceNo; }
            set { playVoiceNo = value; }
        }

        /// <summary>
        /// ボイス無効フラグ
        /// </summary>
        public override bool SoundDisable
        {
            get
            {
                return base.SoundDisable;
            }
            set
            {
                if (SoundDisable != value)
                {
                    if (value)
                    {
                        // 新たに無効にする
                        if (INVALIDE_VOICE_NO != playVoiceNo)
                        {
                            SoundLoader.Stop(playVoiceNo);
                        }
                    }
                    else
                    {
                        // 新たに有効にする
                        if (INVALIDE_VOICE_NO != playVoiceNo)
                        {
                            SoundLoader.Play(playVoiceNo);
                        }
                    }
                    base.SoundDisable = value;
                }
            }
        }

        /// <summary>
        /// BGMが再生されているか
        /// ただし、フェード中も停止していると見なす
        /// </summary>
        public bool IsPalying
        {
            get { return playVoiceNo != INVALIDE_VOICE_NO && SoundLoader.IsPlaying(playVoiceNo); }
        }

        /// <summary>
        /// 一連ボイスを再生する
        /// </summary>
        /// <param name="playNo"></param>
        /// <param name="volume"></param>
        /// <returns></returns>
        public YanesdkResult PlayVoice(int[] playNo, float volume)
        {
            SetSequencePlay(playNo, volume);
            if (playNo.Length == 0)
            {
                return YanesdkResult.NoError;
            }

            return PlayVoice(playNo[sequenceVoiceIndex], volume);
        }

        /// <summary>
        /// 一連ボイス再生し、最初のボイスをフェードインで再生する
        /// </summary>
        /// <param name="playNo"></param>
        /// <param name="volume"></param>
        /// <param name="fadeTime"></param>
        /// <returns></returns>
        public YanesdkResult PlayVoiceFade(int[] playNo, float volume, int fadeTime)
        {
            SetSequencePlay(playNo, volume);
            if (playNo.Length == 0)
            {
                return YanesdkResult.NoError;
            }
            return PlayVoiceFade(playNo[sequenceVoiceIndex], volume, fadeTime);
        }

        /// <summary>
        /// 再生する
        /// </summary>
        /// <param name="playNo"></param>
        /// <param name="volume"></param>
        /// <returns></returns>
        public YanesdkResult PlayVoice(int playNo, float volume)
        {
            YanesdkResult result;
            SetVolume(playNo, volume);
            if (SoundDisable)
            {
                result = YanesdkResult.NoError;
            }
            else
            {
                result = SoundLoader.Play(playNo);
            }
            CheckPlayResult(result, playNo);
            CommonLogWriter.Write("PlayVoice - voice no:" + playNo + ", voice volume:" + volume.ToString());
            return result;
        }

        /// <summary>
        /// 再生する
        /// </summary>
        /// <param name="playNo"></param>
        /// <param name="volume"></param>
        /// <param name="fadeTime"></param>
        /// <returns></returns>
        public YanesdkResult PlayVoiceFade(int playNo, float volume, int fadeTime)
        {
            YanesdkResult result;

            SetVolume(playNo, volume);
            if (SoundDisable)
            {
                result = YanesdkResult.NoError;
            }
            else
            {
                if (PlayVoiceNo != INVALIDE_VOICE_NO)
                {
                    // クロスフェード
                    result = SoundLoader.PlayFade(playNo, fadeTime);
                }
                else
                {
                    result = SoundLoader.PlayFade(playNo, fadeTime);
                }
            }

            CheckPlayResult(result, playNo);
            CommonLogWriter.Write("PlayVoiceFade - voice no:" + playNo + ", voice volume:" + volume.ToString());
            return result;
        }

        /// <summary>
        /// 停止
        /// </summary>
        /// <returns></returns>
        public YanesdkResult StopVoice()
        {
            if (PlayVoiceNo == INVALIDE_VOICE_NO)
            {
                return YanesdkResult.NoError;
            }

            YanesdkResult result = SoundLoader.Stop(PlayVoiceNo);
            PlayVoiceNo = INVALIDE_VOICE_NO;
            return result;
        }

        /// <summary>
        /// フェード停止
        /// </summary>
        /// <param name="fadeTime"></param>
        /// <returns></returns>
        public YanesdkResult StopVoiceFade(int fadeTime)
        {
            if (PlayVoiceNo == INVALIDE_VOICE_NO)
            {
                return YanesdkResult.NoError;
            }

            YanesdkResult result = SoundLoader.StopFade(PlayVoiceNo, fadeTime);
            PlayVoiceNo = INVALIDE_VOICE_NO;
            return result;
        }

        /// <summary>
        /// 再生用要求後の結果をチェックし、成功していれば再生中のBGM番号をストアする
        /// </summary>
        /// <param name="result"></param>
        private void CheckPlayResult(YanesdkResult result, int playNo)
        {
            if (YanesdkResult.NoError == result || true)
            {
                OldVoiceNo = PlayVoiceNo;
                PlayVoiceNo = playNo;
            }
        }

        /// <summary>
        ///　停止要求後の結果をチェックし、停止された曲番号をストアする
        /// </summary>
        /// <param name="result"></param>
        private void CheckStopResult(YanesdkResult result)
        {
            if (YanesdkResult.NoError == result)
            {
                OldVoiceNo = PlayVoiceNo;
                PlayVoiceNo = INVALIDE_VOICE_NO;
            }
            else
            {
                // 失敗したということだけど...とりあえず止まっているとみなしたほうがいいか
                OldVoiceNo = PlayVoiceNo;
                PlayVoiceNo = INVALIDE_VOICE_NO;
            }
        }

        /// <summary>
        /// 一連再生設定をする
        /// </summary>
        /// <param name="playNo"></param>
        /// <param name="volume"></param>
        /// <returns></returns>
        private YanesdkResult SetSequencePlay(int[] playNo, float volume)
        {
            if (volume < 0 || playNo == null)
            {
                return YanesdkResult.InvalidParameter;
            }
            sequenceVoiceNo = playNo;
            this.volume = volume;
            sequenceVoiceIndex = 0;
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// マスターボリュームで調整した音量を取得する
        /// </summary>
        /// <param name="volume"></param>
        /// <returns></returns>
        private float GetAdjustVolume(float volume)
        {
            return volume * masterVolume;
        }

        /// <summary>
        /// ボリュームを設定する
        /// </summary>
        /// <param name="playNo"></param>
        /// <param name="volume"></param>
        /// <returns></returns>
        private YanesdkResult SetVolume(int playNo, float volume)
        {
            Sound sound = SoundLoader.GetSound(playNo);
            if (null == sound)
            {
                return YanesdkResult.InvalidParameter;
            }
            sound.Volume = GetAdjustVolume(volume);
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// 
        /// </summary>
        private int OldVoiceNo
        {
            get { return oldPlayVoiceNo; }
            set { oldPlayVoiceNo = value; }
        }


    }



}
