using System;
using System.Collections.Generic;
using System.Text;
using Yanesdk.System;
using Kyojin.Model;
using Yanesdk.GUIParts;
using Kyojin.Component;
using Yanesdk.Draw;
using Yamalib.Draw;
using System.Diagnostics;
using Yanesdk.Ytl;
using Kyojin.Component.Scenario;
using Yamalib;
using Yanesdk.Input;
using Yamalib.Util;
using Yamalib.GUI;
using Yamalib.Model;
using System.Text.RegularExpressions;
using Yanesdk.Sound;
using Yanesdk.Timer;
using Yamalib.Yanesdkext.Draw;
using Yamalib.Input;
using Kyojin.Scene.EyeCatche;
using Yamalib.Scenario;
using Yamalib.Scenario.YaneScript;
using Yamalib.Logger;
using Kyojintachi.src.yamalib.draw;

namespace Kyojin.Scene.Scenario
{
    class ScenarioScene : TaskBase, IDisposable
    {
        #region 定数値

        private const int MAIN_TEXT_MAX = 500;
        private const int RUBI_TEXT_MAX = 50;

        private const int VIEW_TEXT_OFFSETX = 45;
        private const int VIEW_TEXT_OFFSETY = 28;

        private const int TEXT_MAX_WIDTH = 530;

        // ボタン位置
        private const int EXIT_BT_X = 550;
        private const int EXIT_BT_Y = 400;
        private const int SKIP_BT_X = 550;
        private const int SKIP_BT_Y = 440;

        private const int MUNU_POS_X = 440;
        private const int MUNU_POS_Y = 454;
        private const int MUNU_SEVE_BT_OX = 4;
        private const int MUNU_OPT_BT_OX = 74;
        private const int MUNU_SIMP_OX = 125;
        private const int MUNU_IND_OX = 168;

        /// オートセーブする間隔
        private const int AUTO_SAVE_SPAN = 3 * 60 * 1000;	// ３分

        /// <summary>
        /// 去人パートではキャラクター位置を左右に大きくふるので、実画面より大きく取る
        /// </summary>
        private const int KYOJIN_VIRTUAL_VIEW_WIDTH = 860;


        #endregion

        private delegate void ReturnSceneDelegate();

        #region メンバフィールド

        private GameSystem m_gSys;
        private ScenarioDrawContext scenarioDrawContext;
        private KyojinScenarioModel model;
        private KyojinScenarioView view;
        private KyojinConst.ScenarioID nowScenarioId = KyojinConst.ScenarioID.KYOJIN01;

        private ITexture screenFilter;

        private KyojinScenarioParser scenarioParser;

        // ボタン関連
        private FocusableTextureGUIControl focusGuiCtrl = new FocusableTextureGUIControl();
        private ControlContext ctrlContext = new ControlContext();
        private bool initFlg = false;

        private ReturnSceneDelegate backOptionDg;
        private ReturnSceneDelegate backBookmarkDg;
        private ReturnSceneDelegate nextSceneDg;
        private ReturnSceneDelegate selectDialogDg;

        // メニューバー
        private PartialMenuBar menuBar;
        private ITexture skipLayer;
        private bool skipping = false;

        // プロンプトカーソル
        private PromptCarsor promptCarsor;

        private readonly FixTimer autoSaveTimer = new FixTimer();
        private Dictionary<string, int> scenarioVoiceMap;

        /// 選択肢
        private TextureDialog selectDialog;
        private bool showSelectDialog = false;

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="gameSystem"></param>
        public ScenarioScene(GameSystem gameSystem)
        {
            m_gSys = gameSystem;
        }

        #region IDisposable メンバ

        public void Dispose()
        {
            // クラスが壊れたらイベント破棄
            m_gSys.FinishDialogEvent -= DoAutoSave;
        }

        #endregion

        public override int Task(object o)
        {
            GameSystem gameSystem = (GameSystem)o;
            OnMove(gameSystem);
            gameSystem.OnMoveCommon();
            if (!gameSystem.FpsTimer.ToBeSkip)
            {
                gameSystem.Screen.Select();
                OnPaint(gameSystem);
                gameSystem.OnDrawCommon();
                gameSystem.Screen.Update();
            }
            else
            {
                OnPaint(gameSystem);
                gameSystem.OnDrawCommon();
            }
            return 1;
        }

        /// <summary>
        /// 動作処理
        /// </summary>
        /// <param name="gameSystem"></param>
        private void OnMove(GameSystem gameSystem)
        {
            if (!initFlg)
            {
                OnInit();
                initFlg = true;
            }

            m_gSys.Key.Update();
            m_gSys.KeyDecolateMouse.Update();
            m_gSys.CommonSeLoader.UpdateSE();

            // バックログのハンドラかくのまんどくせ
            if (!model.IsBackLogMode && m_gSys.KeyDecolateMouse.IsWheelUp)
            {
                model.IsBackLogMode = true;
            }
            if (model.IsBackLogMode)
            {
                if (m_gSys.KeyDecolateMouse.IsWheelUp)
                {
                    model.PrevBackLog();
                }
                else if (m_gSys.KeyDecolateMouse.IsWheelDown)
                {
                    model.NextBackLog();
                }
                else if (m_gSys.KeyDecolateMouse.IsPush(MouseInput.Button.Right))
                {
                    model.IsBackLogMode = false;
                }
            }

            // オートセーブ
            autoSaveTimer.Update();
            if (autoSaveTimer.Time > AUTO_SAVE_SPAN)
            {
                DoAutoSave();
                autoSaveTimer.Reset();
            }

            if (null != backOptionDg)
            {
                backOptionDg();
                backOptionDg = null;
            }
            if (null != backBookmarkDg)
            {
                backBookmarkDg();
                backBookmarkDg = null;
            }

            if (null != nextSceneDg)
            {
                nextSceneDg();
                nextSceneDg = null;
            }

            if (null != selectDialogDg)
            {
                selectDialogDg();
                selectDialogDg = null;
            }

            // フォーカス
            focusGuiCtrl.OnMoveFocus();

            // インプットハンドラでかくのまんどくせ
            if (skipping)
            {
                IMouseInput mouse = m_gSys.KeyDecolateMouse;
                if (mouse.IsPush(MouseInput.Button.Left) || mouse.IsPush(MouseInput.Button.Middle) ||
                    mouse.IsPush(MouseInput.Button.Right) || mouse.IsPush(MouseInput.Button.XButton1) ||
                    mouse.IsPush(MouseInput.Button.XButton2))
                {
                    skipping = false;
                    SetTextSpeed(model, m_gSys.OptionInfo);
                    if (m_gSys.OptionInfo.VoiceOn)
                    {
                        model.VoiceMgr.SoundDisable = false;
                    }
                    view.PostPaintText = null;
                }
                else
                {
                    long scenarioReadPos = m_gSys.UserInfo.GetReadPos(nowScenarioId);
                    if (scenarioReadPos > scenarioDrawContext.PageHeadTextOffset)
                    {
                        model.ContinueRead();
                    }
                    else
                    {
                        // 未読位置に来た
                        skipping = false;
                        SetTextSpeed(model, m_gSys.OptionInfo);
                        if (m_gSys.OptionInfo.VoiceOn)
                        {
                            model.VoiceMgr.SoundDisable = false;
                        }
                        view.PostPaintText = null;
                    }
                }
            }

            this.model.OnMove(gameSystem.Screen);
        }

        /// <summary>
        /// 描画処理
        /// </summary>
        /// <param name="gameSystem"></param>
        private void OnPaint(GameSystem gameSystem)
        {
            m_gSys.Screen.Clear();
            m_gSys.Screen.BlendSrcAlpha();

            // シナリオ描画
            this.view.OnPaint(gameSystem.Screen);

            // ボタンは自分で描画すっかー
            //focusGuiCtrl.OnPaint(gameSystem.Screen);

            // 選択肢
            if (showSelectDialog)
            {
                m_gSys.EnableAllInputDevie();
                m_gSys.Key.Update();
                m_gSys.KeyDecolateMouse.Update();
                selectDialog.OnPaint(m_gSys.Screen, ctrlContext, 0, 0);
                // 上の処理でダイアログボックス表示終了判定が行われている
                if (showSelectDialog)
                {
                    m_gSys.DisableAllInputDevie();
                }
            }

            // メニューバー
            menuBar.OnPaint(m_gSys.Screen, ctrlContext, 0, 0);
        }

