using System;
using System.Collections.Generic;
using System.Text;
using Yanesdk.Timer;
using Yanesdk.Ytl;
using Yamalib.Yanesdkext.Draw;
using Yamalib.Model;
using Yamalib.Util;
using Yanesdk.System;

namespace Yamalib.Scenario.YaneScript
{
    #region コマンドハンドラクラス

    /// <summary>
    /// YaneScrpt形式のタグを定義する
    /// </summary>
    public static class TagDefinition
    {
        public static readonly String TAG_JUMP_SCENE = "jump_scene";
        public static readonly String TAG_READ_STOP = "readstop";
        public static readonly String TAG_BGM_PLAY = "bgm_play";
        public static readonly String TAG_BGM_STOP = "bgm_stop";
        public static readonly String TAG_BG = "bg";
        public static readonly String TAG_CHARA_IN = "charain";
        public static readonly String TAG_CHARA_OUT = "charaout";
        public static readonly String TAG_SE_PLAY = "se";
        public static readonly String TAG_SE_STOP = "se_stop";
        public static readonly String TAG_VOICE = "voice";
        public static readonly String TAG_VOICE_WAIT = "voicewait";

        /// <summary>
        /// Yane形式のスクリプトで使うデフォルトのコマンドハンドラ
        /// </summary>
        /// <returns></returns>
        public static Dictionary<string, CommandHandlerCreator> GetFactories()
        {
            Dictionary<string, CommandHandlerCreator> factories = new Dictionary<string, CommandHandlerCreator>();

            // 読み止まりのコマンド
            factories[TAG_READ_STOP] = delegate()
            {
                return new ReadStopCommandHandler();
            };

            //BGM_Playのコマンド
            factories[TAG_BGM_PLAY] = delegate()
            {
                return new BgmPlayCommandHandler();
            };

            //BGM_SOPのコマンド
            factories[TAG_BGM_STOP] = delegate()
            {
                return new BgmStopCommandHandler();
            };

            // 背景コマンド
            factories[TAG_BG] = delegate()
            {
                return new BgCommandHandler();
            };

            //TAG_CHARA_INのコマンド
            factories[TAG_CHARA_IN] = delegate()
            {
                return new CharaInCommandHandler();
            };

            //TAG_CHARA_OUTのコマンド
            factories[TAG_CHARA_OUT] = delegate()
            {
                return new CharaOutCommandHandler();
            };

            // SE 再生コマンド
            factories[TAG_SE_PLAY] = delegate()
            {
                return new SePlayCommandHandler();
            };

            // SE 停止コマンド
            factories[TAG_SE_STOP] = delegate()
            {
                return new SeStopCommandHandler();
            };

            // ボイスウェイトコマンド
            factories[TAG_VOICE_WAIT] = delegate()
            {
                return new VoiceWaitCommandHandler();
            };

            //TODO: 必要なものを追加していくこと

            return factories;
        }
    }

    /// <summary>
    /// タグ処理に使うと便利なユーティリティクラス
    /// </summary>
    public static class TagUtil
    {
        /// <summary>
        /// タグのパラメータを分割する文字
        /// </summary>
        public static readonly char TAG_SEPARATER = ',';

        /// <summary>
        /// タグ文字列を指定されたセパレータで分割する
        /// </summary>
        /// <param name="commandStr"></param>
        /// <returns></returns>
        public static String[] TagSplit(String commandStr)
        {
            //Console.WriteLine("split command : {0}", commandStr );
            if (null == commandStr)
            {
                return new String[0];
            }
            String[] resultStr = commandStr.Split(TAG_SEPARATER);
            for (int i = 0; i < resultStr.Length; i++)
            {
                resultStr[i] = resultStr[i].ToLower().Trim('"', ' ');
            }
            return resultStr;
        }

