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

namespace Kyojin.Component.Scenario
{

    /// <summary>
    /// 背景表示コマンド
    /// </summary>
    public class KyojinBgCommandHandler : ICommandHandler
    {
        #region 定数値

        private static readonly int INVALID_BG_VALUE = -1;
        private static readonly int MIN_PARAM_NUM = 2;

        private static readonly int BG_NO = 1;
        private static readonly int EFFECT_NO = 2;
        private static readonly int EFFECT_SPEED = 3;
        private static readonly int WAIT_FLG = 4;

        private static readonly int INVALID_EFFECT_NO = -1;
        private static readonly int DEFAULT_EFFECT_SPEED = 1;
        private static readonly bool DEFAULT_WAIT_FLG = false;

        #endregion

        #region メンバフィールド

        private int execPosition;
        private CommandProcessor processor;
        private CommandState execState = CommandState.UN_EXECUTION;

        private int imgNo = INVALID_BG_VALUE;
        private int effectNo = INVALID_EFFECT_NO;
        private int effectSpeed;
        private bool waitFlg;

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public KyojinBgCommandHandler()
        {
        }

        /// <summary>
        /// このコマンドの状態
        /// </summary>
        public CommandState State
        {
            get { return execState; }
        }

        /// <summary>
        /// コマンド属性値の設定取得
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public YanesdkResult SetCommand(String command)
        {
            String[] tagParam = TagUtil.TagSplit(command);
            if (tagParam.Length < MIN_PARAM_NUM)
            {
                execState = CommandState.DONE;
                return YanesdkResult.InvalidParameter;
            }

            imgNo = TagUtil.GetPramInt(tagParam, BG_NO, INVALID_BG_VALUE);
            //effectNo = TagUtil.GetPramInt(tagParam, EFFECT_NO, INVALID_EFFECT_NO);
            // eNN 形式の文字列
            string effectNoStr = TagUtil.GetPram(tagParam, EFFECT_NO, null);
            if (null == effectNoStr)
            {
                effectNo = INVALID_EFFECT_NO;
            }
            else
            {

                try
                {
                    effectNo = Convert.ToInt32(effectNoStr.Substring(1));
                }
                catch (Exception)
                {
                    Debug.Assert(false, "無効な背景エフェクト番号が指定された：" + effectNoStr);
                    effectNo = 0;
                }

                // 去人たちではエフェクト番号が 1 から始まるため１減らす
                effectNo -= 1;
            }

            effectSpeed = TagUtil.GetPramInt(tagParam, EFFECT_SPEED, DEFAULT_EFFECT_SPEED);
            //waitFlg = TagUtil.GetPramBool(tagParam, WAIT_FLG, DEFAULT_WAIT_FLG);
            waitFlg = TagUtil.GetPramInt(tagParam, WAIT_FLG, DEFAULT_WAIT_FLG ? 1 : 0) == 1;

            return CheckPramValue();
        }

        /// <summary>
        /// 実行位置
        /// </summary>
        public int ExecPosition
        {
            set { execPosition = value; }
            get { return execPosition; }
        }

        /// <summary>
        /// コマンドの状況
        /// </summary>
        public CommandProcessor CommandProsser
        {
            get { return processor; }
            set { processor = value; }
        }

        /// <summary>
        /// コマンドを実行する
        /// </summary>
        /// <param name="model">モデル</param>
        /// <returns>実行結果を返却する</returns>
        public YanesdkResult DoCommand(IScenarioModel model)
        {
            switch (execState)
            {
                case CommandState.UN_EXECUTION:
                    return ExcecutionTag(model);
                case CommandState.EXECUTING:
                    return Excecuting(model);

                case CommandState.DONE:
                    break;
            }

            return YanesdkResult.NoError;
        }

        #region 非公開メソッド