        /// <summary>
        /// 初期化処理
        /// </summary>
        /// <param name="gameSystem"></param>
        private void OnInit()
        {
            Debug.Assert(m_gSys.ScenarioSceneParam.ScenarioInfo != null, "ScenarioInfoが設定されていない");

            // 念のためサウンドをすべて停止
            Sound.StopAll();

            //// test
            //if (m_gSys.ScenarioSceneParam.ScenarioInfo.ScenarioID == 0)
            //{
            //    m_gSys.ScenarioSceneParam.ScenarioInfo.ScenarioID = KyojinConst.ScenarioID.KYOJIN01;
            //}

            promptCarsor = new PromptCarsor();
            ITexture promptImg = YamalibConst.CreateTexture("img/scenario/carsor.png");
            promptCarsor.SetTexture(promptImg);


            // パーサのセットアップ
            SetupScenarioParser(m_gSys.ScenarioSceneParam.ScenarioInfo.ScenarioID);

            // モデルのセットアップ
            SetupModel();

            // ビューのセットアップ
            SetupView();

            // サムネール
            SetupThumbnailDraw(scenarioDrawContext, m_gSys.ScenarioSceneParam.ScenarioInfo.ScenarioID);

            // ボタン
            SetupControl();
            CreateMenuButton();

            // ボイステーブルを更新しておく
            scenarioVoiceMap = GetVoiceListMap(nowScenarioId);
            model.CommandFactory.GetFactories()[TagDefinition.TAG_VOICE] = delegate()
            {
                return new KyojinVoicePlayCommandHandler(scenarioVoiceMap);
            };

            // スキップレイヤー
            skipLayer = YamalibConst.CreateTexture("img/common/skip_layer.png");

            //// デバッグ
            //KyojinScenarioModel theModel = this.model as KyojinScenarioModel;
            //theModel.IsAutoRead = true;

            autoSaveTimer.Reset();

            // 終了ダイアログのクリックされたときのデリゲートに登録
            m_gSys.FinishDialogEvent += DoAutoSave;

            if (m_gSys.ScenarioSceneParam.IsReadTop)
            {
                // 読み始める
                this.model.ContinueRead();
            }
        }

        /// <summary>
        /// GUIコントロールを初期化する
        /// </summary>
        /// <param name="gameSystem"></param>
        private void SetupControl()
        {
            ctrlContext.MouseInput = m_gSys.MouseOriginal;
            ctrlContext.SmartTextureLoader = m_gSys.SmartTextureLoader;
            ctrlContext.SmartSoundLoader = m_gSys.SmartSoundLoader;
            ctrlContext.Param = new FocusableGUIParam(m_gSys.KeyDecolateMouse, m_gSys.Key);
            focusGuiCtrl.OnInit(ctrlContext);
        }

        /// <summary>
        /// シナリオ画面のボタンを作成
        /// </summary>
        private void CreateMenuButton()
        {
            menuBar = new PartialMenuBar();
            menuBar.OnInit(ctrlContext);
            menuBar.SetHideStep(30);

            const string defFilename = "img/menu/menu_bt.txt";

            // フォーカスにダミーを食わせる
            {
                NullButton nullBt = new NullButton();
                TextureGUIControl.Control ctrl = new TextureGUIControl.Control(nullBt, 630, 450);
                focusGuiCtrl.AddControl(ctrl);
                focusGuiCtrl.AddFocusGUI(nullBt);
            }

            // インジケータ
            {
                FocusableTextureButton btInd = new FocusableTextureButton(defFilename, false);
                btInd.LoaderOffset = 12;
                btInd.OnInit(ctrlContext);
                menuBar.SetIndicator(new TextureGUIControl.Control(btInd, MUNU_POS_X + MUNU_IND_OX, MUNU_POS_Y),
                    640 - MUNU_POS_X, 0);
            }
            // スキップ
            {
                FocusableTextureButton btSd = new FocusableTextureButton(defFilename, false);
                btSd.LoaderOffset = 8;
                btSd.OnInit(ctrlContext);
                btSd.OnClick += delegate(IScreen scr, ControlContext cc)
                {
                    // 現在のシナリオの既読位置が先であること
                    long scenarioReadPos = m_gSys.UserInfo.GetReadPos(nowScenarioId);
                    if (scenarioReadPos <= scenarioDrawContext.PageHeadTextOffset || model.IsBackLogMode)
                    {
                        m_gSys.PlaySENegative();
                        return;
                    }

                    if (!skipping)
                    {
                        skipping = true;
                        model.IsEnableReadStop = true;
                        model.ReadSpeed = int.MaxValue;
                        model.VoiceMgr.SoundDisable = true;
                        // ビューにスキップレイヤーを描画させる
                        view.PostPaintText += delegate(IScreen screen, YaneScenarioView ownView)
                        {
                            screen.Blt(skipLayer, 0, 0);
                            return YanesdkResult.NoError;
                        };

                    }
                };

                TextureGUIControl.Control ctrl = new TextureGUIControl.Control(btSd,
                    MUNU_POS_X + MUNU_SIMP_OX, MUNU_POS_Y);
                PartialMenuItem item = new PartialMenuItem();
                item.GUIControl = ctrl;
                item.Hide();

                menuBar.AddItem(item);

                focusGuiCtrl.AddControl(ctrl);
                focusGuiCtrl.AddFocusGUI(btSd);
            }
            // オプション
            {
                FocusableTextureButton btOp = new FocusableTextureButton(defFilename, false);
                btOp.LoaderOffset = 4;
                btOp.OnInit(ctrlContext);
                btOp.OnClick += delegate(IScreen scr, ControlContext cc)
                {
                    DoAutoSave();
                    m_gSys.FromTitleScene = false;
                    m_gSys.SceneController.CallScene(Scenes.OptionSetting);
                    m_gSys.PlaySystemSE((int)GameSystem.SYS_SE.CLICK_TITLE_ACTIVE);

                    // 戻ってきたときの処理をデリゲードで記述
                    backOptionDg = delegate()
                    {
                        SetOptionInfo(model, m_gSys.OptionInfo);
                    };

                };

                TextureGUIControl.Control ctrl = new TextureGUIControl.Control(btOp,
                    MUNU_POS_X + MUNU_OPT_BT_OX, MUNU_POS_Y);
                PartialMenuItem item = new PartialMenuItem();
                item.GUIControl = ctrl;
                item.Hide();

                menuBar.AddItem(item);
                focusGuiCtrl.AddControl(ctrl);
                focusGuiCtrl.AddFocusGUI(btOp);
            }
            // セーブロード
            {
                FocusableTextureButton btSaveLoad = new FocusableTextureButton(defFilename, false);
                btSaveLoad.LoaderOffset = 0;
                btSaveLoad.OnInit(ctrlContext);
                btSaveLoad.OnClick += delegate(IScreen scr, ControlContext cc)
                {
                    if (model.IsBackLogMode)
                    {
                        m_gSys.PlaySENegative();
                        return;
                    }

                    // 自動保存
                    DoAutoSave();

                    m_gSys.SceneController.CallScene(Scenes.SeveLoad);
                    m_gSys.PlaySystemSE((int)GameSystem.SYS_SE.CLICK_TITLE_ACTIVE);
                    m_gSys.FromTitleScene = false;

                    // ブックマークシーンで必要なデータを引き渡す
                    if (null == m_gSys.BookmarkSceneParam.CurrentScenarioInfo)
                    {
                        m_gSys.BookmarkSceneParam.CurrentScenarioInfo = new CurrentInfo();
                    }
                    m_gSys.BookmarkSceneParam.CurrentScenarioInfo.Text = RemoveHtmlTag(scenarioParser.GetText());
                    m_gSys.BookmarkSceneParam.CurrentScenarioInfo.ScenarioInfo = CreateScenarioInfo();

                    // ブックマークから帰ってきたときの処理を
                    backBookmarkDg = delegate()
                    {
                        // シナリオが選択されたか
                        if (m_gSys.ScenarioSceneParam.ScenarioInfo != null)
                        {
                            LoadFromScenarioInfo(m_gSys.ScenarioSceneParam.ScenarioInfo, !m_gSys.ScenarioSceneParam.IsReadTop);
                        }
                    };

                };

                TextureGUIControl.Control ctrl = new TextureGUIControl.Control(btSaveLoad,
                    MUNU_POS_X + MUNU_SEVE_BT_OX, MUNU_POS_Y);
                PartialMenuItem item = new PartialMenuItem();
                item.GUIControl = ctrl;
                item.Hide();

                menuBar.AddItem(item);

                focusGuiCtrl.AddControl(ctrl);
                focusGuiCtrl.AddFocusGUI(btSaveLoad);
            }
        }

        /// <summary>
        /// 指定したモデルに、オプション情報を反映させる
        /// </summary>
        /// <param name="theModel"></param>
        /// <param name="theOptionInfo"></param>
        private static void SetOptionInfo(KyojinScenarioModel theModel, OptionInfo theOptionInfo)
        {
            theModel.BgmMgr.SoundDisable = !theOptionInfo.BGMOn;
            theModel.SeMgr.SoundDisable = !theOptionInfo.SEOn;
            theModel.VoiceMgr.SoundDisable = !theOptionInfo.VoiceOn;

            // BGMボリューム
            theModel.BgmMgr.MasterVolume = theOptionInfo.BGMVolume / 100.0f;

            // SEボリューム
            theModel.SeMgr.MasterVolume = theOptionInfo.SEVolume / 100.0f;

            // ボイスボリューム
            theModel.VoiceMgr.MasterVolume = theOptionInfo.VoiceVolume / 100.0f;

            SetTextSpeed(theModel, theOptionInfo);
        }

