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

namespace Yamalib.Draw.Effect
{
    /// <summary>
    /// 横に字間を広げながら描画する演出描画クラス
    /// </summary>
    public class SpreadString
    {
        #region 定数値

        public enum BASE_POS { LEFT, CENTER, RIGHT };

        #endregion

        #region メンバフィールド

        static SinTable sin = null;

        // 描画文字列のリポジトリ
        FontRepository fontRepository;
        // 描画文字列の大きさ
        float rate = 1.0f;
        // 角度
        int rad = 0;
        // 描画中の文字列テクスチャ
        Textures textureVec;
        // 描画している文字列
        string drawString;
        /// 描画アルファ
        int alpha = 255;
        ///　字間カウンター
        IDecimalCounter spaceCounter;

        #endregion


        /// コンストラクタ
        public SpreadString(FontRepository fontRepository_)
        {
            Debug.Assert(fontRepository_ != null);
            fontRepository = fontRepository_;
        }

        /// 描画する文字列を設定する
        public void SetStringUnicode(string str)
        {
            Debug.Assert(str != null);
            drawString = str;
            textureVec = fontRepository.GetTexture(str, 0);
        }
        public string GetStringUnicode()
        {
            return drawString;
        }

        /// 拡大率を設定
        public void SetRate(float rate_)
        {
            rate = rate_;
        }
        public float GetRate()
        {
            return rate;
        }

        public void SetRad(int rad_)
        {
            rad = rad_ % 512;
        }
        public int GetRad()
        {
            return rad;
        }

        /// アルファを設定
        public void SetAlpha(int alpha_)
        {
            alpha = alpha_;
        }
        public int GetAlpha()
        {
            return alpha;
        }

        /// 字間カウンターの設定
        public void SetSpaceCounter(IDecimalCounter spaceCounter_)
        {
            Debug.Assert(spaceCounter_ != null);
            spaceCounter = spaceCounter_;
        }
        public IDecimalCounter GetSpaceCounter()
        {
            return spaceCounter;
        }

        public void OnMove(IScreen screen)
        {
            if (spaceCounter == null || textureVec == null)
            {
                return;
            }
            spaceCounter.Inc();
        }

        /// 現在の設定で描画する
        public void OnDraw(IScreen screen, int x, int y, BASE_POS basePos)
        {
            if (spaceCounter == null || textureVec == null)
            {
                return;
            }
            // オリジナルカラー保存
            Color4ub colorOrg = YanesdkUtil.GetNowScreenColor(screen);

            // アルファ設定
            screen.SetColor(colorOrg.R, colorOrg.G, colorOrg.B, alpha);
            float addWidth = 0;
            float spaceRate = (float)spaceCounter.GetDecimal();

            switch (basePos)
            {
                case BASE_POS.LEFT:
                    int i = 0;
                    foreach (Textures.TextureInfo textureInfo in textureVec.Infos)
                    {
                        screen.BltRotate(textureInfo.Texture,
                            (int)((x + textureInfo.PosX + addWidth)), y, 0, rate, 0);
                        addWidth += (spaceRate * rate);
                        ++i;
                    }
                    break;
                case BASE_POS.CENTER:
                    if (0 == rad)
                    {
                        DrawBaseCenter(screen, x, y);
                    }
                    else
                    {
                        DrawBaseCenterRad(screen, x, y);
                    }
                    break;
                case BASE_POS.RIGHT:
                    break;
            }

            // カラーもどし
            screen.SetColor(colorOrg);
        }

        /// 状態を初期化	
        public void Reset()
        {
            spaceCounter.Reset();
            drawString = null;
        }

        #region 非公開メンバ