        private YanesdkResult CheckPramValue()
        {
            if (INVALID_BG_VALUE == imgNo)
            {
                execState = CommandState.DONE;
                return YanesdkResult.InvalidParameter;
            }
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// 背景を表示する
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult ExcecutionTag(IScenarioModel model)
        {
            if (model.ShowTextCount < ExecPosition)
            {
                return YanesdkResult.NoError;
            }
            YanesdkResult result = YanesdkResult.NoError;


            model.BgImgMgr.BgImgNo = imgNo;
            model.BgImgMgr.SetEffect(effectNo, 0, TransBltter.PAHSE_MAX, effectSpeed);

            if (waitFlg)
            {
                model.ScenarioState.BgEffectWaitFlg = true;
                execState = CommandState.EXECUTING;
            }
            else
            {
                execState = CommandState.DONE;
            }

            return result;
        }

        /// <summary>
        /// 実行中
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult Excecuting(IScenarioModel model)
        {
            if (model.BgImgMgr.IsEffecting)
            {
                return YanesdkResult.NoError;
            }

            model.ScenarioState.BgEffectWaitFlg = false;

            execState = CommandState.DONE;
            return YanesdkResult.NoError;
        }

        #endregion
    }



    /// <summary>
    /// キャラクター表示コマンド
    /// </summary>
    public class KyojinCharaInCommandHandler : ICommandHandler
    {
        #region 定数値

        private static readonly int MIN_PARAM_NUM = 3;

        private static readonly int CHARACTER_ID = 1;
        private static readonly int PRESET_POS = 2;
        private static readonly int SLIDE_VALUE = 3;
        private static readonly int EFFECT_NO = 4;
        private static readonly int EFFECT_SPEED = 5;
        private static readonly int COLOR = 6;
        private static readonly int WAIT_FLG = 7;
        private static readonly int REPLACE_CHARACTER_ID = 8;

        private static readonly int INVALID_SLIDE_VALUE = 0;
        private static readonly int INVALID_EFFECT_NO = -1;
        private static readonly int DEFAULT_EFFECT_SPEED = 1;
        private static readonly String DEFAULT_COLOR = "FFFFFFFF";
        private static readonly bool DEFAULT_WAIT_FLG = false;

        #endregion

        #region メンバフィールド

        private int execPosition;
        private CommandProcessor processor;
        private CommandState execState = CommandState.UN_EXECUTION;

        private String characterId;
        private String presetPosition;
        private int slideOffsetValue;
        private int effectNo;
        private int effectSpeed;
        private String color;
        private bool waitFlg;
        private String replaceCharacterId;

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public KyojinCharaInCommandHandler()
        {
        }

        /// <summary>
        /// このコマンドの状態
        /// </summary>
        public CommandState State
        {
            get { return execState; }
        }

        /// <summary>
        /// コマンド属性値の設定取得
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public YanesdkResult SetCommand(String command)
        {
            String[] tagParam = TagUtil.TagSplit(command);
            if (tagParam.Length < MIN_PARAM_NUM)
            {
                execState = CommandState.DONE;
                return YanesdkResult.InvalidParameter;
            }

            characterId = TagUtil.GetPram(tagParam, CHARACTER_ID, null);
            presetPosition = TagUtil.GetPram(tagParam, PRESET_POS, null);
            slideOffsetValue = TagUtil.GetPramInt(tagParam, SLIDE_VALUE, INVALID_SLIDE_VALUE);

            //effectNo = TagUtil.GetPramInt(tagParam, EFFECT_NO, INVALID_EFFECT_NO);
            // eNN 形式の文字列
            string effectNoStr = TagUtil.GetPram(tagParam, EFFECT_NO, null);
            if (null == effectNoStr)
            {
                effectNo = INVALID_EFFECT_NO;
            }
            else
            {
                effectNo = Convert.ToInt32(effectNoStr.Substring(1)); ;
                // 去人たちではエフェクト番号が 1 から始まるため１減らす
                effectNo -= 1;
            }

            effectSpeed = TagUtil.GetPramInt(tagParam, EFFECT_SPEED, DEFAULT_EFFECT_SPEED);
            color = TagUtil.GetPram(tagParam, COLOR, DEFAULT_COLOR);
            //waitFlg = TagUtil.GetPramBool(tagParam, WAIT_FLG, DEFAULT_WAIT_FLG);
            waitFlg = TagUtil.GetPramInt(tagParam, WAIT_FLG, DEFAULT_WAIT_FLG ? 1 : 0) == 1;
            replaceCharacterId = TagUtil.GetPram(tagParam, REPLACE_CHARACTER_ID, null);

            return CheckPramValue();
        }