        /// <summary>
        /// オプションの設定値より、テキストスピードをモデルに設定します。
        /// </summary>
        /// <param name="theModel"></param>
        /// <param name="theOptionInfo"></param>
        private static void SetTextSpeed(KyojinScenarioModel theModel, OptionInfo theOptionInfo)
        {
            // テキストスピード
            switch ((OptionInfo.TEXT_SPEED)theOptionInfo.TextSpeed)
            {
                case OptionInfo.TEXT_SPEED.NORMAL:
                    theModel.ReadSpeed = theOptionInfo.TextSpeed;
                    theModel.IsEnableReadStop = true;
                    break;
                case OptionInfo.TEXT_SPEED.FAST:
                    theModel.ReadSpeed = theOptionInfo.TextSpeed;
                    theModel.IsEnableReadStop = true;
                    break;
                case OptionInfo.TEXT_SPEED.LINE:
                    theModel.ReadSpeed = int.MaxValue;
                    theModel.IsEnableReadStop = true;
                    break;
                case OptionInfo.TEXT_SPEED.PAGE:
                    theModel.ReadSpeed = int.MaxValue;
                    theModel.IsEnableReadStop = false;
                    break;
                default:
                    Debug.Assert(false, "未定義のテキストスピードが選択された:" + new Exception().StackTrace);
                    break;
            }
        }

        /// <summary>
        /// セーブする
        /// </summary>
        private void DoAutoSave()
        {
            if (model != null && scenarioParser != null)
            {
                BookmarkData bkData = null;
                foreach (BookmarkData data in m_gSys.UserInfo.BookmarkData)
                {
                    if (data.IsAutoBookmark)
                    {
                        bkData = data;
                        break;
                    }
                }
                Debug.Assert(bkData != null, "オートセーブデータが見つからない");
                bkData.ScenarioInfo = CreateScenarioInfo();
                bkData.Text = RemoveHtmlTag(scenarioParser.GetText());
                bkData.SaveDate = DateTime.Now;
                bkData.IsUse = true;

                // ユーザ既読位置の設定
                m_gSys.UserInfo.SetReadPos(this.nowScenarioId, scenarioDrawContext.PageHeadTextOffset);

                m_gSys.SaveUserInfo(KyojinConst.SAVE_HEADER_FILE);
            }
        }

        /// <summary>
        /// 指定した文字列からHTMLタグを取り除いた文字列を返却する
        /// </summary>
        /// <param name="str"></param>
        private static string RemoveHtmlTag(string str)
        {
            // タグと改行、全角空白を除去
            Regex regex = new System.Text.RegularExpressions.Regex("<.*?>|[\n\r]|　");
            return regex.Replace(str, string.Empty);
        }

        /// <summary>
        /// 現在の情報からScenarioInfoを構築して返却する
        /// </summary>
        /// <returns></returns>
        private ScenarioInfo CreateScenarioInfo()
        {
            ScenarioInfo scenarioInfo = new ScenarioInfo();
            KyojinScenarioModel aModel = model as KyojinScenarioModel;
            scenarioInfo.ScenarioID = nowScenarioId;
            scenarioInfo.ScenarioPos = scenarioParser.GetHeadTextOffset();
            scenarioInfo.TextPos = aModel.ShowTextCount;
            //scenarioInfo.AnalyzedTagNum=model.
            scenarioInfo.BgNo = aModel.BgImgMgr.BgImgNo;
            scenarioInfo.PageNo = aModel.PageNo;
            scenarioInfo.BgmNo = aModel.BgmMgr.PlayBgmNo;
            scenarioInfo.BgmVol = aModel.BgmMgr.PlayBgmVolume;
            scenarioInfo.BgmLoop = true;
            scenarioInfo.SeNo = aModel.SeMgr.GetPlayingSeNo();

            YaneCharacterManager charaMgr = aModel.CharacterImgMgr as YaneCharacterManager;

            // キャラクター
            scenarioInfo.CharaPos.Clear();
            scenarioInfo.PresetPos.Clear();
            scenarioInfo.CharaIds.Clear();
            scenarioInfo.CharaColors.Clear();

            foreach (Character chara in charaMgr.CharacterContainer)
            {
                if (chara.IsShowing && !chara.IsEffectOut())
                {
                    scenarioInfo.CharaPos.Add(chara.CharacterOffsetX);
                    scenarioInfo.PresetPos.Add((int)chara.PresetPos);
                    scenarioInfo.CharaColors.Add(YanesdkUtil.Color4ubToString(chara.Color));
                    scenarioInfo.CharaIds.Add(chara.GetCharId());
                }
                else
                {
                    scenarioInfo.CharaPos.Add(chara.CharacterOffsetX);
                    scenarioInfo.PresetPos.Add((int)Character.PresetPosID.UNSET);
                    scenarioInfo.CharaColors.Add(YanesdkUtil.Color4ubToString(chara.Color));
                    scenarioInfo.CharaIds.Add(null);
                }
            }

            return scenarioInfo;

        }

        /// <summary>
        /// SenarioInfo からシナリオをロードします
        /// </summary>
        /// <param name="scenarioInfo"></param>
        /// <param name="scenarioLoad"></param>
        void LoadFromScenarioInfo(ScenarioInfo scenarioInfo, bool scenarioLoad)
        {
            if (!m_gSys.ScenarioSceneParam.IsUseExtraMusic)
            {
                scenarioDrawContext =
                    CreateScenarioDrawContext(KyojinConst.GetScenarioFilename(scenarioInfo.ScenarioID));
            }
            else
            {
                // TODO サウンドテスト用
                scenarioDrawContext =
                    CreateScenarioDrawContext(KyojinConst.GetScenarioFilename(scenarioInfo.ScenarioID + 3));
            }
            // 現在のシナリオIDを保存
            nowScenarioId = scenarioInfo.ScenarioID;

            scenarioParser.SetScenarioDrawContext(scenarioDrawContext);

            KyojinScenarioModel theModel = model as KyojinScenarioModel;
            // 対象シナリオのボイスマップに更新しておく
            scenarioVoiceMap = GetVoiceListMap(scenarioInfo.ScenarioID);
            // 対象シナリオのボイス定義を読み込んでおく
            YaneVoiceManager voiceMgr = theModel.VoiceMgr as YaneVoiceManager;
            Debug.Assert(voiceMgr != null);
            voiceMgr.SoundLoader = m_gSys.SmartSoundLoader.LoadDefFile(KyojinConst.GetVoiceListName(scenarioInfo.ScenarioID));
            CommonLogWriter.Write("update voice SoundLoader def file : " + KyojinConst.GetVoiceListName(scenarioInfo.ScenarioID));

            if (!scenarioLoad)
            {
                // はじめから
                theModel.PageNo = 0;

                YaneCharacterManager characterMgr = theModel.CharacterImgMgr as YaneCharacterManager;
                Debug.Assert(characterMgr != null);
                foreach (Character chara in characterMgr.CharacterContainer)
                {
                    chara.Reset();
                }
                // se をすべて止める
                theModel.SeMgr.StopAll();
            }
            else
            {
                SetupFromScenarioInfoForLoad(theModel, scenarioInfo);
            }

        }

        /// <summary>
        /// 今使用するシナリオパーサを初期化する
        /// </summary>
        private void SetupScenarioParser(KyojinConst.ScenarioID scenarioID)
        {
            FontRepository mainTextFontRep = new FontRepository(YamalibConst.FONT_REP_TEXTURE_FACTORY);
            mainTextFontRep.SetLoader(m_gSys.CommonFontLoader, KyojinConst.SCENARIO_KYOJIN_TEXT_FONT_NO);
            mainTextFontRep.Max = MAIN_TEXT_MAX;

            FontRepository rubiTextFontRep = new FontRepository(YamalibConst.FONT_REP_TEXTURE_FACTORY);
            rubiTextFontRep.SetLoader(m_gSys.CommonFontLoader, KyojinConst.SCENARIO_RUBI_FONT_NO);
            rubiTextFontRep.Max = RUBI_TEXT_MAX;

            FontRepository backMainTextFontRep = new FontRepository(YamalibConst.FONT_REP_TEXTURE_FACTORY);
            backMainTextFontRep.SetLoader(m_gSys.CommonFontLoader, KyojinConst.SCENARIO_KYOJIN_TEXT_FONT_NO);
            backMainTextFontRep.Max = MAIN_TEXT_MAX;

            scenarioParser = new KyojinScenarioParser();
            scenarioParser.TextFontRepository = mainTextFontRep;
            scenarioParser.RubiFontRepository = rubiTextFontRep;
            scenarioParser.BacklogFontRepository = backMainTextFontRep;

            // 対象のシナリオを読み込む
            if (!m_gSys.ScenarioSceneParam.IsUseExtraMusic)
            {
                scenarioDrawContext =
                    CreateScenarioDrawContext(KyojinConst.GetScenarioFilename(scenarioID));
            }
            else
            {
                scenarioDrawContext =
                    CreateScenarioDrawContext(KyojinConst.GetScenarioFilename(scenarioID + 3));
            }
            scenarioParser.SetScenarioDrawContext(scenarioDrawContext);

            // 現在のシナリオIDを保存
            nowScenarioId = scenarioID;
        }