        private void DrawBaseCenterRad(IScreen screen, int x, int y)
        {
            if (sin == null)
            {
                sin = SinTable.Instance;
            }
            float addWidth = 0.0f;
            float spaceRate = (float)spaceCounter.GetDecimal();
            float offsetPos = GetConterOffsetPos();
            double r;
            int i = 0;
            foreach (Textures.TextureInfo textureInfo in textureVec.Infos)
            {
                r = (addWidth - offsetPos);
                screen.BltRotate(textureInfo.Texture,
                    (int)(x + (sin.CosDouble(rad) * r)),
                        (int)(y + sin.SinDouble(rad) * r), rad, rate, 4);
                addWidth += spaceRate + textureInfo.Texture.Width * rate;
                ++i;
            }
        }

        private void DrawBaseCenter(IScreen screen, int x, int y)
        {
            float addWidth = 0;
            float spaceRate = (float)spaceCounter.GetDecimal();
            float offsetPos = GetConterOffsetPos();
            int i = 0;
            foreach (Textures.TextureInfo textureInfo in textureVec.Infos)
            {
                screen.BltRotate(textureInfo.Texture,
                    (int)(x + addWidth - offsetPos),
                    y, 0, rate, 4);
                addWidth += spaceRate + textureInfo.Texture.Width * rate;
                ++i;
            }
        }

        private float GetConterOffsetPos()
        {
            List<Textures.TextureInfo> textureInfos = textureVec.Infos;
            if (textureInfos == null)
            {
                return 0.0f;
            }
            float spaceRate = (float)spaceCounter.GetDecimal();
            return ((textureVec.Width * rate) + (spaceRate * (textureInfos.Count - 1))) / 2.0f;
        }

        #endregion

    }

    /// <summary>
    /// SpreadString を二つ使用して、疑似ブラーを行うクラス
    /// </summary>
    public class SpreadStringBlur
    {
        /// <summary>
        /// SpreadStringBlurクラスのエッセンスオブジェクト
        /// </summary>
        public class EssencePram
        {
            private FontRepository frontFont;

            public FontRepository FrontFont
            {
                get { return frontFont; }
                set { frontFont = value; }
            }
            private FontRepository backFont;

            public FontRepository BackFont
            {
                get { return backFont; }
                set { backFont = value; }
            }
            private int spreadStartWidth;

            public int SpreadStartWidth
            {
                get { return spreadStartWidth; }
                set { spreadStartWidth = value; }
            }
            private int spreadEndWidth;

            public int SpreadEndWidth
            {
                get { return spreadEndWidth; }
                set { spreadEndWidth = value; }
            }
            private int spreadSpeed;

            public int SpreadSpeed
            {
                get { return spreadSpeed; }
                set { spreadSpeed = value; }
            }
            private int rad;

            public int Rad
            {
                get { return rad; }
                set { rad = value; }
            }
            private float frontRate = 1.0f;

            public float FrontRate
            {
                get { return frontRate; }
                set { frontRate = value; }
            }
            private float backRate = 1.0f;

            public float BackRate
            {
                get { return backRate; }
                set { backRate = value; }
            }
            private ICounter frontAlpha;

            public ICounter FrontAlpha
            {
                get { return frontAlpha; }
                set { frontAlpha = value; }
            }
            private ICounter backAlpha;

            public ICounter BackAlpha
            {
                get { return backAlpha; }
                set { backAlpha = value; }
            }

            public bool isValid()
            {
                return (frontFont != null) && (backFont != null);
            }
        }


        #region 定数値

        #endregion

        #region メンバフィールド

        private EssencePram essenceParam;
        // 描画用
        private SpreadString frontString;
        // ブラー用
        private SpreadString backString;
        // スタート待機
        private int startWait = 0;