        /// <summary>
        /// 対象の文字列配列の想定する arrayIndexNo から値を取り出す。
        /// もし、配列がそれより短ければ、iferr で指定した値を返却する
        /// </summary>
        /// <param name="splitCommand"></param>
        /// <param name="arrayIndexNo"></param>
        /// <param name="iferr"></param>
        /// <returns></returns>
        public static String GetPram(String[] splitCommand, int arrayIndexNo, String iferr)
        {

            if (null == splitCommand || arrayIndexNo >= splitCommand.Length)
            {
                return iferr;
            }
            try
            {
                return splitCommand[arrayIndexNo];
            }
            catch (FormatException e)
            {
                Console.WriteLine("TAG PRAM:{0}", e);
                Console.WriteLine("TAG PRAM:{0}", e.StackTrace);
                return iferr;
            }
        }

        /// <summary>
        /// 対象の文字列配列の想定する arrayIndexNo から値を取り出す。
        /// もし、配列がそれより短ければ、iferr で指定した値を返却する
        /// </summary>
        /// <param name="splitCommand"></param>
        /// <param name="arrayIndexNo"></param>
        /// <param name="iferr"></param>
        /// <returns></returns>
        public static int GetPramInt(String[] splitCommand, int arrayIndexNo, int iferr)
        {
            if (null == splitCommand || arrayIndexNo >= splitCommand.Length)
            {
                return iferr;
            }
            try
            {
                return Convert.ToInt32(splitCommand[arrayIndexNo]);
            }
            catch (FormatException e)
            {
                Console.WriteLine("TAG PRAM:{0}", e);
                Console.WriteLine("TAG PRAM:{0}", e.StackTrace);
                return iferr;
            }
        }

        public static bool GetPramBool(String[] splitCommand, int arrayIndexNo, bool iferr)
        {
            if (null == splitCommand || arrayIndexNo >= splitCommand.Length)
            {
                return iferr;
            }
            try
            {
                return Convert.ToBoolean(splitCommand[arrayIndexNo]);
            }
            catch (FormatException e)
            {
                // 便宜的に0,1も許可する
                Console.WriteLine("TAG PRAM:{0}", e);
                Console.WriteLine("TAG PRAM:{0}", e.StackTrace);
                int value = GetPramInt(splitCommand, arrayIndexNo, iferr ? 1 : 0);
                return 1 == value;
            }
        }
    }

    /// <summary>
    /// タグハンドラファクトリ
    /// </summary>
    public class YaneCommandHandlerFactory : ICommandHandlerFactory
    {

        #region メンバフィールド
        private Dictionary<String, CommandHandlerCreator> factories;
        #endregion
        public void SetFactories(Dictionary<String, CommandHandlerCreator> factories)
        {
            this.factories = factories;
        }
        public Dictionary<String, CommandHandlerCreator> GetFactories()
        {
            return factories;
        }

        public ICommandHandler Create(String commandId)
        {
            if (factories == null)
            {
                return NullCommandHandler.Instance;
            }
            String tagId = GetTagId(commandId);
            if (factories.ContainsKey(tagId))
            {
                return factories[tagId]();
            }
            return NullCommandHandler.Instance;
        }

        /// <summary>
        /// コマンド文字列から、先頭のタグIDとなるモノを取り出す
        /// </summary>
        /// <param name="commadStr"></param>
        /// <returns></returns>
        private String GetTagId(String commadStr)
        {
            String[] tagParam = TagUtil.TagSplit(commadStr);
            if (null == tagParam || 0 == tagParam.Length)
            {
                return null;
            }
            return tagParam[0].ToLower();
        }

    }

    /// <summary>
    /// 読み止まりコマンド
    /// </summary>
    public class ReadStopCommandHandler : ICommandHandler
    {
        #region 定数値

        private static readonly int INVALID_WAIT_TIME = -1;

        #endregion


        #region メンバフィールド