        /// <summary>
        /// シナリオをスクリプトを読込、画面設定を行った後、そのオブジェクトを返却する
        /// </summary>
        /// <param name="scenarioFilename"></param>
        /// <returns></returns>
        private static ScenarioDrawContext CreateScenarioDrawContext(String scenarioFilename)
        {
            ScenarioDrawContext scenarioDrawContext = new ScenarioDrawContext();
            scenarioDrawContext.LoadTextFile(scenarioFilename);

            scenarioDrawContext.DrawWidth = TEXT_MAX_WIDTH;
            // 行間
            scenarioDrawContext.BlankHeight = 2;
            // 空行
            scenarioDrawContext.BlankLineHeight = 20;
            // 文字間
            scenarioDrawContext.CharacterInterval = -1;

            return scenarioDrawContext;
        }

        /// <summary>
        /// サムネール表示クラスをセットアップします
        /// </summary>
        /// <param name="scenarioDrawContext"></param>
        private void SetupThumbnailDraw(ScenarioDrawContext scenarioDrawContext_, KyojinConst.ScenarioID scenarioID)
        {
            ScenarioDrawContext theScenarioDrawContext = scenarioDrawContext_.Colne();
            theScenarioDrawContext.TextOffsetPos = 0;
            theScenarioDrawContext.PageHeadTextOffset = 0;
            ThumbnailInfo.SetCharactorImgMap(GetCharacterMapName(scenarioID));
            List<ThumbnailInfo> thumbnailInfos = new List<ThumbnailInfo>();
            long readPos = m_gSys.UserInfo.GetReadPos(scenarioID);
            int readPageNo = -1;
            int loopCount = 0;
            // サムネイルタグのみ抜き出す
            Regex regex = new System.Text.RegularExpressions.Regex("<thuminfo.*?>");
            while (true)
            {
                string pageText = theScenarioDrawContext.GetNextText();
                if (pageText == null)
                {
                    break;
                }
                Match match = regex.Match(pageText);
                if (match.Success)
                {
                    ThumbnailInfo thumbnailInfo = CreateThumbnailInfo(match.Value);
                    thumbnailInfo.Text = pageText;
                    thumbnailInfo.PageNo = loopCount;
                    thumbnailInfo.TextOffset = theScenarioDrawContext.TextOffsetPos;
                    thumbnailInfos.Add(thumbnailInfo);
                    if (-1 == readPageNo && thumbnailInfo.TextOffset > readPos)
                    {
                        // このページの前まで既読
                        readPageNo = loopCount;
                    }

                    ++loopCount;
                    match = match.NextMatch();
                }
            }

            if (readPageNo == -1)
            {
                readPageNo = thumbnailInfos.Count;
            }

            // 元に戻す
            theScenarioDrawContext.TextOffsetPos = 0;

            KyojinScenarioModel theModel = model as KyojinScenarioModel;
            theModel.ThumbnailCreator = new ThumbnailCreator(m_gSys.SmartSurfaceLoader.LoadDefFile("img2/back/list.lst", false),
                m_gSys.SmartSurfaceLoader.LoadDefFile("img2/sil/list.lst", false), CreateThumbnailTextDraw(theScenarioDrawContext));
            theModel.ThumbnailCreator.ViewWidth = KYOJIN_VIRTUAL_VIEW_WIDTH;

            theModel.ThumbnailDraw = new ThumbnailDraw(m_gSys.Screen.Width, m_gSys.Screen.Height);
            theModel.ThumbnailDraw.ThumbnailCreator = theModel.ThumbnailCreator;
            theModel.ThumbnailDraw.ThumbnailInfos = thumbnailInfos;
            theModel.ThumbnailDraw.SetThumbnailLimitNo(readPageNo);


            //test
            //theModel.IsShowThumbnailDraw = true;
            //theModel.ThumbnailDraw.SetThumbnailLimitNo(loopCount - 1);
            //theModel.ThumbnailDraw.FadeIn(5, 10);
            //theModel.ThumbnailDraw.SetThumbnailNo(10);
        }

        /// サーフェイス版の ScenarioDraw を構築する
        private ScenarioParserSurface CreateThumbnailTextDraw(ScenarioDrawContext context)
        {
            ScenarioParserSurface parser = new ScenarioParserSurface();
            parser.SetScenarioDrawContext(context);

            // フォント
            SurfaceFontRepository mainFontRep = parser.GetSurfaceFontRepository();
            mainFontRep.SetLoader(m_gSys.CommonFontLoader, KyojinConst.SCENARIO_KYOJIN_TEXT_FONT_NO);
            mainFontRep.Max = 300;

            SurfaceFontRepository rubiFontRep = parser.GetRubiSurfaceFontRepository();
            rubiFontRep.SetLoader(m_gSys.CommonFontLoader, KyojinConst.SCENARIO_RUBI_FONT_NO);
            rubiFontRep.Max = 300;

            return parser;
        }

        /// スクリプトタグ文字列から、データクラスを構築し返却する
        private static ThumbnailInfo CreateThumbnailInfo(string thumbTagStr)
        {
            char[] keyValueSplitChar = new char[] { '=' };
            char[] tagElemntSplitChar = new char[] { ' ' };

            ThumbnailInfo thumbInfo = new ThumbnailInfo();
            //<>を除去
            string[] splitStr = thumbTagStr.Substring(1, thumbTagStr.Length - 2).Split(tagElemntSplitChar);
            foreach (string str in splitStr)
            {
                if (-1 != str.IndexOf('='))
                {
                    string[] keyValue = str.Split(keyValueSplitChar);
                    string key = keyValue[0].ToUpper();
                    string value = keyValue[1];
                    switch (key)
                    {
                        case "BG":
                            thumbInfo.BgNo = Convert.ToInt32(value);
                            break;
                        case "CHARA0":
                            thumbInfo.CharaLeft = value;
                            break;
                        case "CHARA1":
                            thumbInfo.CharaCenter = value;
                            break;
                        case "CHARA2":
                            thumbInfo.CharaRight = value;
                            break;
                        case "BGM":
                            thumbInfo.BgmNo = Convert.ToInt32(value);
                            break;
                        case "BGM_LOOP":
                            thumbInfo.BgmLoop = Convert.ToInt32(value);
                            break;
                        case "SE":
                            thumbInfo.SeNo = Convert.ToInt32(value);
                            break;
                        case "SE_LOOP":
                            thumbInfo.SeLoop = Convert.ToInt32(value);
                            break;
                        default:
                            //#Log.print("undefined thumbnail tag key:%s", key);
                            break;
                    }
                }
            }

            return thumbInfo;
        }

        /// <summary>
        /// テクスチャローダーに設定する背景画像の設定ファイル名を取得する
        /// </summary>
        /// <returns></returns>
        private static string GetBGListName(KyojinConst.ScenarioID scenarioID)
        {
            switch (scenarioID)
            {
                case KyojinConst.ScenarioID.NOT_DATA:
                case KyojinConst.ScenarioID.STORY01:
                case KyojinConst.ScenarioID.STORY02_0:
                case KyojinConst.ScenarioID.STORY02_1:
                case KyojinConst.ScenarioID.STORY02_2:
                case KyojinConst.ScenarioID.STORY03:
                case KyojinConst.ScenarioID.STORY04:
                case KyojinConst.ScenarioID.STORY05:
                case KyojinConst.ScenarioID.STORY06:
                case KyojinConst.ScenarioID.STORY07:
                case KyojinConst.ScenarioID.STORY08_0:
                case KyojinConst.ScenarioID.STORY08_1:
                case KyojinConst.ScenarioID.STORY08_2:
                case KyojinConst.ScenarioID.STORY08_3:
                case KyojinConst.ScenarioID.STORY09:
                case KyojinConst.ScenarioID.STORY2ch01:
                    return "img/back/list.lst";
                case KyojinConst.ScenarioID.KYOJIN01:
                case KyojinConst.ScenarioID.KYOJIN02:
                case KyojinConst.ScenarioID.KYOJIN03:
                    return "img2/back/list.lst";
                default:
                    return "img2/back/list.lst";
            }
        }

        /// <summary>
        /// テクスチャローダーに設定するリスト設定ファイル名を取得する
        /// </summary>
        /// <returns></returns>
        private static string GetCharacterListName(KyojinConst.ScenarioID scenarioID)
        {
            switch (scenarioID)
            {
                case KyojinConst.ScenarioID.NOT_DATA:
                case KyojinConst.ScenarioID.STORY01:
                case KyojinConst.ScenarioID.STORY02_0:
                case KyojinConst.ScenarioID.STORY02_1:
                case KyojinConst.ScenarioID.STORY02_2:
                case KyojinConst.ScenarioID.STORY03:
                case KyojinConst.ScenarioID.STORY04:
                case KyojinConst.ScenarioID.STORY05:
                case KyojinConst.ScenarioID.STORY06:
                case KyojinConst.ScenarioID.STORY07:
                case KyojinConst.ScenarioID.STORY08_0:
                case KyojinConst.ScenarioID.STORY08_1:
                case KyojinConst.ScenarioID.STORY08_2:
                case KyojinConst.ScenarioID.STORY08_3:
                case KyojinConst.ScenarioID.STORY09:
                case KyojinConst.ScenarioID.STORY2ch01:
                    return "img/sil/list.lst";
                case KyojinConst.ScenarioID.KYOJIN01:
                case KyojinConst.ScenarioID.KYOJIN02:
                case KyojinConst.ScenarioID.KYOJIN03:
                    return "img2/sil/list.lst";
                default:
                    return "img2/sil/list.lst";
            }
        }