        /// <summary>
        /// 実行位置
        /// </summary>
        public int ExecPosition
        {
            set { execPosition = value; }
            get { return execPosition; }
        }

        /// <summary>
        /// コマンドの状況
        /// </summary>
        public CommandProcessor CommandProsser
        {
            get { return processor; }
            set { processor = value; }
        }

        /// <summary>
        /// コマンドを実行する
        /// </summary>
        /// <param name="model">モデル</param>
        /// <returns>実行結果を返却する</returns>
        public YanesdkResult DoCommand(IScenarioModel model)
        {
            switch (execState)
            {
                case CommandState.UN_EXECUTION:
                    return ExcecutionTag(model);
                case CommandState.EXECUTING:
                    return Executing(model);

                case CommandState.DONE:
                    break;
            }

            return YanesdkResult.NoError;
        }


        #region 非公開メソッド

        private YanesdkResult CheckPramValue()
        {
            if (null == characterId || null == presetPosition)
            {
                return YanesdkResult.InvalidParameter;
            }
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// キャラクターを表示する
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult ExcecutionTag(IScenarioModel model)
        {
            if (model.ShowTextCount < ExecPosition)
            {
                return YanesdkResult.NoError;
            }
            YanesdkResult result = YanesdkResult.NoError;

            Character character = null;
            Console.WriteLine("charain : new {0}, replace {1}", characterId, replaceCharacterId);
            if (null != replaceCharacterId)
            {
                // 置換
                // もし、新規キャラクターのほうが既存であれば初期化しておく
                Character newCharacter = model.CharacterImgMgr.GetCharacterImage(characterId) as Character;
                if (null != newCharacter)
                {
                    newCharacter.Reset();
                }
                character = model.CharacterImgMgr.GetCharacterImage(replaceCharacterId) as Character;
            }
            else
            {
                // 新規
                // このキャラクターが重複存在しないことを保証する
                character = model.CharacterImgMgr.GetCharacterImage(characterId) as Character;
                // フェードアウト中に取得したら、そのインスタンスを取得していることになるので、念のため初期化する
                if (null != character)
                {
                    character.Reset();
                }
                character = model.CharacterImgMgr.GetNewCharacterImage(characterId) as Character;
            }

            if (null == character)
            {
                Debug.Assert(null != character, "未定義のキャラクターID : " + characterId);
                return YanesdkResult.InvalidParameter;
            }

            // 位置
            character.PresetPos = Character.ToPresetPos(this.presetPosition);

            // エフェクト
            if (INVALID_EFFECT_NO != effectNo)
            {
                if (null != replaceCharacterId)
                {
                    if (IsCharaPoseChange(replaceCharacterId, characterId))
                    {
                        // ポーズ変更
                        character.SetEffectReplace(characterId, effectNo, effectSpeed, effectNo, effectSpeed);
                    }
                    else
                    {
                        // 表情変更
                        character.SetEffectReplace(characterId, 22, effectSpeed, 23, calcAlphaStep(effectSpeed));
                    }
                }
                else
                {
                    character.SetEffect(effectNo, 0, TransBltter.PAHSE_MAX, effectSpeed);
                }
            }
            // キャラクターカラー
            character.Color = YanesdkUtil.ToColor4ub(color);
            // スライド
            if (INVALID_SLIDE_VALUE != slideOffsetValue)
            {
                character.SetSlide(slideOffsetValue, 1);
            }

            if (waitFlg)
            {
                model.ScenarioState.CharacterEffectWaitFlg = true;
                execState = CommandState.EXECUTING;
            }
            else
            {
                execState = CommandState.DONE;
            }

            return result;
        }

        /// <summary>
        /// キャラクタ表示中処理
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult Executing(IScenarioModel model)
        {
            Character[] characters = ((YaneCharacterManager)model.CharacterImgMgr).CharacterContainer;
            foreach (Character chara in characters)
            {
                if (chara.IsEffecting)
                {
                    return YanesdkResult.NoError;
                }
            }
            model.ScenarioState.CharacterEffectWaitFlg = false;
            execState = CommandState.DONE;
            return YanesdkResult.NoError;
        }

        /// IDを認識しポーズが変更されたかを返却する
        /// キャラクター識別子(a-z,A-Z)＋キャラクターポーズ識別子(1-9)１文字＋表情識別子(1-9)２文字
        private static bool IsCharaPoseChange(string charNow, string charPre)
        {
            // キャラが違うのであれば、すべて違うはず
            if (GetCharaIDName(charNow) != GetCharaIDName(charPre))
            {
                return true;
            }
            string nowNum = GetCharaIDNumber(charNow);
            string preNum = GetCharaIDNumber(charPre);

            // ポーズ識別子が別であるか？
            return nowNum.ToCharArray()[0] != preNum.ToCharArray()[0];
        }

        /// キャラクターIDよりID番号部分を返却する
        private static string GetCharaIDNumber(string charId)
        {
            StringBuilder numBuffer = new StringBuilder();
            foreach (char c in charId.ToCharArray())
            {
                if (!char.IsNumber(c))
                {
                    continue;
                }
                numBuffer.Append(c);
            }
            return numBuffer.ToString();
        }

        /// キャラクターIDよりID識別子部分を返却する
        private static string GetCharaIDName(string charId)
        {
            StringBuilder numBuffer = new StringBuilder();
            foreach (char c in charId.ToCharArray())
            {
                if (char.IsNumber(c))
                {
                    break;
                }
                numBuffer.Append(c);
            }
            return numBuffer.ToString();
        }


        /// 指定したステップで、RootCounterを動作させたときに、何回で終端に達するかを返却
        private static int calcAlphaStep(int step)
        {
            if (0 == step)
            {
                step = 1;
            }
            int result;
            if (0 > step)
            {
                result = (255 * (step + 1)) + step;
                return result;
            }
            else
            {
                result = 255 / step;
                return (255 % step) == 0 ? result : result + 1;
            }
        }

        #endregion
    }