        private int execPosition;
        private CommandProcessor processor;
        private CommandState execState = CommandState.UN_EXECUTION;
        private readonly FixTimer timer = new FixTimer();
        private int readWaitTime = INVALID_WAIT_TIME;

        #endregion

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

        }

        /// <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 (1 < tagParam.Length)
            {
                // これは <readstop,millsec> 指定時間停止
                readWaitTime = Convert.ToInt32(tagParam[1]);
            }

            return YanesdkResult.NoError;
        }

        public int ExecPosition
        {
            set { execPosition = value; }
            get { return execPosition; }
        }

        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 ExcecutingTag(model);

                case CommandState.DONE:
                    break;
            }

            return YanesdkResult.NoError;
        }

        #region 非公開メソッド

        private YanesdkResult ExcecutionTag(IScenarioModel model)
        {
            // 未実行
            if (model.ShowTextCount >= ExecPosition)
            {
                //スキップ中なら何もしない
                if (model.ScenarioState.ReadSkipFlg)
                {
                    execState = CommandState.DONE;
                    return YanesdkResult.NoError;
                }

                // テキスト停止
                model.ScenarioState.ReadStopFlg = true;
                if (INVALID_WAIT_TIME != readWaitTime)
                {
                    timer.Reset();
                    execState = CommandState.EXECUTING;
                }
                else
                {
                    execState = CommandState.DONE;
                }

                if (null != processor)
                {
                    processor(this, model);
                }
            }
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// readstop,waittime のチェック
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult ExcecutingTag(IScenarioModel model)
        {
            timer.Update();
            if (readWaitTime <= timer.Time)
            {
                model.ScenarioState.ReadStopFlg = false;
                execState = CommandState.DONE;
            }
            return YanesdkResult.NoError;
        }

        #endregion

    }


    /// <summary>
    /// BGM再生コマンド
    /// </summary>
    public class BgmPlayCommandHandler : ICommandHandler
    {
        #region 定数値

        private static readonly int INVALID_BGM_VALUE = -1;
        private static readonly float INVALID_VOLUME_VALUE = float.NaN;
        private static readonly int MIN_PARAM_NUM = 2;
        private static readonly int BGM_NO_INDEX = 1;
        private static readonly int BGM_VOLUME = 2;
        private static readonly int BGM_FADE_TIME = 3;

        #endregion


        #region メンバフィールド

        private int execPosition;
        private CommandProcessor processor;
        private CommandState execState = CommandState.UN_EXECUTION;
        private int bgmNo = INVALID_BGM_VALUE;
        private float bgmVolume = INVALID_VOLUME_VALUE;
        private int fadeTime = INVALID_BGM_VALUE;

        #endregion

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

        }

        /// <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;
            }

            bgmNo = TagUtil.GetPramInt(tagParam, BGM_NO_INDEX, INVALID_BGM_VALUE);
            bgmVolume = TagUtil.GetPramInt(tagParam, BGM_VOLUME, Sdl.SDL.MIX_MAX_VOLUME) / (float)Sdl.SDL.MIX_MAX_VOLUME;
            fadeTime = TagUtil.GetPramInt(tagParam, BGM_FADE_TIME, INVALID_BGM_VALUE);

            return CheckPramValue();
        }

        public int ExecPosition
        {
            set { execPosition = value; }
            get { return execPosition; }
        }

        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 (bgmNo == INVALID_BGM_VALUE)
            {
                execState = CommandState.DONE;
                return YanesdkResult.InvalidParameter;
            }
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// BGMを再生する
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult ExcecutionTag(IScenarioModel model)
        {
            // 未実行
            if (model.ShowTextCount < ExecPosition)
            {
                return YanesdkResult.NoError;
            }
            YanesdkResult result;
            if (INVALID_BGM_VALUE == fadeTime)
            {
                result = model.BgmMgr.PlayBgm(bgmNo, bgmVolume);
            }
            else
            {
                result = model.BgmMgr.PlayBgmFade(bgmNo, bgmVolume, fadeTime);
            }

            execState = CommandState.DONE;

            return result;
        }

        #endregion
    }

    /// <summary>
    /// BGM再生コマンド
    /// </summary>
    public class BgmStopCommandHandler : ICommandHandler
    {
        #region 定数値

        private static readonly int INVALID_BGM_VALUE = -1;
        private static readonly int MIN_PARAM_NUM = 1;
        private static readonly int BGM_FADE_TIME = 1;

        #endregion

        #region メンバフィールド

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

        #endregion

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

        }

        /// <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;
            }

            fadeTime = TagUtil.GetPramInt(tagParam, BGM_FADE_TIME, INVALID_BGM_VALUE);

            return CheckPramValue();
        }

        public int ExecPosition
        {
            set { execPosition = value; }
            get { return execPosition; }
        }

        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()
        {
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// BGMを停止する
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult ExcecutionTag(IScenarioModel model)
        {
            if (model.ShowTextCount < ExecPosition)
            {
                return YanesdkResult.NoError;
            }
            YanesdkResult result;
            if (INVALID_BGM_VALUE == fadeTime)
            {
                result = model.BgmMgr.StopBgm();
            }
            else
            {
                result = model.BgmMgr.StopBgmFade(fadeTime);
            }

            execState = CommandState.DONE;

            return result;
        }

        #endregion
    }

    /// <summary>
    /// 背景表示コマンド
    /// </summary>
    public class BgCommandHandler : 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 oldImgNo = INVALID_BG_VALUE;
        private int imgNo = INVALID_BG_VALUE;
        private int effectNo = INVALID_EFFECT_NO;
        private int effectSpeed;
        private bool waitFlg;

        #endregion

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

        }

        /// <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;
            }

            oldImgNo = imgNo;
            imgNo = TagUtil.GetPramInt(tagParam, BG_NO, INVALID_BG_VALUE);
            effectNo = TagUtil.GetPramInt(tagParam, EFFECT_NO, INVALID_EFFECT_NO);
            effectSpeed = TagUtil.GetPramInt(tagParam, EFFECT_SPEED, DEFAULT_EFFECT_SPEED);
            waitFlg = TagUtil.GetPramBool(tagParam, WAIT_FLG, DEFAULT_WAIT_FLG);

            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 CharaInCommandHandler : 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 CharaInCommandHandler()
        {

        }

        /// <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);
            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);
            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 = model.CharacterImgMgr.GetCharacterImage(characterId) as Character;

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

            // エフェクト
            if (INVALID_EFFECT_NO != effectNo)
            {
                if (null != replaceCharacterId)
                {
                    character.SetEffectReplace(characterId, effectNo, 0, TransBltter.PAHSE_MAX, 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;
        }

        #endregion
    }


    /// <summary>
    /// キャラクター表示コマンド
    /// </summary>
    public class CharaOutCommandHandler : 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 CharaOutCommandHandler()
        {

        }

        /// <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);
            slideOffsetValue = TagUtil.GetPramInt(tagParam, SLIDE_VALUE, INVALID_SLIDE_VALUE);
            effectNo = TagUtil.GetPramInt(tagParam, EFFECT_NO, INVALID_EFFECT_NO);
            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);

            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;
            // エフェクト
            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>
    /// SE再生コマンド
    /// </summary>
    public class SePlayCommandHandler : ICommandHandler
    {
        #region 定数値

        private static readonly int INVALID_SE_VALUE = -1;
        private static readonly int MIN_PARAM_NUM = 2;
        private static readonly int SE_NO_INDEX = 1;
        private static readonly int SE_VOLUME = 2;
        private static readonly int SE_LOOP_TIME = 3;
        private static readonly int SE_FADE_TIME = 4;

        #endregion


        #region メンバフィールド

        private int execPosition;
        private CommandProcessor processor;
        private CommandState execState = CommandState.UN_EXECUTION;
        private int seNo = INVALID_SE_VALUE;
        private float seVolume = 1.0f;
        private int fadeTime = INVALID_SE_VALUE;
        private int loopTime = YanesdkUtil.SOUND_INFINITY_LOOP;

        #endregion

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

        }

        /// <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;
            }

            seNo = TagUtil.GetPramInt(tagParam, SE_NO_INDEX, INVALID_SE_VALUE);
            seVolume = TagUtil.GetPramInt(tagParam, SE_VOLUME, Sdl.SDL.MIX_MAX_VOLUME) / (float)Sdl.SDL.MIX_MAX_VOLUME; ;
            loopTime = TagUtil.GetPramInt(tagParam, SE_LOOP_TIME, YanesdkUtil.SOUND_INFINITY_LOOP);
            if (YanesdkUtil.SOUND_INFINITY_LOOP != loopTime)
            {
                // ループ回数は 0が１回、1が２回
                loopTime -= 1;
            }
            fadeTime = TagUtil.GetPramInt(tagParam, SE_FADE_TIME, INVALID_SE_VALUE);
            if (INVALID_SE_VALUE != fadeTime && fadeTime == 0)
            {
                // フェードは使わない
                fadeTime = INVALID_SE_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 (seNo == INVALID_SE_VALUE)
            {
                execState = CommandState.DONE;
                return YanesdkResult.InvalidParameter;
            }
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// SEを再生する
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult ExcecutionTag(IScenarioModel model)
        {
            // 未実行
            // 次行の先頭にSEが設定されている場合を考慮して+1する
            if (model.ShowTextCount < ExecPosition + 1)
            {
                return YanesdkResult.NoError;
            }
            YanesdkResult result;
            if (INVALID_SE_VALUE == fadeTime)
            {
                result = model.SeMgr.PlaySe(seNo, seVolume, loopTime);
            }
            else
            {
                result = model.SeMgr.PlaySeFade(seNo, seVolume, fadeTime, loopTime);
            }

            execState = CommandState.DONE;

            return result;
        }

        #endregion
    }

    /// <summary>
    /// BGM停止コマンド
    /// </summary>
    public class SeStopCommandHandler : ICommandHandler
    {
        #region 定数値

        private static readonly int INVALID_SE_VALUE = -1;
        private static readonly int MIN_PARAM_NUM = 2;
        private static readonly int SE_NO_INDEX = 1;
        private static readonly int SE_FADE_TIME = 2;

        #endregion

        #region メンバフィールド

        private int execPosition;
        private CommandProcessor processor;
        private CommandState execState = CommandState.UN_EXECUTION;
        private int seNo = INVALID_SE_VALUE;
        private int fadeTime = INVALID_SE_VALUE;

        #endregion

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

        }

        /// <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;
            }

            seNo = TagUtil.GetPramInt(tagParam, SE_NO_INDEX, INVALID_SE_VALUE);
            fadeTime = TagUtil.GetPramInt(tagParam, SE_FADE_TIME, INVALID_SE_VALUE);

            return CheckPramValue();
        }

        public int ExecPosition
        {
            set { execPosition = value; }
            get { return execPosition; }
        }

        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 (seNo == INVALID_SE_VALUE)
            {
                execState = CommandState.DONE;
                return YanesdkResult.InvalidParameter;
            }
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// SEを停止する
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult ExcecutionTag(IScenarioModel model)
        {
            if (model.ShowTextCount < ExecPosition)
            {
                return YanesdkResult.NoError;
            }
            YanesdkResult result;
            if (INVALID_SE_VALUE == fadeTime)
            {
                result = model.SeMgr.StopSe(seNo);
            }
            else
            {
                result = model.SeMgr.StopSeFade(seNo, fadeTime);
            }

            execState = CommandState.DONE;

            return result;
        }

        #endregion
    }

    /// <summary>
    /// ボイス再生コマンド
    /// </summary>
    public class VoicePlayCommandHandler : 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 int voiceNo = INVALID_VOICE_VALUE;
        private float voiceVolume = INVALID_VOICE_VALUE;
        private int fadeTime = INVALID_VOICE_VALUE;

        #endregion

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

        /// <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;
            }

            voiceNo = TagUtil.GetPramInt(tagParam, VOICE_NO_INDEX, INVALID_VOICE_VALUE);
            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);

            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)
        {
            // 未実行
            if (model.ShowTextCount < ExecPosition)
            {
                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;

            return result;
        }

        #endregion
    }



    /// <summary>
    /// ボイス待機コマンド
    /// このコマンドはボイス再生中であれば、そこで読み止まりする命令である
    /// </summary>
    public class VoiceWaitCommandHandler : ICommandHandler
    {
        #region メンバフィールド

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

        #endregion

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

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

        /// <summary>
        /// コマンド属性値の設定取得
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public YanesdkResult SetCommand(String command)
        {
            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 ExcecutingTag(model);

                case CommandState.DONE:
                    break;
            }

            return YanesdkResult.NoError;
        }

        #region 非公開メソッド

        private YanesdkResult CheckPramValue()
        {
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// VoiceWaitを開始する
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult ExcecutionTag(IScenarioModel model)
        {
            // 未実行
            if (model.ShowTextCount < ExecPosition)
            {
                return YanesdkResult.NoError;
            }
            if (model.VoiceMgr.IsPalying)
            {
                execState = CommandState.EXECUTING;
                model.ScenarioState.ReadStopFlg = true;
            }
            else
            {
                execState = CommandState.DONE;
            }

            return YanesdkResult.NoError;
        }

        /// <summary>
        /// VoiceWait のチェック
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private YanesdkResult ExcecutingTag(IScenarioModel model)
        {
            if (!model.VoiceMgr.IsPalying)
            {
                execState = CommandState.DONE;
                model.ScenarioState.ReadStopFlg = false;
            }
            return YanesdkResult.NoError;
        }



        #endregion
    }

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

        private static readonly int MIN_PARAM_NUM = 2;
        private static readonly int SCENE_ID_INDEX = 1;
        private static readonly int ADDITION_PARAM_INDEX = 2;

        #endregion

        #region メンバフィールド

        protected readonly SceneController<String> sceneController;
        private int execPosition;
        private CommandProcessor processor;
        private CommandState execState = CommandState.UN_EXECUTION;
        private String sceneId;
        private readonly List<String> paramList = new List<string>();

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public JumpSceneCommandHandler(SceneController<String> scneController)
        {
            this.sceneController = scneController;
        }

        /// <summary>
        /// 遷移先シーンID
        /// </summary>
        public String SceneId
        {
            get { return sceneId; }
        }

        /// <summary>
        /// スクリプトに指定されたパラメータのリスト
        /// </summary>
        public List<String> ParamList
        {
            get { return paramList; }
        }

        /// <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;
            }

            sceneId = TagUtil.GetPram(tagParam, SCENE_ID_INDEX, null);
            for (int i = ADDITION_PARAM_INDEX; i < tagParam.Length; i++)
            {
                paramList.Add(tagParam[i]);
            }

            return CheckPramValue();
        }

        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 virtual 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 (sceneId == null)
            {
                execState = CommandState.DONE;
                return YanesdkResult.InvalidParameter;
            }
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// SEを停止する
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        protected virtual YanesdkResult ExcecutionTag(IScenarioModel model)
        {
            if (model.ShowTextCount < ExecPosition)
            {
                return YanesdkResult.NoError;
            }


            this.sceneController.JumpScene(sceneId);

            //デリゲートが設定してあればそれを起動して終了
            if (null != processor)
            {
                processor(this, model);
            }

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

        #endregion
    }

    #endregion
}