        /// <summary>
        /// キャラクターマップのファイル名を取得する
        /// </summary>
        /// <returns></returns>
        private static string GetCharacterMapName(KyojinConst.ScenarioID scenarioID)
        {
            switch (scenarioID)
            {
                case KyojinConst.ScenarioID.NOT_DATA:
                case KyojinConst.ScenarioID.STORY01:
                case KyojinConst.ScenarioID.STORY02_0:
                case KyojinConst.ScenarioID.STORY02_1:
                case KyojinConst.ScenarioID.STORY02_2:
                case KyojinConst.ScenarioID.STORY03:
                case KyojinConst.ScenarioID.STORY04:
                case KyojinConst.ScenarioID.STORY05:
                case KyojinConst.ScenarioID.STORY06:
                case KyojinConst.ScenarioID.STORY07:
                case KyojinConst.ScenarioID.STORY08_0:
                case KyojinConst.ScenarioID.STORY08_1:
                case KyojinConst.ScenarioID.STORY08_2:
                case KyojinConst.ScenarioID.STORY08_3:
                case KyojinConst.ScenarioID.STORY09:
                case KyojinConst.ScenarioID.STORY2ch01:
                    return "img/sil/chara_map.lst";
                case KyojinConst.ScenarioID.KYOJIN01:
                case KyojinConst.ScenarioID.KYOJIN02:
                case KyojinConst.ScenarioID.KYOJIN03:
                    return "img2/sil/chara_map.lst";
                default:
                    return "img2/sil/chara_map.lst";
            }
        }

        /// <summary>
        /// モデルを初期化する
        /// </summary>
        /// <returns></returns>
        private YanesdkResult SetupModel()
        {
            KyojinScenarioModel theModel = new KyojinScenarioModel();
            // ユーザ情報
            theModel.UserInfo = m_gSys.UserInfo;

            // ユーザ情報表示オブジェクト
            theModel.UserStateView = new UserStateView(m_gSys.UserInfo);

            theModel.BgImgMgr = new YaneBgImageManager(
                m_gSys.SmartTextureLoader.LoadDefFile(GetBGListName(m_gSys.ScenarioSceneParam.ScenarioInfo.ScenarioID), false));
            TextureLoader charaTl = m_gSys.SmartTextureLoader.LoadDefFile(GetCharacterListName(m_gSys.ScenarioSceneParam.ScenarioInfo.ScenarioID), false);
            YaneCharacterManager theCharaMgr = new YaneCharacterManager(charaTl, GetCharacterMapName(
                m_gSys.ScenarioSceneParam.ScenarioInfo.ScenarioID), KyojinConst.CHARA_CONTAINER_SIZE);
            // キャラクターのオフセット位置を外側にずらすために、仮想画面サイズにする
            foreach (Character chara in theCharaMgr.CharacterContainer)
            {
                chara.ViewWidth = KYOJIN_VIRTUAL_VIEW_WIDTH;
            }
            theModel.CharacterImgMgr = theCharaMgr;

            if (!m_gSys.ScenarioSceneParam.IsUseExtraMusic)
            {
                theModel.BgmMgr = new YaneBgmManager(m_gSys.SmartSoundLoader.LoadDefFile("snd/bgm/list.lst", false));
            }
            else
            {
                // TODO サウンドテスト用
                theModel.BgmMgr = new YaneBgmManager(m_gSys.SmartSoundLoader.LoadDefFile("snd/bgm_ex/list.lst", false));
            }
            theModel.SeMgr = new YaneSeManager(m_gSys.SmartSoundLoader.LoadDefFile("snd/se/list.lst", false));
            theModel.VoiceMgr = new YaneVoiceManager(m_gSys.SmartSoundLoader.LoadDefFile(
                KyojinConst.GetVoiceListName(m_gSys.ScenarioSceneParam.ScenarioInfo.ScenarioID)));
            m_gSys.LogWriter.Write("load voice id def file : " + KyojinConst.GetVoiceListName(m_gSys.ScenarioSceneParam.ScenarioInfo.ScenarioID));

            // オプションの設定を反映する
            SetOptionInfo(theModel, m_gSys.OptionInfo);

            // コマンドファクトリの生成・設定
            YaneCommandHandlerFactory commandFactory = new YaneCommandHandlerFactory();
            commandFactory.SetFactories(CreateCommandFactories());
            theModel.CommandFactory = commandFactory;

            theModel.ScenarioParser = scenarioParser;

            theModel.MouseInputHandler = CreateMouseInputHandler();
            theModel.KeyInputHandler = CreateKeyInputHandler();

            if (m_gSys.ScenarioSceneParam.IsReadTop)
            {
                // はじめから
                theModel.PageNo = 0;
            }
            else
            {
                ScenarioInfo scenarioInfo = m_gSys.ScenarioSceneParam.ScenarioInfo;
                SetupFromScenarioInfoForLoad(theModel, scenarioInfo);
            }

            this.model = theModel;

            // テキストの背景レイヤー
            SetupScenarioLayer();

            return YanesdkResult.NoError;
        }

        /// <summary>
        /// ScenarioInfoからシナリオを構築する
        /// ロード専用
        /// </summary>
        /// <param name="theModel"></param>
        /// <param name="scenarioInfo"></param>
        private void SetupFromScenarioInfoForLoad(KyojinScenarioModel theModel, ScenarioInfo scenarioInfo)
        {
            // 続きから
            scenarioDrawContext.TextOffsetPos = scenarioInfo.ScenarioPos;
            scenarioDrawContext.PageHeadTextOffset = scenarioInfo.ScenarioPos;
            theModel.PageNo = scenarioInfo.PageNo;

            // 背景
            YaneBgImageManager bgMgr = theModel.BgImgMgr as YaneBgImageManager;
            bgMgr.BgImgNo = scenarioInfo.BgNo;

            // キャラクター
            YaneCharacterManager characterMgr = theModel.CharacterImgMgr as YaneCharacterManager;
            Debug.Assert(characterMgr != null);
            for (int i = 0; i < characterMgr.CharacterContainer.Length; i++)
            {
                // プリセットポジション
                characterMgr.CharacterContainer[i].PresetPos = (Character.PresetPosID)scenarioInfo.PresetPos[i];
                // キャラクターID
                characterMgr.CharacterContainer[i].SetCharId(scenarioInfo.CharaIds[i]);
                // 色
                characterMgr.CharacterContainer[i].Color = YanesdkUtil.ToColor4ub(scenarioInfo.CharaColors[i]);

                if (characterMgr.CharacterContainer[i].PresetPos == Character.PresetPosID.UNSET)
                {
                    characterMgr.CharacterContainer[i].Reset();
                }

            }

            // BGM
            theModel.BgmMgr.PlayBgmFade(scenarioInfo.BgmNo, scenarioInfo.BgmVol, 1500);

            // se
            if (null != scenarioInfo.SeNo)
            {
                for (int i = 0; i < scenarioInfo.SeNo.Length; i++)
                {
                    theModel.SeMgr.PlaySe(scenarioInfo.SeNo[i], scenarioInfo.SeVol / 100.0f, -1);
                }
            }

            theModel.Reset();

            // updateする必要がある
            theModel.ContinueRead();
            theModel.SetShowTextCountForRestore(scenarioInfo.TextPos);
        }

        /// <summary>
        /// シナリオに従ったボイスマップを取得する
        /// </summary>
        /// <param name="scenarioID"></param>
        /// <returns></returns>
        private static Dictionary<string, int> GetVoiceListMap(KyojinConst.ScenarioID scenarioID)
        {
            string voiceListFilename = KyojinConst.GetVoiceListName(scenarioID);
            CommonLogWriter.Write("load voice def file : " + voiceListFilename);
            Dictionary<string, int> voiceMap = new Dictionary<string, int>();
            if (null == voiceListFilename)
            {
                return voiceMap;
            }

            CSVReader reader = new CSVReader();
            YanesdkResult result = reader.Read(voiceListFilename);
            if (result != YanesdkResult.NoError)
            {
                return voiceMap;
            }

            // 読み込んだCSVから、ファイル名と番号とを対応させ、
            // LinkedListに格納していく。

            List<List<string>> list = reader.CsvData;
            foreach (List<string> line in list)
            {
                // filename, channel, no, id
                if (line.Count < 4)
                {
                    continue;
                }
                voiceMap.Add(line[3], Convert.ToInt32(line[2]));
            }
            return voiceMap;
        }