    /// <summary>
    /// キャラクター表示コマンド
    /// </summary>
    public class KyojinCharaOutCommandHandler : ICommandHandler
    {
        #region 定数値

        private static readonly int MIN_PARAM_NUM = 3;

        private static readonly int CHARACTER_ID = 1;
        private static readonly int SLIDE_VALUE = 2;
        private static readonly int EFFECT_NO = 3;
        private static readonly int EFFECT_SPEED = 4;
        private static readonly int COLOR = 5;
        private static readonly int WAIT_FLG = 6;

        private static readonly int INVALID_SLIDE_VALUE = 0;
        private static readonly int INVALID_EFFECT_NO = -1;
        private static readonly int DEFAULT_EFFECT_SPEED = 1;
        private static readonly String DEFAULT_COLOR = "FFFFFFFF";
        private static readonly bool DEFAULT_WAIT_FLG = false;

        #endregion

        #region メンバフィールド

        private int execPosition;
        private CommandProcessor processor;
        private CommandState execState = CommandState.UN_EXECUTION;

        private String characterId;
        private int slideOffsetValue;
        private int effectNo;
        private int effectSpeed;
        private String color;
        private bool waitFlg;

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public KyojinCharaOutCommandHandler()
        {

        }

        /// <summary>
        /// このコマンドの状態
        /// </summary>
        public CommandState State
        {
            get { return execState; }
        }

