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

namespace Yamalib.Scenario
{
    /// <summary>
    /// シナリオ描画時のコンテキストを指定するデータクラス
    /// </summary>
    public class ScenarioDrawContext
    {
        #region 定数フィールド

        #endregion

        public ScenarioDrawContext Colne()
        {
            ScenarioDrawContext instance = new ScenarioDrawContext();
            instance.DisplayWidth = this.DisplayWidth;
            instance.DrawWidth = this.DrawWidth;
            instance.BlankHeight = this.BlankHeight;
            instance.BlankLineHeight = this.BlankLineHeight;
            instance.CharacterInterval = this.CharacterInterval;
            instance.TextColor = this.TextColor;
            instance.TextShadowColor = this.TextShadowColor;
            instance.HorizontalAlign = this.HorizontalAlign;
            instance.VerticalAlign = this.VerticalAlign;
            instance.Vartical = this.Vartical;
            instance.SetText(this.ScenarioText);
            instance.TextOffsetPos = this.TextOffsetPos;
            instance.PageHeadTextOffset = this.PageHeadTextOffset;

            return instance;
        }

        /// コンストラクタ
        public ScenarioDrawContext()
        {
            width = 530;
            blankHeight = 2;
            align1 = 0;
            align2 = 0;
            hInterval = 4; // 文字と文字との間隔
            textPos = 0;
            viewWidth = 640;
        }

        # region フィールドとプロパティ

        private int viewWidth = YamalibConst.DEFAULT_SCRENN_WIDTH;		//	画面サイズ

        /// <summary>
        /// 画面の幅
        /// </summary>
        public int DisplayWidth
        {
            get { return viewWidth; }
            set { viewWidth = value; }
        }
        private int width;			//	最大で表示する横幅
        /// <summary>
        /// テキストの最大表示幅
        /// ただし、これは禁則処理を含まない幅
        /// </summary>
        public int DrawWidth
        {
            get { return width; }
            set { width = value; }
        }
        private int blankHeight;	//	行間

        /// <summary>
        /// 行間
        /// </summary>
        public int BlankHeight
        {
            get { return blankHeight; }
            set { blankHeight = value; }
        }
        private int blankHeight2;	//	空行の高さ

        /// <summary>
        /// 空行の高さ
        /// </summary>
        public int BlankLineHeight
        {
            get { return blankHeight2; }
            set { blankHeight2 = value; }
        }

        private int hInterval;		//	文字と文字との間隔

        /// <summary>
        /// 文字間
        /// </summary>
        public int CharacterInterval
        {
            get { return hInterval; }
            set { hInterval = value; }
        }

        /// <summary>
        /// 文字の色
        /// デフォルトでは 255:255:255:255 (白)
        /// </summary>
        private Color4ub textColor = YanesdkUtil.WHITE_COLOR;

        /// <summary>
        /// バックログ用のテキストカラー
        /// </summary>
        private Color4ub backLogTextColor = new Color4ub(128, 128, 128, 255);

        /// <summary>
        /// 文字の色
        /// </summary>
        public Color4ub TextColor
        {
            get { return textColor; }
            set { textColor = value; }
        }

        public Color4ub BackLogTextColor
        {
            get { return backLogTextColor; }
            set { backLogTextColor = value; }
        }

        private Color4ub textShadowColor = YanesdkUtil.BLOCK_COLOR;		//	バックの文字の色(ディフォルトではCLR_INVALIDなので描画できない)

        /// <summary>
        /// 文字の陰色
        /// デフォルトでは 0:0:0 (黒)
        /// </summary>
        public Color4ub TextShadowColor
        {
            get { return textShadowColor; }
            set { textShadowColor = value; }
        }

        private int align1;			//	0:左寄せ(通常) 1:センター 2:右寄せ

        public int HorizontalAlign
        {
            get { return align1; }
            set { align1 = value; }
        }
        private int align2;			//	0:下寄せ(通常) 1:センター 2:上寄せ

        public int VerticalAlign
        {
            get { return align2; }
            set { align2 = value; }
        }

        private bool vartical;

        /// <summary>
        /// 縦書きかどうか
        /// </summary>
        public bool Vartical
        {
            get { return vartical; }
            set { vartical = value; }
        }

        private String strText;	//	現在のコンテクスト位置
        private int textPos;		// 読み完了したところまでの位置
        private int prevTextPos;		// 読み込んでいるページの最初の位置
        private bool backTextFlg;

        /// <summary>
        /// 今読み込んでいるシナリオテキスト（読み取り専用）
        /// </summary>
        public String ScenarioText
        {
            get { return strText; }
        }


        /// <summary>
        /// 今読んでいるところの位置を設定取得する
        /// </summary>
        public int TextOffsetPos
        {
            get { return textPos; }
            set { textPos = value; }
        }

        /// <summary>
        /// 現在の１頁分のスクリプトの先頭オフセット値
        /// </summary>
        public int PageHeadTextOffset
        {
            get { return prevTextPos; }
            set { prevTextPos = value; }
        }

        # endregion

        public void LoadTextFile(String filename)
        {
            SetText(Util.YamalibUtility.ReadTextFile(filename));
        }

        /// シナリオ全体の文字列を設定
        public void SetText(String text)
        {
            strText = text;
            textPos = 0;
        }

        /// <HR> までの文字列を返す
        public String GetNextText()
        {

            if (backTextFlg)
            {
                backTextFlg = false;
                if (textPos != 0)
                {
                    textPos += 3;
                }
            }

            int startpos0 = textPos;
            prevTextPos = textPos;

            if (textPos >= strText.Length) return null;

            do
            {
            CONTINUE:
                ;
                char c = strText[textPos++];

                if (c == '<')
                {
                    //	タグの取得
                    //	前方へ '>'をサーチ
                    int startpos = textPos;
                    while (true)
                    {

                        if (textPos >= strText.Length)
                        {
                            throw new YanesdkException(this, "タグが閉じられていない");
                        }

                        char wc = strText[textPos];
                        if (wc == '>')
                        {
                            String tag = strText.Substring(startpos, (textPos - startpos));
                            if (tag == "HR" || tag == "hr")
                            {
                                ++textPos;
                                String ww = strText.Substring(startpos0, (textPos - startpos0));
                                return ww;
                            }
                            else
                            {
                                goto CONTINUE;
                            }
                        }
                        textPos++;
                    }
                }

            } while (textPos < strText.Length);

            return strText.Substring(startpos0, textPos - startpos0);
        }