        /// <summary>
        /// 去人シナリオ用のコマンドハンドラファクトリを生成し返却する
        /// </summary>
        /// <returns></returns>
        private Dictionary<String, CommandHandlerCreator> CreateCommandFactories()
        {
            Dictionary<String, CommandHandlerCreator> factories = TagDefinition.GetFactories();

            // 去人用のコマンドハンドラに上書き
            factories[TagDefinition.TAG_BG] = delegate()
            {
                return new KyojinBgCommandHandler();
            };
            factories[TagDefinition.TAG_CHARA_IN] = delegate()
            {
                return new KyojinCharaInCommandHandler();
            };
            factories[TagDefinition.TAG_CHARA_OUT] = delegate()
            {
                return new KyojinCharaOutCommandHandler();
            };
            factories[TagDefinition.TAG_VOICE] = delegate()
            {
                return new KyojinVoicePlayCommandHandler(GetVoiceListMap(KyojinConst.ScenarioID.KYOJIN01));
            };

            factories["nextscene"] = delegate()
            {
                KyojinNextSceneCommandHandler nextSceneCmd = new KyojinNextSceneCommandHandler();
                nextSceneCmd.CommandProsser = delegate(ICommandHandler own, IScenarioModel model)
                {
                    // このタグが実行されたときのデリゲート
                    KyojinNextSceneCommandHandler cmd = own as KyojinNextSceneCommandHandler;
                    return NextScene(cmd.SceneId);
                };
                return nextSceneCmd;
            };

            /// 選択枝
            factories["select"] = delegate()
            {
                SelectCommandHandler selectCmd = new SelectCommandHandler();
                selectCmd.CommandProsser = delegate(ICommandHandler own, IScenarioModel model)
                {
                    if (!showSelectDialog)
                    {
                        // 選択肢ダイアログを作成
                        selectDialog = TextureDialog.CreateDialogBox(m_gSys.createDialogResources(), "img/dialog/dialog_select.txt",
                            ctrlContext, m_gSys.Key, 0, 1);
                        List<TextureGUIControl.Control> bts = selectDialog.GetButton();
                        // 日記を読む
                        FontButton readButton = bts[0].Parts as FontButton;
                        readButton.OnClick += delegate(IScreen scr, ControlContext cc)
                        {
                            // さらに次回の「移動処理時」に処理を実行させるために、デリゲート登録しておく
                            selectDialogDg = delegate()
                            {
                                m_gSys.UserInfo.SetReadFlg((int)KyojinConst.ScenarioID.STORY02_0, true);
                                // テロップへ
                                m_gSys.SceneController.ExitScene();
                                m_gSys.SceneController.CallScene(Scenes.ScenarioEndEyecatche);
                                m_gSys.CommonBgmLoader.StopBGMFade(1000);
                                OnPaint(m_gSys);
                                m_gSys.EyeCatcheSceneParam.ScreenImg = YanesdkUtil.CopyGlFlameBufferNormalize(m_gSys.Screen as Screen2DGl);
                                m_gSys.EyeCatcheSceneParam.CallScenarioNo = KyojinConst.ScenarioID.STORY02_2;
                                m_gSys.EyeCatcheSceneParam.Pattern = (int)SenarioEndEyeCatcheScene.SHI_TYPE.ANZAI01;
                                // ダイアログ選択終了
                                showSelectDialog = false;
                                m_gSys.EnableAllInputDevie();
                                CommonLogWriter.Write("READ");
                            };
                        };
                        // 日記を読まない
                        FontButton noReadButton = bts[1].Parts as FontButton;
                        noReadButton.OnClick += delegate(IScreen scr, ControlContext cc)
                        {
                            // さらに次回の「移動処理時」に処理を実行させるために、デリゲート登録しておく
                            selectDialogDg = delegate()
                            {
                                m_gSys.UserInfo.SetReadFlg((int)KyojinConst.ScenarioID.STORY02_0, true);
                                // テロップへ
                                m_gSys.SceneController.ExitScene();
                                m_gSys.SceneController.CallScene(Scenes.ScenarioEndEyecatche);
                                m_gSys.CommonBgmLoader.StopBGMFade(1000);
                                OnPaint(m_gSys);
                                m_gSys.EyeCatcheSceneParam.ScreenImg = YanesdkUtil.CopyGlFlameBufferNormalize(m_gSys.Screen as Screen2DGl);
                                m_gSys.EyeCatcheSceneParam.CallScenarioNo = KyojinConst.ScenarioID.STORY02_1;
                                m_gSys.EyeCatcheSceneParam.Pattern = (int)SenarioEndEyeCatcheScene.SHI_TYPE.ANZAI01;
                                // ダイアログ選択終了
                                showSelectDialog = false;
                                m_gSys.EnableAllInputDevie();
                                CommonLogWriter.Write("NO READ");
                            };
                        };

                        // 選択肢表示時はなにもさせない
                        m_gSys.DisableAllInputDevie();
                        showSelectDialog = true;
                    }
                    return YanesdkResult.NoError;
                };
                return selectCmd;
            };


            return factories;
        }