        /// <summary>
        /// コマンド属性値の設定取得
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public YanesdkResult SetCommand(String command)
        {
            String[] tagParam = TagUtil.TagSplit(command);
            if (tagParam.Length < MIN_PARAM_NUM)
            {
                Debug.Assert(false);
                execState = CommandState.DONE;
                return YanesdkResult.InvalidParameter;
            }

            characterId = TagUtil.GetPram(tagParam, CHARACTER_ID, null);
            slideOffsetValue = TagUtil.GetPramInt(tagParam, SLIDE_VALUE, INVALID_SLIDE_VALUE);
            //effectNo = TagUtil.GetPramInt(tagParam, EFFECT_NO, INVALID_EFFECT_NO);
            // eNN 形式の文字列
            string effectNoStr = TagUtil.GetPram(tagParam, EFFECT_NO, null);
            if (null == effectNoStr)
            {
                effectNo = INVALID_EFFECT_NO;
            }
            else
            {
                effectNo = Convert.ToInt32(effectNoStr.Substring(1));
                // 去人たちではエフェクト番号が 1 から始まるため１減らす
                effectNo -= 1;
            }

            effectSpeed = TagUtil.GetPramInt(tagParam, EFFECT_SPEED, DEFAULT_EFFECT_SPEED);
            color = TagUtil.GetPram(tagParam, COLOR, DEFAULT_COLOR);

            //waitFlg = TagUtil.GetPramBool(tagParam, WAIT_FLG, DEFAULT_WAIT_FLG);
            waitFlg = TagUtil.GetPramInt(tagParam, WAIT_FLG, DEFAULT_WAIT_FLG ? 1 : 0) == 1;

            return CheckPramValue();
        }

        /// <summary>
        /// 実行位置
        /// </summary>
        public int ExecPosition
        {
            set { execPosition = value; }
            get { return execPosition; }
        }

        /// <summary>
        /// コマンドの状況
        /// </summary>
        public CommandProcessor CommandProsser
        {
            get { return processor; }
            set { processor = value; }
        }

        /// <summary>
        /// コマンドを実行する
        /// </summary>
        /// <param name="model">モデル</param>
        /// <returns>実行結果を返却する</returns>
        public YanesdkResult DoCommand(IScenarioModel model)
        {
            switch (execState)
            {
                case CommandState.UN_EXECUTION:
                    return ExcecutionTag(model);
                case CommandState.EXECUTING:
                    return Executing(model);

                case CommandState.DONE:
                    break;
            }

            return YanesdkResult.NoError;
        }


        #region 非公開メソッド

        private YanesdkResult CheckPramValue()
        {
            if (null == characterId)
            {
                return YanesdkResult.InvalidParameter;
            }
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// キャラクターを表示する
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult ExcecutionTag(IScenarioModel model)
        {
            if (model.ShowTextCount < ExecPosition)
            {
                return YanesdkResult.NoError;
            }
            YanesdkResult result = YanesdkResult.NoError;

            Character character = model.CharacterImgMgr.GetCharacterImage(characterId) as Character;

            Console.WriteLine("charaout : {0}", characterId);
            if (null == character)
            {
                Debug.Assert(false, "キャラクターが取得できない" + characterId);
                return YanesdkResult.PreconditionError;
            }

            // エフェクト
            if (INVALID_EFFECT_NO != effectNo)
            {
                character.SetEffect(effectNo, TransBltter.PAHSE_MAX, 0, effectSpeed);
            }
            else
            {
                // 消える
                character.Reset();
            }
            // キャラクターカラー
            character.Color = YanesdkUtil.ToColor4ub(color);
            // スライド
            if (INVALID_SLIDE_VALUE != slideOffsetValue)
            {
                character.SetSlide(slideOffsetValue, 1);
            }

            if (waitFlg)
            {
                model.ScenarioState.CharacterEffectWaitFlg = true;
                execState = CommandState.EXECUTING;
            }
            else
            {
                execState = CommandState.DONE;
            }

            return result;
        }

        /// <summary>
        /// キャラクタ表示中処理
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult Executing(IScenarioModel model)
        {
            Character[] characters = ((YaneCharacterManager)model.CharacterImgMgr).CharacterContainer;
            foreach (Character chara in characters)
            {
                if (chara.IsEffecting)
                {
                    return YanesdkResult.NoError;
                }
            }
            model.ScenarioState.CharacterEffectWaitFlg = false;
            execState = CommandState.DONE;
            return YanesdkResult.NoError;
        }

        #endregion
    }