        /// 前の<HR> までの文字列を返す
        public String GetPreText()
        {

            if (textPos < 0)
            {
                // EOFまで達している
                textPos = 0;
            }

            if (!backTextFlg)
            {
                GetPrevHRPos();
            }

            if (textPos == 0) return null;

            int endpos0 = textPos;
            prevTextPos = textPos;

            do
            {
            CONTINUE:
                ;
                char c = strText[textPos--];

                if (c == '>')
                {
                    //	タグの取得
                    //	前方へ '>'をサーチ
                    int tailpos = textPos;
                    while (true)
                    {

                        if (textPos < 0)
                        {
                            throw new YanesdkException(this, "タグが閉じられていない");
                        }

                        char wc = strText[textPos];
                        if (wc == '<')
                        {
                            String tag = strText.Substring(textPos + 1, tailpos - textPos);

                            if (tag == "HR" || tag == "hr")
                            {
                                backTextFlg = true;
                                String ww = strText.Substring(tailpos + 2, endpos0 - (tailpos + 2));
                                return ww;
                            }
                            else
                            {
                                goto CONTINUE;
                            }
                        }
                        textPos--;
                    }
                }

            } while (textPos >= 0);



            return strText.Substring(0, endpos0);
        }

        /// 以前の<HR>タグの位置を返却する
        private int GetPrevHRPos()
        {

            // まず現ページのＨＥＡＤポジションを検索
            do
            {
            CONTINUE:
                ;
                char c = strText[textPos--];

                if (c == '>')
                {
                    int tailpos = textPos;
                    while (true)
                    {
                        if (textPos < 0)
                        {
                            textPos = 0;
                            throw new YanesdkException(this, "タグが閉じられていない");
                        }
                        char wc = strText[textPos];
                        if (wc == '<')
                        {
                            String tag = strText.Substring(textPos + 1, tailpos - textPos);
                            if (tag == "HR" || tag == "hr")
                            {
                                return textPos;
                            }
                            else
                            {
                                goto CONTINUE;
                            }
                        }
                        textPos--;
                    }
                }

            } while (textPos >= 0);

            textPos = 0;
            return 0;
        }
        /// バックログ用のフラグを戻す
        public void ResetBackLogFlg()
        {
            backTextFlg = false;
        }

    }

    /// <summary>
    /// シナリオを解析し、データに変換する
    /// </summary>
    public class ScenarioParser : IDisposable
    {
        /// <summary>
        /// 表示すべき文字画像情報を保持すデータクラス
        /// </summary>
        public class DrawLetter : ILetterDeta
        {
            private ITexture texture;	//!< 	文字はテクスチャー
            private float size = 1.0f;	//!<	基準値に比する倍率
            private Color4ub color = YanesdkUtil.WHITE_COLOR;		//!<	描画する色
            private Position pos = new Position();		//!<	描画する文字の描画ポジション
            private List<String> tags = new List<string>();		//!<	その位置に書かれていたタグ(色指定・改行指定等は取り除かれる)
            private List<ILetterDeta> rubi = new List<ILetterDeta>();		//!<    その文字に付帯するルビ文字
            private char letter;			//!<	テクスチャにした文字
            private int angle;

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

            /// <summary>
            /// シャローコピーでかえす。
            /// イメージオブジェクトはただの参照です。
            /// </summary>
            /// <returns></returns>
            public ILetterDeta Clone()
            {
                DrawLetter instance = new DrawLetter();
                instance.Texture = this.texture;
                instance.Size = this.size;
                instance.Color = this.color;
                instance.Pos.X = this.pos.X;
                instance.Pos.Y = this.pos.Y;
                instance.Tags = this.Tags;
                instance.Letter = this.letter;
                instance.Angle = this.angle;

                for (int i = 0; i < rubi.Count; i++)
                {
                    instance.RubiChara.Add(rubi[i].Clone());
                }

                return instance;
            }

            /// <summary>
            /// コピーコンストラクタ
            /// ただし、テクスチャのデータはコピーしないので
            /// 実質的なコピー元とコピー先の寿命は同一と思って使うこと
            /// </summary>
            /// <param name="drawChar"></param>
            public DrawLetter(DrawLetter drawChar)
            {
                this.texture = drawChar.texture;
                this.size = drawChar.size;
                this.color = drawChar.color;
                this.pos.X = drawChar.pos.X;
                this.pos.Y = drawChar.pos.Y;
                this.tags = drawChar.Tags;
                this.letter = drawChar.letter;
                this.angle = drawChar.Angle;
            }

            public ITexture Texture
            {
                get { return texture; }
                set { texture = value; }
            }

            public virtual Object ImgObj
            {
                get { return texture; }
                set { texture = value as ITexture; }
            }

            public virtual float ImgObjWidth
            {
                get { return texture.Width; }
            }

            public virtual float ImgObjHeight
            {
                get { return texture.Height; }
            }

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

            /// <summary>
            /// 文字角度
            /// 必ず0 - 511 の範囲
            /// </summary>
            public int Angle
            {
                get { return angle; }
                set { angle = value % 512; }
            }

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

            public List<String> Tags
            {
                get { return tags; }
                set { tags = value; }
            }

            public List<ILetterDeta> RubiChara
            {
                get { return rubi; }
                set { rubi = value; }
            }

            public char Letter
            {
                get { return letter; }
                set { letter = value; }
            }

            public Position Pos
            {
                get { return pos; }
                set
                {
                    // コピーせなあかん...
                    pos = new Position(value.X, value.Y);
                }
            }
        }

        /// <summary>
        /// デフォルトのタグ以外の意味のタグを保持するデータクラス
        /// </summary>
        public struct UnknownTagInfo
        {
            private String tag;
            /// <summary>
            /// タグの文字列
            /// </summary>
            public String Tag
            {
                get { return tag; }
                set { tag = value; }
            }
            private int pos;
            /// <summary>
            /// 出現位置
            /// </summary>
            public int Pos
            {
                get { return pos; }
                set { pos = value; }
            }
        }

        /// <summary>
        /// シナリオでの選択肢情報を保持するクラス
        /// </summary>
        public struct SelectTagInfo
        {
            private static int pos;		//!< 通常選択肢は連続して配置される。従って表示位置はクラス変数とする

            public static int Pos
            {
                get { return SelectTagInfo.pos; }
                set { SelectTagInfo.pos = value; }
            }
            Textures texture;	//!< 選択肢文字列テクスチャ

