using System;
using System.Collections.Generic;
using System.Text;
using Yanesdk.Draw;
using Yanesdk.Math;
using Yamalib.Util;

namespace Yamalib.Draw.Effect
{

    /// <summary>
    /// ランダムテキスト表示クラス
    /// 指定範囲を文字で埋め尽くし変わっていきます
    /// </summary>
    public class DizzyTextDraw
    {
        #region 定数値

        /// <summary>
        /// 半角カタカナ文字
        /// </summary>
        public readonly string hankana_str = "ｦｧｨｩｪｫｬｭｮｯｱｲｳｴｵｶｷｸｹｺｻｼｽｾｿﾀﾁﾂﾃﾄﾅﾆﾇﾈﾉﾊﾋﾌﾍﾎﾏﾐﾑﾒﾓﾔﾕﾖﾗﾘﾙﾚﾛﾜﾝ";

        /// <summary>
        /// 記号文字
        /// </summary>
        public readonly string mark_str = ":;<=>?@[]^_!\"#$%&'()*+,-./`{|}";

        /// <summary>
        /// 数字文字
        /// </summary>
        public readonly string number_str = "0123456789";

        /// <summary>
        /// アルファベット文字
        /// </summary>
        public readonly string alphabet_str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

        #endregion

        #region フィールドメンバ

        private string enable_str;	//!< 使用する文字すべてを連結した文字列

        private readonly List<string> rand_str = new List<string>();	//!< 描画中の文字列配列

        private FontRepository fr;	// 文字貯蔵庫
        private Rand rand;
        private Textures tv;	// 文字列を受け取る
        private Rect drawrect;		//!< 表示する矩形

        private RootCounterS alpha;

        private int posx, posy;		//!< 描画開始位置
        private bool blend;
        private bool hankana;
        private bool mark;
        private bool number;	//!< 使用する文字
        private byte r, g, b;		//!< 描画色
        private int fwidth, fheight;	//!< フォントの幅と高さ
        private int speed;		//!< 変更のタイミング
        private int flamecounter;	//!< フレームカウンタ

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public DizzyTextDraw()
        {
            // 文字貯蔵庫の生成
            fr = new FontRepository(YamalibConst.FONT_REP_TEXTURE_FACTORY);
            fr.Max = 300;		// とりあえず 300 ぐらいか？

            rand = new Rand();
            rand.Randomize();

            alpha = new RootCounterS();
            alpha.Set(255, 255, 0);	// 無効

            enable_str += alphabet_str;
            enable_str += number_str;
            enable_str += mark_str;
            enable_str += hankana_str;

            blend = true;

            // 使用する文字
            hankana = true;
            mark = true;
            number = true;
        }

        public FontRepository FontRepository
        {
            get { return fr; }
            set { fr = value; }
        }

        public bool EnableHankana
        {
            get { return hankana; }
            set { hankana = value; }
        }

        public bool EnableMarkLetter
        {
            get { return mark; }
            set { mark = value; }
        }

        public bool EnableNumberLetter
        {
            get { return number; }
            set { number = value; }
        }

        public bool EnableBlend
        {
            get { return blend; }
            set { blend = value; }
        }

        public void setFadeIn(int step)
        {
            int start = 0;
            if (!alpha.IsEnd)
            {
                start = alpha.Value();
            }
            alpha.Set(start, 255, step);
        }

        public void SetFadeOut(int step)
        {
            int start = 255;
            if (!alpha.IsEnd)
            {
                start = alpha.Value();
            }
            alpha.Set(start, 0, step);
        }

        public bool IsFade()
        {
            return !alpha.IsEnd;
        }

        /// 維持するフレーム数　大きいほど更新は遅い
        public void SetSpeed(int i)
        {
            if (i == 0) i = 1;
            speed = i;
        }

        /// 表示する矩形 nullで画面全体
        public void SetDrawRect(Rect rc)
        {
            if (rc == null)
            {
                drawrect = null;
            }
            else
            {
                drawrect = rc;
            }
        }

        public void SetColor(byte r, byte g, byte b)
        {
            this.r = r; this.g = g; this.b = b;
        }

        /// <summary>
        /// 描画処理
        /// </summary>
        /// <param name="screen"></param>
        public void OnPaint(IScreen screen)
        {
            int sx, sy;
            alpha++;
            // なんぢゃそりゃ...
            if (alpha.Value() <= 0) return;

            if (fwidth == 0 || fheight == 0)
            {
                // 平均文字幅と高さ
                Textures tv = FontRepository.GetTexture(enable_str, 0);
                fwidth = (int)(tv.Width / enable_str.Length);
                fheight = (int)tv.Height;
            }

            if (drawrect != null)
            {
                sx = (int)(drawrect.Width / fwidth);
                sy = (int)(drawrect.Height / fheight);
            }
            else
            {
                sx = screen.Width / fwidth;
                sy = screen.Height / fheight;
                posx = posy = 0;
            }

            int i, j;
            rand_str.Clear();
            // 描画するランダム文字を作って描画する
            screen.SetColor(73, 79, 179, alpha.Value());
            screen.BlendSrcAlpha();
            if (flamecounter == speed)
            {
                rand_str.Clear();
                for (i = 0; i < sy; ++i)
                {
                    StringBuilder ww = new StringBuilder();
                    for (j = 0; j < sx; ++j)
                    {
                        ww.Append(GetRandChara());
                    }
                    // 描画
                    tv = fr.GetTexture(ww.ToString(), 0);
                    screen.Blt(tv, posx, posy + i * fheight);

                    rand_str.Add(ww.ToString());
                }
                flamecounter = 0;
            }
            else
            {
                for (i = 0; i < rand_str.Count; ++i)
                {
                    tv = fr.GetTexture(rand_str[i], 0);
                    screen.Blt(tv, posx, posy + i * fheight);
                }

            }
            screen.ResetColor();
            flamecounter++;
        }

        #region 非公開メンバ

        /// <summary>
        /// 設定条件より一文字文字を返す
        /// </summary>
        /// <returns></returns>
        private char GetRandChara()
        {
            // ABC:26,123:10,mark:30,ﾊﾝｶﾅ:55
            // 0          36      66
            int charnum = 0, index, last;

            // 描画できる文字の数
            charnum += alphabet_str.Length;
            if (EnableNumberLetter) charnum += number_str.Length;
            if (EnableMarkLetter) charnum += mark_str.Length;
            if (EnableHankana) charnum += hankana_str.Length;

            index = rand.GetRand(charnum);

            last = alphabet_str.Length;
            if (index > last)
            {
                last += number_str.Length;
                if (EnableNumberLetter)
                {
                    if (index > last)
                    {
                        last += mark_str.Length;
                        if (EnableMarkLetter)
                        {
                            if (index > last)
                            {
                                if (!EnableHankana)
                                {
                                    // error
                                    return ' ';
                                }
                            }
                        }
                        else
                        {
                            index += mark_str.Length;
                        }
                    }
                }
                else
                {
                    index += number_str.Length;
                    last += mark_str.Length;
                    if (EnableMarkLetter)
                    {
                        if (last > index)
                        {
                            if (!EnableHankana)
                            {
                                // error
                                return ' ';
                            }
                        }
                    }
                    else
                    {
                        index += mark_str.Length;
                    }
                }
            }

            return enable_str[index];
        }

        #endregion

    }
}