    /// <summary>
    /// ボイス再生コマンド
    /// </summary>
    public class KyojinVoicePlayCommandHandler : ICommandHandler
    {
        #region 定数値

        private static readonly int INVALID_VOICE_VALUE = -1;
        private static readonly int MIN_PARAM_NUM = 2;
        private static readonly int VOICE_NO_INDEX = 1;
        private static readonly int VOICE_VOLUME = 2;
        private static readonly int VOICE_FADE_TIME = 3;

        #endregion


        #region メンバフィールド

        private int execPosition;
        private CommandProcessor processor;
        private CommandState execState = CommandState.UN_EXECUTION;
        private string voiceID = null;
        private int voiceNo = INVALID_VOICE_VALUE;
        private float voiceVolume = 1.0f;
        private int fadeTime = INVALID_VOICE_VALUE;
        private Dictionary<string, int> voiceNoMap;

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public KyojinVoicePlayCommandHandler(Dictionary<string, int> voiceNoMap)
        {
            this.voiceNoMap = voiceNoMap;
        }

        /// <summary>
        /// 去人たちではボイス指定をIDによって行っている。
        /// 従ってIDとボイスNOとのマッピングを行う必要がある。
        /// そのマッピングに使用するID -> VOICE_NO のマップ 
        /// </summary>
        public Dictionary<string, int> VoiceNoMap
        {
            get { return voiceNoMap; }
            set { voiceNoMap = value; }
        }

        /// <summary>
        /// このコマンドの状態
        /// </summary>
        public CommandState State
        {
            get { return execState; }
        }

        /// <summary>
        /// コマンド属性値の設定取得
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public YanesdkResult SetCommand(String command)
        {
            String[] tagParam = TagUtil.TagSplit(command);
            if (tagParam.Length < MIN_PARAM_NUM)
            {
                execState = CommandState.DONE;
                return YanesdkResult.InvalidParameter;
            }

            voiceID = TagUtil.GetPram(tagParam, VOICE_NO_INDEX, null);
            if (null == voiceID || !VoiceNoMap.ContainsKey(voiceID))
            {
                execState = CommandState.DONE;
                Yamalib.Logger.CommonLogWriter.Write("ScriptTagWarning - 未定義のボイスID:" + voiceID);
                return YanesdkResult.InvalidParameter;
            }

            voiceNo = VoiceNoMap[voiceID];
            voiceVolume = TagUtil.GetPramInt(tagParam, VOICE_VOLUME, Sdl.SDL.MIX_MAX_VOLUME) / (float)Sdl.SDL.MIX_MAX_VOLUME; ;
            fadeTime = TagUtil.GetPramInt(tagParam, VOICE_FADE_TIME, 0);
            if (0 == fadeTime)
            {
                fadeTime = INVALID_VOICE_VALUE;
            }

            return CheckPramValue();
        }

        /// <summary>
        /// 実行位置の設定取得
        /// </summary>
        public int ExecPosition
        {
            set { execPosition = value; }
            get { return execPosition; }
        }