            public Textures Texture
            {
                get { return texture; }
                set { texture = value; }
            }
            int x;

            public int X
            {
                get { return x; }
                set { x = value; }
            }
            int y;

            public int Y
            {
                get { return y; }
                set { y = value; }
            }
            int width;		//!< 文字列の幅

            public int Width
            {
                get { return width; }
                set { width = value; }
            }
            int height;		//!< 文字列の高さ

            public int Height
            {
                get { return height; }
                set { height = value; }
            }
            String nextSceneId;	//!< 選択後の遷移先

            public String NextSceneId
            {
                get { return nextSceneId; }
                set { nextSceneId = value; }
            }
            Color4ub color;		//!<	描画する色

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

        /// <summary>
        /// フォント情報を保持するデータクラス
        /// </summary>
        internal class FontInfo
        {
            private float size = 1.0f;	//!< フォントのサイズ
            /// <summary>
            /// フォントサイズ
            /// </summary>
            public float Size
            {
                get { return size; }
                set { size = value; }
            }
            private Color4ub color = YanesdkUtil.WHITE_COLOR; 		//!< 文字色

            /// <summary>
            /// フォントカラー
            /// </summary>
            public Color4ub Color
            {
                get { return color; }
                set { color = value; }
            }
        }

        #region 定数値

        private static readonly String FONT_TAG_SIZE = "size=";
        private static readonly String FONT_TAG_COLOR = "color=";

        //	どのタグに該当するかを調べる
        private static readonly String[] DEF_TAGS = {
					    "br", 		// 改行
					    "space", 	// 空白行
					    "rubi",		// ルビ
                        //"select",	// 選択肢
                        "",
					    "font",		// フォント開始
					    "/font"		// フォント終了
				    };

        #endregion

        # region メンバフィールド

        // 禁則対象文字セット
        private static readonly String prohibitionChar = "。、」ァィゥェォャュョッぁぃぅぇぉっゃゅょ！？";
        private static readonly String VARTICAL_LETTER = "「」ー〜（）『』【】《》{}［］";
        private static readonly String VARTICAL_AJUST_LETTER = "、。";

        private FontRepository textFontRepository; 		//	文字フォント
        private FontRepository rubifontrep;		// ルビフォント
        private FontRepository backlogFontRep;	// バックログ用フォント

        private String pageText;				//	設定されている文字
        private List<ILetterDeta> drawCharacter = new List<ILetterDeta>();		//	描画するテキスト
        private List<ILetterDeta> backLogDrawCharacter = new List<ILetterDeta>();		//	描画するテキスト
        private List<UnknownTagInfo> unknownTag = new List<UnknownTagInfo>();	// 未知タグの配列
        private List<SelectTagInfo> selectTagInfo = new List<SelectTagInfo>();	// 選択肢配列
        private List<FontInfo> fontInfos = new List<FontInfo>();	// フォント情報をスタックする

        private bool m_useRubi = true;	//!< ルビを使用するか

        private int textPosOrg;			//!< バックログ用待避
        private int headerTextPosOrg;	//!< バックログ用待避
        private String textOrg;
        private bool backLogMode;

        private bool parseFinish;

        private ScenarioDrawContext scenarioDrawContext;	// コンテクスト
        private bool adjust;	// 調整フラグ
        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public ScenarioParser()
        {
            fontInfos.Add(new FontInfo());
        }

        /// <summary>
        /// リソースの破棄
        /// </summary>
        public void Dispose()
        {
            YamalibUtility.Dispose(textFontRepository);
            YamalibUtility.Dispose(rubifontrep);
            YamalibUtility.Dispose(backlogFontRep);
        }

        public void SetScenarioDrawContext(ScenarioDrawContext v)
        {
            // 現在の状態は初期化しておこう
            drawCharacter.Clear();
            unknownTag.Clear();
            selectTagInfo.Clear();
            backLogDrawCharacter.Clear();


            // デフォルトフォントとして色を設定
            fontInfos[0].Color = v.TextColor;
            scenarioDrawContext = v;
        }
        public ScenarioDrawContext GetScenarioDrawContext()
        {
            return scenarioDrawContext;
        }

        public void SetTextOffset(int pos)
        {
            scenarioDrawContext.TextOffsetPos = pos;
        }

        public int GetTextOffset()
        {
            if (backLogMode)
            {
                return this.textPosOrg;
            }
            return scenarioDrawContext.TextOffsetPos;
        }

        public int GetHeadTextOffset()
        {
            if (backLogMode)
            {
                return this.headerTextPosOrg;
            }
            return scenarioDrawContext.PageHeadTextOffset;
        }

        public FontRepository TextFontRepository
        {
            get { return textFontRepository; }
            set { textFontRepository = value; }
        }

        public FontRepository RubiFontRepository
        {
            get { return rubifontrep; }
            set { rubifontrep = value; }
        }

        public FontRepository BacklogFontRepository
        {
            get { return backlogFontRep; }
            set { backlogFontRep = value; }
        }

        public List<SelectTagInfo> SelectTagInfos
        {
            get { return selectTagInfo; }
        }

        public List<UnknownTagInfo> UnknownTags
        {
            get { return unknownTag; }
        }

        public List<ILetterDeta> DrawCharacterData
        {
            get { return drawCharacter; }
        }

        public List<ILetterDeta> BackLogDrawCharacter
        {
            get { return backLogDrawCharacter; }
        }

        /// <summary>
        /// シナリオ解析を実行する
        /// </summary>
        /// <returns></returns>
        public bool UpdateText()
        {
            return UpdateText(false);
        }

        /// <summary>
        /// 前のページを表示使用とする場合に、こちらを呼べば、前画面のシナリオを解析する
        /// </summary>
        /// <returns></returns>
        public bool UpdateTextBack()
        {
            return UpdateText(true);
        }

        /// ルビを使用する
        public void EnableRubiText()
        {
            m_useRubi = true;
        }

        /// ルビを使用しない
        public void DisenableRubiText()
        {
            m_useRubi = false;
        }

        /// <summary>
        /// 全てパースし終えたか
        /// </summary>
        public bool IsParseFinish
        {
            get { return parseFinish; }
            set { parseFinish = value; }
        }