        /// <summary>
        /// 別シーンへの遷移処理
        /// </summary>
        /// <param name="sceneId"></param>
        /// <returns></returns>
        private YanesdkResult NextScene(string sceneId)
        {
            nextSceneDg = delegate()
            {
                ScenarioInfo scenarioInfo = new ScenarioInfo();
                // TODO シナリオエンド時の遷移処理を追加すること
                switch (sceneId.ToLower())
                {
                    case "title":
                        // メインパートプロローグ（タイトル画面に戻るけど、すべてフラグならエンディングへ）
                        m_gSys.UserInfo.SetReadFlg((int)nowScenarioId, true);
                        m_gSys.UserInfo.SetReadPos(nowScenarioId, scenarioParser.GetScenarioDrawContext().PageHeadTextOffset + 1);

                        if (nowScenarioId == KyojinConst.ScenarioID.STORY07 || nowScenarioId == KyojinConst.ScenarioID.STORY05)
                        {
                            // 今のシナリオはエピローグ
                            if (m_gSys.UserInfo.IsRead((int)KyojinConst.ScenarioID.STORY05) && m_gSys.UserInfo.IsRead((int)KyojinConst.ScenarioID.STORY07))
                            {
                                // メインパートをすべて読んだということなので、エンディングにジャンプして終わる
                                m_gSys.SceneController.ExitScene();
                                m_gSys.SceneController.JumpScene(Scenes.MainPartEnding);
                                m_gSys.CommonBgmLoader.StopBGMFade(1000);
                                break;
                            }
                        }
                        // タイトルへジャンプ
                        m_gSys.SceneController.ExitScene();
                        m_gSys.SceneController.JumpScene(Scenes.Startmenu);
                        m_gSys.CommonBgmLoader.StopBGMFade(1000);
                        break;

                    case "telop":
                        m_gSys.TelopParam.CallScenarioNo = nowScenarioId;
                        m_gSys.SceneController.CallScene(Scenes.MainPartTelop);
                        break;

                    case "story02":
                        // 残秋挽歌
                        m_gSys.UserInfo.SetReadFlg((int)KyojinConst.ScenarioID.STORY01, true);
                        m_gSys.UserInfo.SetReadPos(nowScenarioId, scenarioParser.GetScenarioDrawContext().PageHeadTextOffset + 1);
                        // テロップへ
                        m_gSys.SceneController.ExitScene();
                        m_gSys.SceneController.CallScene(Scenes.ScenarioEndEyecatche);
                        m_gSys.CommonBgmLoader.StopBGMFade(1000);
                        OnPaint(m_gSys);
                        m_gSys.EyeCatcheSceneParam.ScreenImg = YanesdkUtil.CopyGlFlameBufferNormalize(m_gSys.Screen as Screen2DGl);
                        m_gSys.EyeCatcheSceneParam.CallScenarioNo = KyojinConst.ScenarioID.STORY02_0;
                        m_gSys.EyeCatcheSceneParam.Pattern = (int)SenarioEndEyeCatcheScene.SHI_TYPE.TOMIE01;
                        break;
                    case "story05":
                        m_gSys.UserInfo.SetReadFlg((int)KyojinConst.ScenarioID.STORY02_1, true);
                        m_gSys.UserInfo.SetReadPos(nowScenarioId, scenarioParser.GetScenarioDrawContext().PageHeadTextOffset + 1);
                        // テロップへ
                        m_gSys.SceneController.ExitScene();
                        m_gSys.SceneController.CallScene(Scenes.ScenarioEndEyecatche);
                        m_gSys.CommonBgmLoader.StopBGMFade(1000);
                        OnPaint(m_gSys);
                        m_gSys.EyeCatcheSceneParam.ScreenImg = YanesdkUtil.CopyGlFlameBufferNormalize(m_gSys.Screen as Screen2DGl);
                        m_gSys.EyeCatcheSceneParam.CallScenarioNo = KyojinConst.ScenarioID.STORY03;
                        m_gSys.EyeCatcheSceneParam.Pattern = (int)SenarioEndEyeCatcheScene.SHI_TYPE.ALICE01;
                        break;
                    case "story06":
                        m_gSys.UserInfo.SetReadFlg((int)KyojinConst.ScenarioID.STORY03, true);
                        m_gSys.UserInfo.SetReadPos(nowScenarioId, scenarioParser.GetScenarioDrawContext().PageHeadTextOffset + 1);
                        // テロップへ
                        m_gSys.SceneController.ExitScene();
                        m_gSys.SceneController.CallScene(Scenes.ScenarioEndEyecatche);
                        m_gSys.CommonBgmLoader.StopBGMFade(1000);
                        OnPaint(m_gSys);
                        m_gSys.EyeCatcheSceneParam.ScreenImg = YanesdkUtil.CopyGlFlameBufferNormalize(m_gSys.Screen as Screen2DGl);
                        m_gSys.EyeCatcheSceneParam.CallScenarioNo = KyojinConst.ScenarioID.STORY04;
                        m_gSys.EyeCatcheSceneParam.Pattern = (int)SenarioEndEyeCatcheScene.SHI_TYPE.MIDO01;
                        break;
                    case "story07":
                        m_gSys.UserInfo.SetReadFlg((int)KyojinConst.ScenarioID.STORY01, true);
                        m_gSys.UserInfo.SetReadPos(nowScenarioId, scenarioParser.GetScenarioDrawContext().PageHeadTextOffset + 1);
                        // テロップへ
                        m_gSys.SceneController.ExitScene();
                        m_gSys.SceneController.CallScene(Scenes.ScenarioEndEyecatche);
                        m_gSys.CommonBgmLoader.StopBGMFade(1000);
                        OnPaint(m_gSys);
                        m_gSys.EyeCatcheSceneParam.ScreenImg = YanesdkUtil.CopyGlFlameBufferNormalize(m_gSys.Screen as Screen2DGl);
                        m_gSys.EyeCatcheSceneParam.CallScenarioNo = KyojinConst.ScenarioID.STORY05;
                        m_gSys.EyeCatcheSceneParam.Pattern = (int)SenarioEndEyeCatcheScene.SHI_TYPE.AYA01;
                        break;
                    case "story08":
                        m_gSys.UserInfo.SetReadFlg((int)KyojinConst.ScenarioID.STORY02_2, true);
                        m_gSys.UserInfo.SetReadPos(nowScenarioId, scenarioParser.GetScenarioDrawContext().PageHeadTextOffset + 1);
                        // テロップへ
                        m_gSys.SceneController.ExitScene();
                        m_gSys.SceneController.CallScene(Scenes.ScenarioEndEyecatche);
                        m_gSys.CommonBgmLoader.StopBGMFade(1000);
                        OnPaint(m_gSys);
                        m_gSys.EyeCatcheSceneParam.ScreenImg = YanesdkUtil.CopyGlFlameBufferNormalize(m_gSys.Screen as Screen2DGl);
                        m_gSys.EyeCatcheSceneParam.CallScenarioNo = KyojinConst.ScenarioID.STORY06;
                        m_gSys.EyeCatcheSceneParam.Pattern = (int)SenarioEndEyeCatcheScene.SHI_TYPE.MIDO01;
                        break;
                    case "kyojin02":
                        // 既読フラグ
                        m_gSys.UserInfo.SetReadFlg((int)KyojinConst.ScenarioID.KYOJIN01, true);
                        m_gSys.UserInfo.SetReadPos(nowScenarioId, scenarioParser.GetScenarioDrawContext().PageHeadTextOffset + 1);
                        DoAutoSave();

                        // テロップへ
                        m_gSys.SceneController.ExitScene();
                        m_gSys.SceneController.CallScene(Scenes.Telop);
                        m_gSys.CommonBgmLoader.StopBGMFade(1000);
                        OnPaint(m_gSys);
                        //m_gSys.EyeCatcheSceneParam.ScreenImg = YanesdkUtil.CopyGlFlameBuffer(m_gSys.Screen as Screen2DGl);
                        //m_gSys.EyeCatcheSceneParam.CallScenarioNo = KyojinConst.ScenarioID.KYOJIN02;
                        m_gSys.TelopParam.ScreenImg = YanesdkUtil.CopyGlFlameBuffer(m_gSys.Screen as Screen2DGl);
                        m_gSys.TelopParam.CallScenarioNo = KyojinConst.ScenarioID.KYOJIN02;
                        break;
                    case "kyojin03":
                        // 既読フラグ
                        m_gSys.UserInfo.SetReadFlg((int)KyojinConst.ScenarioID.KYOJIN02, true);
                        m_gSys.UserInfo.SetReadPos(nowScenarioId, scenarioParser.GetScenarioDrawContext().PageHeadTextOffset + 1);
                        DoAutoSave();

                        // テロップへ
                        m_gSys.SceneController.ExitScene();
                        m_gSys.SceneController.CallScene(Scenes.Telop);
                        m_gSys.CommonBgmLoader.StopBGMFade(1000);
                        OnPaint(m_gSys);
                        m_gSys.TelopParam.ScreenImg = YanesdkUtil.CopyGlFlameBuffer(m_gSys.Screen as Screen2DGl);
                        m_gSys.TelopParam.CallScenarioNo = KyojinConst.ScenarioID.KYOJIN03;
                        break;

                    case "kyojinending":
                        // 既読フラグ
                        m_gSys.UserInfo.SetReadFlg((int)KyojinConst.ScenarioID.KYOJIN03, true);
                        m_gSys.UserInfo.SetReadPos(nowScenarioId, scenarioParser.GetScenarioDrawContext().PageHeadTextOffset + 1);
                        DoAutoSave();

                        // エンディングへ
                        m_gSys.SceneController.ExitScene();
                        m_gSys.SceneController.CallScene(Scenes.Ending);
                        m_gSys.CommonBgmLoader.StopBGMFade(1000);
                        break;

                    default:
                        break;
                }
            };
            return YanesdkResult.NoError;
        }

        /// <summary>
        /// ビューを設定する
        /// </summary>
        /// <returns></returns>
        private YanesdkResult SetupView()
        {
            screenFilter = YamalibConst.CreateTexture("img/scenario/black_filter.png");
            KyojinScenarioView theView = new KyojinScenarioView();
            theView.Model = model;
            // マウス
            theView.Mouse = m_gSys.KeyDecolateMouse;

            theView.SetTextOffsetXY(VIEW_TEXT_OFFSETX, VIEW_TEXT_OFFSETY);
            this.view = theView;

            // プロンプトカーソル表示すると落ち着かないなぁ...
            //theView.PostPaintText = delegate(IScreen screen, YaneScenarioView view)
            //{
            //    // プロンプトカーソルを描画する
            //    KyojinScenarioView myView = view as KyojinScenarioView;
            //    YaneScenarioModel myModel = myView.Model as YaneScenarioModel;
            //    int ox, oy;
            //    myView.GetTextOffsetXY(out ox, out oy);
            //    int lastLetterIndex = myModel.ShowTextCount;
            //    if (myModel.LetterData.Count <= lastLetterIndex)
            //    {
            //        lastLetterIndex = myModel.LetterData.Count - 1;
            //        ox += 20;
            //    }
            //    promptCarsor.SetXY(ox + (int)myModel.LetterData[lastLetterIndex].Pos.X, oy + (int)myModel.LetterData[lastLetterIndex].Pos.Y);
            //    promptCarsor.OnPaint(screen);
            //    return YanesdkResult.NoError;
            //};

            theView.PostPaintCharacter = delegate(IScreen screen, YaneScenarioView view)
            {
                KyojinScenarioView myView = view as KyojinScenarioView;
                myView.IsShowText = false;
                if (!m_gSys.Key.IsPress(11) && !m_gSys.Key.IsPress(12))
                {
                    Color4ub colorOrg = YanesdkUtil.GetNowScreenColor(screen);
                    screen.SetColor(255, 255, 255, 128);
                    screen.Blt(screenFilter, 0, 0);
                    screen.SetColor(colorOrg);
                    myView.IsShowText = true;
                }
                return YanesdkResult.NoError;
            };

            return YanesdkResult.NoError;
        }

        /// <summary>
        /// ストーリー画面のレイヤーを設定
        /// </summary>
        /// <returns></returns>
        private YanesdkResult SetupScenarioLayer()
        {
            // TODO: レイヤーが必要なら追記すること
            return YanesdkResult.NoError;
        }

        private void ReturnScene()
        {
            m_gSys.SceneController.ReturnScene();
        }

        /// <summary>
        /// マウスのハンドラを生成して返却する
        /// </summary>
        /// <returns></returns>
        private MouseInputHandler CreateMouseInputHandler()
        {
            MouseInputHandler handler = new MouseInputHandler(m_gSys.KeyDecolateMouse);

            // 右クリック
            handler.SetHandler(new MouseState(MouseInput.Button.Left, true),
                delegate(IScenarioModel model)
                {
                    KyojinScenarioModel theModel = model as KyojinScenarioModel;
                    if (theModel == null)
                    {
                        return YanesdkResult.InvalidParameter;
                    }
                    //CommonLogWriter.Write("HANDLE LCLICK UP");
                    if ((theModel.IsReadStop || theModel.IsPageEnd) && !theModel.IsEffectWait && !theModel.ScenarioState.InputLockFlg && !theModel.IsShowThumbnailDraw &&
                        !menuBar.IsInBar())
                    {
                        // ボイスが再生されていたら止める
                        model.VoiceMgr.StopVoiceFade(250);

                        // 読み進める
                        return model.ContinueRead();
                    }
                    return YanesdkResult.NoError;
                }
            );

            return handler;
        }