        /// <summary>
        /// コマンド処理を追加する
        /// </summary>
        public CommandProcessor CommandProsser
        {
            get { return processor; }
            set { processor = value; }
        }

        /// <summary>
        /// コマンドを実行する
        /// </summary>
        /// <param name="model">モデル</param>
        /// <returns>実行結果を返却する</returns>
        public YanesdkResult DoCommand(IScenarioModel model)
        {
            switch (execState)
            {
                case CommandState.UN_EXECUTION:
                    return ExcecutionTag(model);
                case CommandState.EXECUTING:
                    break;

                case CommandState.DONE:
                    break;
            }

            return YanesdkResult.NoError;
        }

        #region 非公開メソッド

        private YanesdkResult CheckPramValue()
        {
            if (voiceNo == INVALID_VOICE_VALUE)
            {
                execState = CommandState.DONE;
                return YanesdkResult.InvalidParameter;
            }
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// SEを再生する
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult ExcecutionTag(IScenarioModel model)
        {
            // 未実行
            // ボイスは改行時に行われてはいけない
            // そのため +1 することで再生位置がずれるのを補正している
            // あんまし良くない実装
            if (model.ShowTextCount < ExecPosition + 1)
            {
                return YanesdkResult.NoError;
            }
            YanesdkResult result;
            if (INVALID_VOICE_VALUE == fadeTime)
            {
                result = model.VoiceMgr.PlayVoice(voiceNo, voiceVolume);
            }
            else
            {
                result = model.VoiceMgr.PlayVoiceFade(voiceNo, voiceVolume, fadeTime);
            }

            execState = CommandState.DONE;

            if (YanesdkResult.NoError != result)
            {
                Yamalib.Logger.CommonLogWriter.Write("VoicePlayError : " + result.ToString());
            }

            return result;
        }

        #endregion
    }

    /// <summary>
    /// 別シーンへの遷移コマンド
    /// </summary>
    public class KyojinNextSceneCommandHandler : ICommandHandler
    {
        #region 定数値

        private static readonly int MIN_PARAM_NUM = 1;
        private static readonly int CHARACTER_ID = 1;

        #endregion

        #region メンバフィールド

        private int execPosition;
        private CommandProcessor processor;
        private CommandState execState = CommandState.UN_EXECUTION;

        private string sceneId;

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public KyojinNextSceneCommandHandler()
        {

        }

        /// <summary>
        /// このコマンドの状態
        /// </summary>
        public CommandState State
        {
            get { return execState; }
        }

        /// <summary>
        /// 設定されているシーンIDを返却する
        /// </summary>
        public string SceneId
        {
            get { return sceneId; }
            set { sceneId = value; }
        }

        /// <summary>
        /// コマンド属性値の設定取得
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public YanesdkResult SetCommand(String command)
        {
            String[] tagParam = TagUtil.TagSplit(command);
            if (tagParam.Length < MIN_PARAM_NUM)
            {
                execState = CommandState.DONE;
                return YanesdkResult.InvalidParameter;
            }

            SceneId = TagUtil.GetPram(tagParam, CHARACTER_ID, null);

            return CheckPramValue();
        }

        /// <summary>
        /// 実行位置
        /// </summary>
        public int ExecPosition
        {
            set { execPosition = value; }
            get { return execPosition; }
        }

        /// <summary>
        /// コマンドの状況
        /// </summary>
        public CommandProcessor CommandProsser
        {
            get { return processor; }
            set { processor = value; }
        }

        /// <summary>
        /// コマンドを実行する
        /// </summary>
        /// <param name="model">モデル</param>
        /// <returns>実行結果を返却する</returns>
        public YanesdkResult DoCommand(IScenarioModel model)
        {
            switch (execState)
            {
                case CommandState.UN_EXECUTION:
                    return ExcecutionTag(model);
                case CommandState.EXECUTING:
                    return Executing(model);

                case CommandState.DONE:
                    break;
            }

            return YanesdkResult.NoError;
        }


        #region 非公開メソッド