        /* バックログ位置を設定する */
        public void SetBackLogMode(bool backMode)
        {
            if (!backLogMode && backMode)
            {
                // on 要請
                textPosOrg = scenarioDrawContext.TextOffsetPos;
                headerTextPosOrg = scenarioDrawContext.PageHeadTextOffset;
                textOrg = GetText();
                backLogMode = true;
            }
            else if (backLogMode && !backMode)
            {
                // off 要請
                scenarioDrawContext.TextOffsetPos = textPosOrg;
                scenarioDrawContext.PageHeadTextOffset = headerTextPosOrg;
                scenarioDrawContext.ResetBackLogFlg();
                backLogMode = false;
            }
        }

        ///	テキストの取得
        /**
            設定してあったテキストの取得。ここで取得したものに追加して
            再度setTextを呼び出すなどしても良い。
        */
        public String GetText()
        {
            if (backLogMode)
            {
                return textOrg;
            }
            return pageText;
        }

        ///	文字列の描画
        /**
            Color4ubを指定しておけば、その色に変移させたものが描画される
        */
        public static void ScenarioOnPaint(IScreen dst, List<ILetterDeta> src, int x, int y)
        {
            foreach (DrawLetter d in src)
            {
                dst.SetColor(d.Color);
                if (d.Angle != 0 || d.Size != 1.0f)
                {
                    dst.BltRotate(d.Texture, (int)(d.Pos.X + x), (int)(d.Pos.Y + y), d.Angle, d.Size, 0);
                }
                else
                {
                    dst.Blt(d.Texture, (int)(d.Pos.X + x), (int)(d.Pos.Y + y));
                }
            }
        }

        public static void ScenarioOnPaint(IScreen dst, List<ILetterDeta> src, int x, int y, Color4ub color)
        {
            foreach (DrawLetter d in src)
            {
                dst.SetColor(color);
                if (d.Angle != 0 || d.Size != 1.0f)
                {
                    dst.BltRotate(d.Texture, (int)(d.Pos.X + x), (int)(d.Pos.Y + y), d.Angle, d.Size, 0);
                }
                else
                {
                    dst.Blt(d.Texture, (int)(d.Pos.X + x), (int)(d.Pos.Y + y));
                }
            }
        }

        ///	文字列の描画
        /**
            Color4ubを指定しておけば、その色に変移させたものが描画される
        */
        public void OnPaint(IScreen dst, int x, int y)
        {
            ScenarioOnPaint(dst, DrawCharacterData, x, y);
        }

        public void OnPaint(IScreen dst, int x, int y, Color4ub color)
        {
            ScenarioOnPaint(dst, DrawCharacterData, x, y, color);
        }


        /// <summary>
        /// バックログと通常描画では、FontRepositoryを切り替える。
        /// そうしないと、通常　→ バックログから通常モードに復元したときに
        /// リポジトリが変更されているために、表示できない文字がでてくる。
        /// </summary>
        /// <returns></returns>