        /// <summary>
        /// マウスのハンドラを生成して返却する
        /// </summary>
        /// <returns></returns>
        private KeyInputHandler CreateKeyInputHandler()
        {
            KeyInputHandler handler = new KeyInputHandler(m_gSys.Key);

            // サムネール起動
            InputHandler thumbnailStartEvent = delegate(IScenarioModel model)
                {
                    KyojinScenarioModel theModel = model as KyojinScenarioModel;
                    if (theModel == null)
                    {
                        return YanesdkResult.InvalidParameter;
                    }

                    if (nowScenarioId < KyojinConst.ScenarioID.KYOJIN01)
                    {
                        return YanesdkResult.NoError;
                    }

                    CommonLogWriter.Write("HANDLE Thumbail Start Event");
                    if (!theModel.IsShowThumbnailDraw)
                    {

                        if (theModel.PageNo > theModel.ThumbnailDraw.GetThumbnailLimitNo())
                        {
                            theModel.ThumbnailDraw.SetThumbnailLimitNo(theModel.PageNo);
                        }

                        theModel.ThumbnailDraw.SetThumbnailNo(theModel.PageNo - 1);
                        theModel.ThumbnailDraw.FadeIn(5, 10);
                        theModel.IsShowThumbnailDraw = true;
                    }
                    return YanesdkResult.NoError;
                };

            // Ctrl + TAB サムネール起動
            handler.SetHandler(new KeyState(new KeyCode[] { (KeyCode)11, (KeyCode)14 }, false), thumbnailStartEvent);
            handler.SetHandler(new KeyState(new KeyCode[] { (KeyCode)13, (KeyCode)14 }, false), thumbnailStartEvent);

            // サムネール決定 enter
            handler.SetHandler(new KeyState(new KeyCode[] { (KeyCode)6 }, false),
                 delegate(IScenarioModel model)
                 {
                     KyojinScenarioModel theModel = model as KyojinScenarioModel;
                     if (theModel == null)
                     {
                         return YanesdkResult.InvalidParameter;
                     }
                     if (theModel.IsShowThumbnailDraw)
                     {
                         CommonLogWriter.Write("HANDLE Thumbail End Event");
                         if (theModel.ThumbnailDraw.IsFinishSelect())
                         {
                             // サムネール決定
                             theModel.ThumbnailDraw.ResetSelect();
                         }
                     }
                     return YanesdkResult.NoError;
                 }
                );

            // サムネールキャンセル Esc
            handler.SetHandler(new KeyState(new KeyCode[] { (KeyCode)0 }, false),
                 delegate(IScenarioModel model)
                 {
                     KyojinScenarioModel theModel = model as KyojinScenarioModel;
                     if (theModel == null)
                     {
                         return YanesdkResult.InvalidParameter;
                     }
                     if (theModel.IsShowThumbnailDraw)
                     {
                         // サムネールキャンセル
                         if (YanesdkResult.NoError == theModel.ThumbnailDraw.FadeOut(5, 10))
                         {
                             theModel.ThumbnailDraw.FadeOutFinishEvent = delegate()
                             {
                                 theModel.ThumbnailDraw.ResetSelect();
                                 theModel.IsShowThumbnailDraw = false;
                             };
                         }
                     }
                     return YanesdkResult.NoError;
                 }
                );

            // サムネールキャンセル 次へ
            handler.SetHandler(new KeyState(new KeyCode[] { (KeyCode)14 }, false),
                 delegate(IScenarioModel model)
                 {
                     KyojinScenarioModel theModel = model as KyojinScenarioModel;
                     if (theModel == null)
                     {
                         return YanesdkResult.InvalidParameter;
                     }
                     if (theModel.IsShowThumbnailDraw)
                     {
                         // サムネールキャンセル
                         theModel.ThumbnailDraw.Next();
                     }
                     return YanesdkResult.NoError;
                 }
                );

            // 決定
            handler.SetHandler(new KeyState(new KeyCode[] { (KeyCode)6 }, false),
                 delegate(IScenarioModel model)
                 {
                     KyojinScenarioModel theModel = model as KyojinScenarioModel;
                     if (theModel == null)
                     {
                         return YanesdkResult.InvalidParameter;
                     }
                     if (theModel.IsShowThumbnailDraw && !theModel.ThumbnailDraw.IsFinishSelect())
                     {
                         theModel.ThumbnailDraw.SelectPane(0, 20);

                         theModel.ThumbnailDraw.SelectFinishEvent = delegate
                         {
                             theModel.ThumbnailDraw.ResetSelect();
                             theModel.IsShowThumbnailDraw = false;
                             JumpByThumbnail(theModel.ThumbnailDraw.GetActiveInfo()[0]);
                             theModel.ThumbnailDraw.SelectFinishEvent = null;
                         };
                     }
                     return YanesdkResult.NoError;
                 }
                );

            return handler;
        }

        /// <summary>
        /// 再読込
        /// </summary>
        /// <param name="thumbInfo"></param>
        private void JumpByThumbnail(ThumbnailInfo thumbInfo)
        {
            model.ScenarioState.PageEndFlg = true;
            LoadFromScenarioInfo(CreateScenarioInfoFromThumbnailInfo(thumbInfo), true);
        }

        /// <summary>
        /// サムネール情報からScenarioInfoを再作成する
        /// </summary>
        /// <param name="thumbInfo"></param>
        /// <returns></returns>
        private ScenarioInfo CreateScenarioInfoFromThumbnailInfo(ThumbnailInfo thumbInfo)
        {
            ScenarioInfo scenarioInfo = new ScenarioInfo();

            scenarioInfo.ScenarioID = nowScenarioId;	// シナリオ番号
            scenarioInfo.BgNo = thumbInfo.BgNo;
            scenarioInfo.BgmNo = thumbInfo.BgmNo;
            scenarioInfo.BgmVol = m_gSys.OptionInfo.BGMVolume / 100.0f;
            scenarioInfo.BgmLoop = true;
            if (thumbInfo.SeNo != -1)
            {
                scenarioInfo.SeNo = new int[4];
                scenarioInfo.SeNo[0] = thumbInfo.SeNo;
                scenarioInfo.SeLoop = 0;
                scenarioInfo.SeVol = m_gSys.OptionInfo.SEVolume / 100.0f; ;
            }
            scenarioInfo.PageNo = thumbInfo.PageNo;	// １ページからはじまる
            scenarioInfo.TextPos = 0;
            scenarioInfo.ScenarioPos = thumbInfo.TextOffset;
            scenarioInfo.TextPos = int.MaxValue;
            scenarioInfo.AnalyzedTagNum = int.MaxValue;

            if (thumbInfo.CharaLeft != null)
            {
                scenarioInfo.CharaPos.Add(0);
                scenarioInfo.PresetPos.Add((int)Character.PresetPosID.LEFT);
                scenarioInfo.CharaIds.Add(thumbInfo.CharaLeft);
                scenarioInfo.CharaColors.Add(null);
            }
            else
            {
                scenarioInfo.CharaPos.Add(0);
                scenarioInfo.PresetPos.Add((int)Character.PresetPosID.UNSET);
                scenarioInfo.CharaIds.Add(null);
                scenarioInfo.CharaColors.Add(null);
            }

            if (thumbInfo.CharaCenter != null)
            {
                scenarioInfo.CharaPos.Add(0);
                scenarioInfo.PresetPos.Add((int)Character.PresetPosID.CENTER);
                scenarioInfo.CharaIds.Add(thumbInfo.CharaCenter);
                scenarioInfo.CharaColors.Add(null);
            }
            else
            {
                scenarioInfo.CharaPos.Add(0);
                scenarioInfo.PresetPos.Add((int)Character.PresetPosID.UNSET);
                scenarioInfo.CharaIds.Add(null);
                scenarioInfo.CharaColors.Add(null);
            }

            if (thumbInfo.CharaRight != null)
            {
                scenarioInfo.CharaPos.Add(0);
                scenarioInfo.PresetPos.Add((int)Character.PresetPosID.RIGHT);
                scenarioInfo.CharaIds.Add(thumbInfo.CharaRight);
                scenarioInfo.CharaColors.Add(null);
            }
            else
            {
                scenarioInfo.CharaPos.Add(0);
                scenarioInfo.PresetPos.Add((int)Character.PresetPosID.UNSET);
                scenarioInfo.CharaIds.Add(null);
                scenarioInfo.CharaColors.Add(null);
            }

            scenarioInfo.CharaPos.Add(0);
            scenarioInfo.PresetPos.Add((int)Character.PresetPosID.UNSET);
            scenarioInfo.CharaIds.Add(null);
            scenarioInfo.CharaColors.Add(null);

            return scenarioInfo;
        }

    }


}