        private YanesdkResult CheckPramValue()
        {
            if (null == SceneId)
            {
                return YanesdkResult.InvalidParameter;
            }
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// キャラクターを表示する
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult ExcecutionTag(IScenarioModel model)
        {
            if (model.ShowTextCount < ExecPosition)
            {
                return YanesdkResult.NoError;
            }
            YanesdkResult result = YanesdkResult.NoError;
            if (CommandProsser != null)
            {
                result = CommandProsser(this, model);
            }
            execState = CommandState.DONE;

            return result;
        }

        /// <summary>
        /// キャラクタ表示中処理
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult Executing(IScenarioModel model)
        {
            return YanesdkResult.NoError;
        }

        #endregion
    }


    /// <summary>
    /// 別シーンへの遷移コマンド
    /// </summary>
    public class SelectCommandHandler : ICommandHandler
    {
        #region 定数値

        private static readonly int MIN_PARAM_NUM = 2;
        private static readonly int CHARACTER_ID = 1;
        private static readonly int SCENE_ID = 2;

        #endregion

        #region メンバフィールド

        private int execPosition;
        private CommandProcessor processor;
        private CommandState execState = CommandState.UN_EXECUTION;

        private string sceneId;
        private string choices;

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public SelectCommandHandler()
        {

        }

        /// <summary>
        /// このコマンドの状態
        /// </summary>
        public CommandState State
        {
            get { return execState; }
        }

        /// <summary>
        /// 設定されているシーンIDを返却する
        /// </summary>
        public string SceneId
        {
            get { return sceneId; }
            set { sceneId = value; }
        }

        /// <summary>
        /// 選択枝の文字列
        /// </summary>
        public string Choices
        {
            get { return choices; }
            set { choices = value; }
        }

        /// <summary>
        /// コマンド属性値の設定取得
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public YanesdkResult SetCommand(String command)
        {
            String[] tagParam = TagUtil.TagSplit(command);
            if (tagParam.Length < MIN_PARAM_NUM)
            {
                execState = CommandState.DONE;
                return YanesdkResult.InvalidParameter;
            }

            SceneId = TagUtil.GetPram(tagParam, CHARACTER_ID, null);
            Choices = TagUtil.GetPram(tagParam, SCENE_ID, null);

            return CheckPramValue();
        }

        /// <summary>
        /// 実行位置
        /// </summary>
        public int ExecPosition
        {
            set { execPosition = value; }
            get { return execPosition; }
        }

        /// <summary>
        /// コマンドの状況
        /// </summary>
        public CommandProcessor CommandProsser
        {
            get { return processor; }
            set { processor = value; }
        }

        /// <summary>
        /// コマンドを実行する
        /// </summary>
        /// <param name="model">モデル</param>
        /// <returns>実行結果を返却する</returns>
        public YanesdkResult DoCommand(IScenarioModel model)
        {
            switch (execState)
            {
                case CommandState.UN_EXECUTION:
                    return ExcecutionTag(model);
                case CommandState.EXECUTING:
                    return Executing(model);

                case CommandState.DONE:
                    break;
            }

            return YanesdkResult.NoError;
        }


        #region 非公開メソッド

        private YanesdkResult CheckPramValue()
        {
            if (null == SceneId || Choices == null)
            {
                return YanesdkResult.InvalidParameter;
            }
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// キャラクターを表示する
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult ExcecutionTag(IScenarioModel model)
        {
            if (model.ShowTextCount < ExecPosition)
            {
                return YanesdkResult.NoError;
            }
            YanesdkResult result = YanesdkResult.NoError;
            if (CommandProsser != null)
            {
                result = CommandProsser(this, model);
            }
            execState = CommandState.DONE;

            return result;
        }

        /// <summary>
        /// キャラクタ表示中処理
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult Executing(IScenarioModel model)
        {
            return YanesdkResult.NoError;
        }

        #endregion
    }



}