        private int posx;
        private int posy;

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="essenceParam_"></param>
        public SpreadStringBlur(EssencePram essenceParam_)
        {
            Debug.Assert(essenceParam_ != null);
            essenceParam = essenceParam_;

            if (!essenceParam.isValid())
            {
                throw new Exception("SpreadStringBlur : Invalid essenceParam");
            }

            frontString = new SpreadString(essenceParam.FrontFont);
            frontString.SetRad(essenceParam.Rad);
            frontString.SetRate(essenceParam.FrontRate);
            {
                IDecimalCounter widthCounter = new PowIncCounter();
                widthCounter.Set(essenceParam.SpreadStartWidth, essenceParam.SpreadEndWidth,
                    essenceParam.SpreadSpeed);
                frontString.SetSpaceCounter(widthCounter);
            }

            backString = new SpreadString(essenceParam.BackFont);
            backString.SetRad(essenceParam.Rad);
            backString.SetRate(essenceParam.BackRate);
            {
                IDecimalCounter widthCounter = new PowIncCounter();
                widthCounter.Set(essenceParam.SpreadStartWidth, essenceParam.SpreadEndWidth,
                    essenceParam.SpreadSpeed);
                backString.SetSpaceCounter(widthCounter);
            }
        }

        public void SetCounterBase(float baseValue)
        {
            PowIncCounter frontCounter = (PowIncCounter)frontString.GetSpaceCounter();
            if (frontCounter != null)
            {
                frontCounter.SetBase(baseValue);
            }
            PowIncCounter backCounter = (PowIncCounter)backString.GetSpaceCounter();
            if (backCounter != null)
            {
                backCounter.SetBase(baseValue);
            }
        }

        public EssencePram GetEssence()
        {
            return essenceParam;
        }

        public bool IsEndAlpha()
        {
            if (essenceParam.FrontAlpha != null)
            {
                if (!essenceParam.FrontAlpha.IsEnd)
                {
                    return false;
                }
            }
            if (essenceParam.BackAlpha != null)
            {
                if (!essenceParam.BackAlpha.IsEnd)
                {
                    return false;
                }
            }
            return true;
        }

        public void SetX(int x)
        {
            posx = x;
        }
        public int GetX()
        {
            return posx;
        }

        public void SetY(int y)
        {
            posy = y;
        }
        public int GetY()
        {
            return posy;
        }

        public void SetPosXY(int x, int y)
        {
            posx = x;
            posy = y;
        }

        public void GetPosXY(out int x, out int y)
        {
            x = posx;
            y = posy;
        }

        public void SetStartWait(int startWait_)
        {
            startWait = startWait_;
        }
        public int GetStatWait()
        {
            return startWait;
        }

        /// 文字列の設定
        public void SetStringUnicode(string str)
        {
            backString.SetStringUnicode(str);
            frontString.SetStringUnicode(str);
        }

        /// 状態を初期化する
        public void Reset()
        {
            if (essenceParam.FrontAlpha != null)
            {
                essenceParam.FrontAlpha.Reset();
            }
            if (essenceParam.BackAlpha != null)
            {
                essenceParam.BackAlpha.Reset();
            }
            frontString.Reset();
            backString.Reset();
        }

        /// 表の文字列画像を取得
        public SpreadString GetFront()
        {
            return frontString;
        }

        /// 裏の文字列画像を取得
        public SpreadString GetBack()
        {
            return backString;
        }

        public void OnMove(IScreen screen)
        {
            if (startWait > 0)
            {
                --startWait;
                return;
            }

            if (essenceParam.FrontAlpha != null)
            {
                essenceParam.FrontAlpha.Inc();
            }
            if (essenceParam.BackAlpha != null)
            {
                essenceParam.BackAlpha.Inc();
            }
            frontString.OnMove(screen);
            backString.OnMove(screen);
        }

        public void OnDraw(IScreen screen)
        {
            if (startWait > 0)
            {
                return;
            }

            if (essenceParam.FrontAlpha != null)
            {
                frontString.SetAlpha(essenceParam.FrontAlpha.Value());
            }
            if (essenceParam.BackAlpha != null)
            {
                backString.SetAlpha(essenceParam.BackAlpha.Value());
            }
            frontString.OnDraw(screen, posx, posy, SpreadString.BASE_POS.CENTER);
            backString.OnDraw(screen, posx, posy, SpreadString.BASE_POS.CENTER);
        }


    }
}