        /// <summary>
        /// 禁則文字化どうかを調査する
        /// </summary>
        /// <param name="c_"></param>
        /// <returns></returns>
        private bool IsProhibition(char letter)
        {
            foreach (char c in prohibitionChar)
            {
                if (c == letter)
                {
                    //Console.WriteLine("prohibition : {0}", letter);
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// フォントタグを解析し、FontInfoを生成する
        /// </summary>
        /// <param name="tagPram"></param>
        /// <returns></returns>
        private static FontInfo CreateFontTagInfo(String[] tagPram)
        {
            FontInfo fontInfo = new FontInfo();
            if (null == tagPram || 1 >= tagPram.Length)
            {
                return fontInfo;
            }

            for (int i = 1; i < tagPram.Length; ++i)
            {
                if (tagPram[i].StartsWith(FONT_TAG_SIZE))
                {
                    // size指定
                    fontInfo.Size = (float)Convert.ToDecimal(GetFontTagPramValue(tagPram[i]));
                }
                else if (tagPram[i].StartsWith(FONT_TAG_COLOR))
                {
                    // color指定
                    fontInfo.Color = YanesdkUtil.ToColor4ub(GetFontTagPramValue(tagPram[i]));
                }
            }
            return fontInfo;
        }

        /// <summary>
        /// フォントタグの属性値を取得する
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private static String GetFontTagPramValue(String str)
        {
            return str.Split('=')[1].Trim(' ', '"');
        }

        /// <summary>
        /// このパーサで有効なタグ一覧
        /// </summary>
        public virtual String[] EnableTags
        {
            get { return DEF_TAGS; }
        }

        /// <summary>
        /// ルビ用のDrawCharとして初期されたインスタンスを返却する
        /// </summary>
        /// <returns></returns>
        private ILetterDeta CreateRubiDrawChar()
        {
            ILetterDeta dc = CreateDrawLetter();
            if (!backLogMode)
            {
                dc.Color = scenarioDrawContext.TextColor;
            }
            else
            {
                dc.Color = scenarioDrawContext.BackLogTextColor;
            }
            return dc;
        }

        /// <summary>
        /// シナリオを解析し、データを保持する
        /// </summary>
        /// <param name="back"></param>
        /// <returns></returns>
        private bool UpdateText(bool back)
        {
            // <HR> まで探す
            if (!back)
            {
                pageText = scenarioDrawContext.GetNextText();
                if (null == pageText)
                {
                    parseFinish = true;
                    return false;
                }
            }
            else
            {
                pageText = scenarioDrawContext.GetPreText();
                if (null == pageText)
                {
                    return false;
                }
            }

            InitializeForNewPage();

            int currentPos = 0; 		// 解析ポジション
            float nowLineHeight = 0;	//	このラインの高さ
            Position nextDrawPt = new Position();		//	現在の描画位置
            int lineStartIndex = 0;		//	行の開始文字のdracharのindex

            do
            {
                char letter = GetNextLetter(ref currentPos);
                if (IsStartTag(letter))
                {
                    AnalyzeTag(ref currentPos, nextDrawPt, ref nowLineHeight, ref lineStartIndex);
                    continue;
                }

                // 無効な文字ならスキップ
                if (IsInvalidLetter(letter)) continue;

                Object letterTexture = GetLetterImg(letter);
                if (null == letterTexture)
                {
                    // なんだこの文字は
                    continue;
                }

                ILetterDeta newDrawChar = CreateDrawChar(currentPos, ref nowLineHeight, nextDrawPt, ref lineStartIndex, letter, letterTexture);

                if (!backLogMode)
                {
                    drawCharacter.Add(newDrawChar);
                }
                else
                {
                    backLogDrawCharacter.Add(newDrawChar);
                }
            } while (currentPos < pageText.Length);

            return true;
        }

        /// <summary>
        /// 新しい頁を開始するにあたって、変数を初期化する
        /// </summary>
        protected virtual void InitializeForNewPage()
        {
            if (!backLogMode)
            {
                drawCharacter.Clear();
                unknownTag.Clear();
                selectTagInfo.Clear();
                SelectTagInfo.Pos = int.MinValue;
            }
            else
            {
                backLogDrawCharacter.Clear();
            }
        }

        /// <summary>
        /// 制御コードなのシナリオに無効な文字かどうか？
        /// </summary>
        /// <param name="letter"></param>
        /// <returns></returns>
        protected static bool IsInvalidLetter(char letter)
        {
            return letter == '\t' || letter == '\n' || letter == '\r';
        }

        /// <summary>
        /// タグのスタートか
        /// </summary>
        /// <param name="letter"></param>
        /// <returns></returns>
        protected static bool IsStartTag(char letter)
        {
            return letter == '<';
        }

        /// <summary>
        /// 次の文字を取得する
        /// </summary>
        /// <param name="currentPos"></param>
        /// <returns></returns>
        protected virtual char GetNextLetter(ref int currentPos)
        {
            return pageText[currentPos++];
        }

        /// <summary>
        /// 認識できないタグ
        /// </summary>
        /// <param name="tagStr"></param>
        /// <param name="position"></param>
        protected virtual void UnknownTag(String tagStr, int position)
        {
            //	認識できないタグなのでタグリストに追加
            UnknownTagInfo uti = new UnknownTagInfo();
            uti.Tag = tagStr;
            uti.Pos = position;
            unknownTag.Add(uti);
        }

        /// <summary>
        /// 現在のコンテクストから、文字画像情報を生成し返却する
        /// </summary>
        /// <param name="currentPos"></param>
        /// <param name="nowLineHeight"></param>
        /// <param name="nextDrawPt"></param>
        /// <param name="lineStartIndex"></param>
        /// <param name="letter"></param>
        /// <param name="letterTexture"></param>
        /// <returns></returns>
        private ILetterDeta CreateDrawChar(int currentPos, ref float nowLineHeight, Position nextDrawPt, ref int lineStartIndex, char letter, Object letterTexture)
        {
            // フォントサイズで拡縮した後のサイズ
            float charRate = fontInfos[fontInfos.Count - 1].Size;
            float charImgWidth = GetImgObjWidth(letterTexture) * charRate;
            float charImgHeight = GetImgObjHeight(letterTexture) * charRate;
            ILetterDeta newDrawChar = CreateDrawLetter();
            newDrawChar.Letter = letter;
            {
                if (scenarioDrawContext.Vartical)
                {
                    // 縦書き
                    if ((nextDrawPt.Y > scenarioDrawContext.DrawWidth) && !IsProhibition(letter))
                    {
                        nextDrawPt.X -= (nowLineHeight + scenarioDrawContext.BlankHeight);
                        nextDrawPt.Y = 0;
                        nowLineHeight = 0;
                        lineStartIndex = currentPos;
                        adjust = false;
                    }

                    newDrawChar.ImgObj = letterTexture;
                    newDrawChar.Color = fontInfos[fontInfos.Count - 1].Color;	// フォントタグで指定されている色
                    newDrawChar.Size = charRate;	// フォントタグで指定されているサイズ
                    newDrawChar.Pos = nextDrawPt;
                    if (IsRotateLetterWithVartical(letter))
                    {
                        newDrawChar.Angle = 128;
                    }
                    if (IsAjustLetterWithVartical(letter))
                    {
                        newDrawChar.Pos.X += newDrawChar.ImgObjWidth / 2;
                        newDrawChar.Pos.Y -= newDrawChar.ImgObjHeight / 2;
                    }

                    nextDrawPt.Y += charImgHeight + scenarioDrawContext.CharacterInterval;
                    if (nowLineHeight < charImgWidth)
                    {
                        //	このラインのベース位置が変わるので、この差の分、
                        //	加算する必要がある。
                        float d = charImgWidth - nowLineHeight;
                        for (int i = lineStartIndex; i < drawCharacter.Count; ++i)
                        {
                            drawCharacter[i].Pos.X -= d;
                        }
                        nowLineHeight = charImgWidth;
                    }

                }
                // 横書き
                else
                {
                    // 禁則文字ではなく、描画位置が指定範囲を超えていれば改行する
                    if ((nextDrawPt.X > scenarioDrawContext.DrawWidth) && !IsProhibition(letter))
                    {
                        // 改行
                        nextDrawPt.X = 0;
                        nextDrawPt.Y += nowLineHeight + scenarioDrawContext.BlankHeight;
                        nowLineHeight = 0;
                        lineStartIndex = currentPos;
                        adjust = false;
                    }

                    newDrawChar.ImgObj = letterTexture;
                    newDrawChar.Color = fontInfos[fontInfos.Count - 1].Color;	// フォントタグで指定されている色
                    newDrawChar.Size = charRate;	// フォントタグで指定されているサイズ
                    newDrawChar.Pos = nextDrawPt;

                    nextDrawPt.X += charImgWidth + scenarioDrawContext.CharacterInterval;
                    if (nowLineHeight < charImgHeight)
                    {
                        //	このラインのベース位置が変わるので、この差の分、
                        //	この行全体に加算する必要がある。
                        float d = charImgHeight - nowLineHeight;
                        for (int i = lineStartIndex; i < drawCharacter.Count; ++i)
                        {
                            drawCharacter[i].Pos.Y += d;
                        }
                        nowLineHeight = charImgHeight;
                    }
                }
            }

            // バックログモードであれば強制的にいろを書き換える
            if (backLogMode)
            {
                newDrawChar.Color = scenarioDrawContext.BackLogTextColor;
            }

            return newDrawChar;
        }

        /// <summary>
        /// 縦書きの時回転させる文字かどうか
        /// </summary>
        /// <param name="letter"></param>
        /// <returns></returns>
        private static bool IsRotateLetterWithVartical(char letter)
        {
            return VARTICAL_LETTER.IndexOf(letter) >= 0;
        }

        /// <summary>
        /// 縦書きの時に表示位置を調整する必要がある文字か
        /// </summary>
        /// <param name="letter"></param>
        /// <returns></returns>
        private static bool IsAjustLetterWithVartical(char letter)
        {
            return VARTICAL_AJUST_LETTER.IndexOf(letter) >= 0;
        }

        /// <summary>
        /// タグの解析を行う
        /// </summary>
        /// <param name="pos"></param>
        /// <param name="nextDrawPt"></param>
        /// <param name="nowLineHeight"></param>
        /// <param name="lineStartIndex"></param>
        /// <returns></returns>
        private bool AnalyzeTag(ref int currentPos, Position nextDrawPt, ref float nowLineHeight, ref int lineStartIndex)
        {
            //	タグの取得
            //	前方へ '>'をサーチ
            String tag = GetTagString(ref currentPos);
            // 次の文字に進めておく
            currentPos++;

            // 分割、空白除去、小文字かをおこなう
            String[] tagParam = SplitTag(tag);
            String tagStr = tagParam[0];
            int found = -1; // not found marker
            for (int i = 0; i < EnableTags.Length; ++i)
            {
                if (tagStr == EnableTags[i])
                {
                    found = i;
                    break;
                }
            }

            if (found == -1)
            {
                //	認識できないタグなのでタグリストに追加
                UnknownTag(tag, drawCharacter.Count);
                return true;
            }

            //	このタグの処理
            switch (found)
            {
                case 0: // <BR> : 行送り処理
                    if (scenarioDrawContext.Vartical)
                    {
                        if (nextDrawPt.Y == 0)
                        {
                            // これは空行とみなす
                            nextDrawPt.X -= scenarioDrawContext.BlankLineHeight;
                            break;
                        }
                        nextDrawPt.Y = 0;
                        nextDrawPt.X -= (nowLineHeight + scenarioDrawContext.BlankHeight);
                        nowLineHeight = 0;
                        lineStartIndex = currentPos;
                        adjust = false;
                    }
                    else
                    {
                        if (nextDrawPt.X == 0)
                        {
                            // これは空行とみなす
                            nextDrawPt.Y += scenarioDrawContext.BlankLineHeight;
                            break;
                        }
                        nextDrawPt.X = 0;
                        nextDrawPt.Y += (nowLineHeight + scenarioDrawContext.BlankHeight);
                        nowLineHeight = 0;
                        lineStartIndex = currentPos;
                        adjust = false;
                    }
                    break;

                case 1:	//<space X>
                    int space = Convert.ToInt32(tagParam[1]);
                    nextDrawPt.X = 0;
                    nextDrawPt.Y += (nowLineHeight * space) / 2;
                    nowLineHeight = 0;
                    lineStartIndex = currentPos;
                    adjust = false;
                    break;

                case 2:	// <RubiChara,X,str>
                    //					    Log.print("RUBI TAG");
                    if (!m_useRubi)
                    {
                        break;
                    }

                    int backNum = (int)Convert.ToInt32(tagParam[1]);
                    String moji = tagParam[2];
                    // 指定チェック
                    if ((backNum == -1) || (moji.Length == 0) || (drawCharacter.Count < backNum)) break;

                    // ルビ文字テクスチャの生成
                    List<Object> tt = new List<Object>();
                    int i = 0, j = 0;
                    for (i = 0; i < moji.Length; ++i)
                    {
                        tt.Add(GetRubiLetterImg(moji[i]));
                    }

                    // ルビの大きさを取得
                    int tWidth = (int)GetImgObjWidth(tt[0]);
                    int tHeight = (int)GetImgObjWidth(tt[0]);

                    // １文字あたりのルビ付帯数
                    float perChar = moji.Length / backNum;
                    float rubiRest = perChar;
                    int index = drawCharacter.Count - backNum;

                    for (i = 0; i < tt.Count && index < drawCharacter.Count; ++i)
                    {
                        for (; rubiRest >= 1.0 && j < tt.Count; j++, rubiRest -= 1.0f)
                        {
                            ILetterDeta dc = CreateRubiDrawChar();
                            dc.ImgObj = tt[j];
                            drawCharacter[index].RubiChara.Add(dc);
                        }
                        index++;
                        rubiRest += perChar;
                    }
                    if (j < tt.Count)
                    {
                        for (i = j; i < tt.Count; ++i)
                        {
                            ILetterDeta dc = CreateRubiDrawChar();
                            dc.ImgObj = tt[i];
                            drawCharacter[index - 1].RubiChara.Add(dc);
                        }
                    }

                    // 均等割付を行う
                    index = drawCharacter.Count - backNum;

                    // まず連結したルビ文字列の長さを算出
                    int sumWidthRubi = 0;
                    int sumWidth = 0;
                    for (j = index; j < drawCharacter.Count; ++j)
                    {
                        sumWidth += (int)drawCharacter[j].ImgObjWidth;
                        // さらにここで行間マージンを加算
                        sumWidth += scenarioDrawContext.CharacterInterval * (backNum - 1);

                        // ルビの連結後の横幅を取得
                        foreach (ILetterDeta rubiChara in drawCharacter[j].RubiChara)
                        {
                            sumWidthRubi += (int)rubiChara.ImgObjWidth;
                        }
                    }

                    int moji_len = moji.Length;
                    int dx, ox;
                    // 一文字あたりにあける間隔
                    int widthPerChar = 0;
                    // もし、ルビ文字の数が、親文字に対して２倍でなければ半角分ずらす必要あり
                    bool posAdjust = (bool)(moji.Length != backNum * 2);

                    if (sumWidth >= sumWidthRubi)
                    {
                        // ルビ文字列の長さより、親文字のほうが大きい
                        widthPerChar = sumWidth - sumWidthRubi;
                        ox = sumWidth / moji_len;
                        dx = (int)drawCharacter[index].Pos.X;
                    }
                    else
                    {
                        // ルビ文字列の長さより、親文字のほうが小さい
                        widthPerChar = sumWidthRubi - sumWidth;
                        dx = widthPerChar / 2;
                        //ox = (int)(drachar[index].RubiChara[0].Texture.GetWidth()/2);
                        ox = 0;
                    }

                    // ルビ親文字が、ルビ中に改行されているかもしれない
                    int newLinePos = -1; // not found marker
                    // 振り付け文字の最初のインデックス
                    int target = drawCharacter.Count - backNum;
                    int baseY = (int)drawCharacter[target].Pos.Y;
                    for (i = 0; i < backNum; ++i, ++target)
                    {
                        if (baseY != (int)drawCharacter[target].Pos.Y)
                        {
                            // 描画位置が変更になっていれ改行やで...
                            newLinePos = i;
                            break;
                        }
                    }

                    // 親文字ごと
                    for (i = index; i < drawCharacter.Count; ++i)
                    {
                        if (sumWidth < sumWidthRubi && i > index)
                        {
                            // ルビ文字のほうが横幅をとるなら、前の文字のルビから、オフセット位置を算出
                            List<ILetterDeta> rubi = drawCharacter[i - 1].RubiChara;
                            ox = (int)(rubi[rubi.Count - 1].Pos.X - drawCharacter[i].Pos.X) + dx + tWidth;
                        }

                        if (i - index == newLinePos)
                        {
                            // ここで改行はいりやがった！
                            dx = 0;
                        }

                        // ルビ一文字ごと
                        for (j = 0; j < drawCharacter[i].RubiChara.Count; ++j)
                        {

                            if (sumWidth >= sumWidthRubi)
                            {
                                // ルビ文字列の長さより、親文字のほうが大きい
                                drawCharacter[i].RubiChara[j].Pos.X = dx;
                                if (posAdjust)
                                {
                                    drawCharacter[i].RubiChara[j].Pos.X += tWidth / 2;
                                }
                                drawCharacter[i].RubiChara[j].Pos.Y = drawCharacter[i].Pos.Y;
                                dx += ox;

                                //								    debug {
                                //									    Log.print("i = %s,j = %s,X = %s,ox = %s\n",i,j,drachar[i].rubi[j].Pos.X,ox);
                                //								    }

                            }
                            else
                            {
                                // ルビ文字列の長さより、親文字のほうが小さい
                                drawCharacter[i].RubiChara[j].Pos.X = drawCharacter[i].Pos.X - dx + ox;
                                drawCharacter[i].RubiChara[j].Pos.Y = drawCharacter[i].Pos.Y;
                                int rubiWidth = (int)drawCharacter[i].RubiChara[j].ImgObjWidth;
                                ox += rubiWidth;
                            }

                            if (adjust)
                            {
                                drawCharacter[i].RubiChara[j].Pos.Y -= tHeight;
                            }
                        }
                    }

                    // 改行ルビ付けなら、前の行にすでにルビがあったかどうか
                    // 行頭１文字で明示改行したら、これは正しく動作しない
                    bool bPreLineRubied = false;
                    if (-1 != newLinePos)
                    {
                        int preLineEnd = drawCharacter.Count - backNum - 1;
                        int preY = (int)drawCharacter[preLineEnd].Pos.Y;

                        // 前行分についてルビが振られているか調べる
                        while (preLineEnd >= 0 && drawCharacter[preLineEnd].Pos.Y == preY)
                        {
                            if (drawCharacter[preLineEnd].RubiChara.Count != 0)
                            {
                                bPreLineRubied = true;
                                break;
                            }

                            preY = (int)drawCharacter[preLineEnd].Pos.Y;
                            --preLineEnd;
                        }
                    }

                    //					    Log.print("bPreLineRubied %s", bPreLineRubied);

                    // 行間調整
                    int end = drawCharacter.Count - 1;
                    int ly = (int)drawCharacter[end].Pos.Y;
                    // 改行ルビであれば、前の分と今の行、２つ分のスペースを取る必要がある
                    int spaceRate = ((-1 != newLinePos) && !bPreLineRubied) ? 2 : 1;

                    if (drawCharacter[index].Pos.Y != 0 && !adjust)
                    {

                        int loopCnt = 0;
                        bool rubiAdust = false;
                        while (end >= 0 && (drawCharacter[end].Pos.Y == ly || end >= index))
                        {

                            // もしルビ中改行であったら、改行の後分だけいい
                            if (-1 != newLinePos)
                            {
                                if (loopCnt == backNum - newLinePos)
                                {
                                    rubiAdust = true;
                                }
                            }

                            if (rubiAdust)
                            {

                                // ルビ改行対応、前行の処理
                                if (bPreLineRubied)
                                {
                                    // 前の行にもルビがあって、すでに行間はあけられている
                                    foreach (ILetterDeta dc in drawCharacter[end].RubiChara)
                                    {
                                        dc.Pos.Y -= tHeight;
                                    }
                                }

                            }
                            else
                            {
                                ly = (int)drawCharacter[end].Pos.Y;
                                drawCharacter[end].Pos.Y += (tHeight * spaceRate);

                                // 改行ルビで前行の行間処理がされていなければ、自分の位置もそれ分、
                                // 追加でさげなければならない
                                if (((-1 != newLinePos) && !bPreLineRubied))
                                {
                                    foreach (ILetterDeta dc in drawCharacter[end].RubiChara)
                                    {
                                        dc.Pos.Y += tHeight;
                                    }
                                }
                            }
                            end--;
                            loopCnt++;
                        }

                        // 改行ルビで前の行が未調整なら、前の行の行間をさらに確保
                        if (-1 != newLinePos && !bPreLineRubied)
                        {
                            end = index + (newLinePos - 1);
                            ly = (int)drawCharacter[end].Pos.Y;

                            while (end >= 0 && drawCharacter[end].Pos.Y == ly)
                            {
                                ly = (int)drawCharacter[end].Pos.Y;
                                drawCharacter[end].Pos.Y += tHeight;
                                --end;
                            }
                        }

                        nextDrawPt.Y += (tHeight * spaceRate);
                        adjust = true;

                    }
                    else if (drawCharacter[index].Pos.Y == 0)
                    {
                        // こっちは既に、この行にルビをつけるための行間が設定済み
                        for (i = index; i < drawCharacter.Count; ++i)
                        {
                            foreach (ILetterDeta rubiChar in drawCharacter[i].RubiChara)
                            {
                                rubiChar.Pos.Y -= tHeight;
                            }
                        }
                    }
                    break;

                case 3:	// <select,str,str>
                    if (null == tagStr || 3 > tagParam.Length)
                    {
                        return false;
                    }
                    SelectTagInfo tagInfo = new SelectTagInfo();
                    String selectText = tagParam[1];
                    tagInfo.NextSceneId = tagParam[2];
                    if (null == tagInfo.NextSceneId)
                    {
                        return false;
                    }

                    if (SelectTagInfo.Pos < 0)
                    {
                        SelectTagInfo.Pos = drawCharacter.Count;
                    }

                    tagInfo.Texture = GetInnerFontRepository().GetTexture(selectText, 0);
                    tagInfo.Width = (int)tagInfo.Texture.Width;
                    tagInfo.Height = (int)tagInfo.Texture.Height;
                    tagInfo.X = (int)nextDrawPt.X;
                    tagInfo.Y = (int)nextDrawPt.Y;

                    nextDrawPt.X = 0;
                    nextDrawPt.Y += tagInfo.Height;

                    selectTagInfo.Add(tagInfo);
                    break;

                case 4: // <font>
                    //					    printf("----------------- find font tag ------------------\n");
                    fontInfos.Add(CreateFontTagInfo(tagParam));
                    break;

                case 5: // </font>
                    // pop

                    // 明示的なスタックがなければ、無視する
                    if (fontInfos.Count >= 2)
                    {
                        fontInfos.RemoveAt(fontInfos.Count - 1);
                        //						    fontInfos.Count = fontInfos.Count - 1; 
                    }
                    else
                    {
                        //						    Log.printWarn("</font> appeared before <font>");
                    }

                    break;
                default:
                    //					    assert(false);
                    break;
            }

            return true;
        }

        /// <summary>
        /// 「,」セパレータでタグを分割し、空白を取り除きかつ小文字かして返却する
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        protected static String[] SplitTag(String tag)
        {
            char[] sep = { ',' };
            String[] tagParam = tag.Split(sep);
            for (int i = 0; i < tagParam.Length; i++)
            {
                tagParam[i] = tagParam[i].Trim().ToLower();
            }
            return tagParam;
        }

        /// <summary>
        /// タグ文字を取得する
        /// </summary>
        /// <param name="currentPos"></param>
        /// <returns></returns>
        private String GetTagString(ref int currentPos)
        {
            int startpos = currentPos;
            while (true)
            {
                if (currentPos >= pageText.Length)
                {
                    throw new YanesdkException(this, "タグが閉じられていない");
                }
                char wc = pageText[currentPos];
                if (wc == '>')
                {
                    break;
                }
                currentPos++;
            }
            return pageText.Substring(startpos, currentPos - startpos);
        }

        protected virtual ILetterDeta CreateDrawLetter()
        {
            return new DrawLetter();
        }

        protected virtual Object GetLetterImg(char c)
        {
            return GetInnerFontRepository().GetTexture(c, 0);
        }

        protected virtual Object GetRubiLetterImg(char c)
        {
            return RubiFontRepository.GetTexture(c, 0);
        }

        protected virtual float GetImgObjWidth(Object imgObj)
        {
            return ((ITexture)imgObj).Width;
        }

        protected virtual float GetImgObjHeight(Object imgObj)
        {
            return ((ITexture)imgObj).Height;
        }

        /// <summary>
        /// バックログと通常描画では、FontRepositoryを切り替える。
        /// そうしないと、通常　→ バックログから通常モードに復元したときに
        /// リポジトリが変更されているために、表示できない文字がでてくる。
        /// </summary>
        /// <returns></returns>
        protected virtual FontRepository GetInnerFontRepository()
        {
            return backLogMode ? backlogFontRep : TextFontRepository;
        }
    }

    /// <summary>
    /// 文字画像データをSurfaceにて実装されているScenarioParser
    /// </summary>
    public class ScenarioParserSurface : ScenarioParser
    {
        /// <summary>
        /// 描画文字のデータクラス(Surface版)
        /// </summary>
        public class DrawLetterSurface : ScenarioParser.DrawLetter
        {
            #region メンバフィールド

            Surface surface;

            #endregion

            public Surface Surface
            {
                get { return surface; }
                set { surface = value; }
            }

            public override Object ImgObj
            {
                get
                {
                    return Surface;
                }
                set
                {
                    Surface = value as Surface;
                }
            }

            public override float ImgObjWidth
            {
                get
                {
                    return Surface.Width;
                }
            }

            public override float ImgObjHeight
            {
                get
                {
                    return Surface.Height;
                }
            }

        }


        #region 定数値

        private static readonly string[] TAGS = {
		    "br", 		// 改行
		    "space", 	// 空白行
		    "rubi",		// ルビ
		    "******",	// 選択肢は無効化
		    "font",		// フォント開始
		    "/font"		// フォント終了
        };

        #endregion

        #region メンバフィールド

        private SurfaceFontRepository fontrep; 		//	文字フォント
        private SurfaceFontRepository rubifontrep;		// ルビフォント
        //private SurfaceFontRepository backlogFontRep;	// バックログ用フォント

        #endregion

        /// コンストラクタ
        public ScenarioParserSurface()
        {
            fontrep = new SurfaceFontRepository(null);
            rubifontrep = new SurfaceFontRepository(null);
        }

        ///	文字列の描画
        /**
            Color4ubを指定しておけば、その色に変移させたものが描画される
        */
        public void OnPaint(Surface dst, int x, int y)
        {
            ScenarioOnPaint(dst, base.DrawCharacterData, x, y);
        }
        ///	文字列の描画
        /**
            Color4ubを指定しておけば、その色に変移させたものが描画される
        */
        public static void ScenarioOnPaint(Surface dst, List<ILetterDeta> src, int x, int y)
        {
            foreach (ILetterDeta d in src)
            {
                DrawLetterSurface drawLetter = d as DrawLetterSurface;
                if (drawLetter == null)
                {
                    continue;
                }
                dst.Blt(drawLetter.Surface, (int)(drawLetter.Pos.X + x), (int)(drawLetter.Pos.Y + y), 0);
            }
        }

        public SurfaceFontRepository GetSurfaceFontRepository() { return fontrep; }
        public SurfaceFontRepository GetRubiSurfaceFontRepository() { return rubifontrep; }
        //public SurfaceFontRepository GetBackLogSurfaceFontRepository() { return backlogFontRep; }

        protected override ILetterDeta CreateDrawLetter()
        {
            return new DrawLetterSurface();
        }

        protected override Object GetLetterImg(char c)
        {
            return fontrep.GetSurface(c, 0);
        }

        protected override Object GetRubiLetterImg(char c)
        {
            return rubifontrep.GetSurface(c, 0);
        }

        protected override float GetImgObjWidth(Object imgObj)
        {
            return ((Surface)imgObj).Width;
        }
        protected override float GetImgObjHeight(Object imgObj)
        {
            return ((Surface)imgObj).Height;
        }

        /// 有効なタグを返却する
        public override string[] EnableTags
        {
            get { return TAGS; }
        }
    }

}
