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

namespace Kyojin.Component.Ending
{

    /// <summary>
    /// ゲームでのポイントを計算するクラス
    /// </summary>
    public class GamePointCal
    {
        #region 定数値

        public const float GREAT_POINT = 100;
        public const float GOOD_POINT = 50;
        public const float BAD_POINT = 25;
        public const float POOR_POINT = -25;
        public const float ERROR_POINT = -50;

        public const float GREAT_BONUS = 0.25f;
        public const float GOOD_BONUS = 0.10f;
        public const float BAD_BONUS = 0.0f;
        //public const float POOR_BONUS = 1.0f;
        //public const float ERROR_BONUS = 1.0f;

        #endregion

        /// <summary>
        /// ヒットステータスをカウントする
        /// </summary>
        /// <param name="status"></param>
        /// <returns></returns>
        public float CalcHitPoint(HitStatus status)
        {
            switch (status)
            {
                case HitStatus.GREAT:
                    ++m_greatCount;
                    m_totalPoint += GREAT_POINT * m_bonusPoint;
                    m_bonusPoint += GREAT_BONUS;
                    break;
                case HitStatus.GOOD:
                    ++m_goodCount;
                    m_totalPoint += GOOD_POINT * m_bonusPoint;
                    m_bonusPoint += GOOD_BONUS;
                    break;
                case HitStatus.BAD:
                    ++m_badCount;
                    m_totalPoint += BAD_POINT * m_bonusPoint;
                    m_bonusPoint += BAD_BONUS;
                    break;
                case HitStatus.POOR:
                    ++m_poorCount;
                    m_totalPoint += POOR_POINT;
                    m_bonusPoint = 1.0f;
                    break;
                case HitStatus.ERROR:
                    ++m_errorCount;
                    m_totalPoint += ERROR_POINT;
                    m_bonusPoint = 1.0f;
                    break;
                default:
                    return m_totalPoint;
            }
            m_statusHitory.Add(status);
            //Log.print("POINT : %f, \t\tBONUS", m_totalPoint, m_bonusPoint);
            return m_totalPoint;
        }

        public List<HitStatus> StatusHitory
        {
            get { return m_statusHitory; }
        }

        public void ClearStatusHistory()
        {
            m_statusHitory.Clear();
        }

        public int GreatCount
        {
            get { return m_greatCount; }
        }

        public int GoodCount
        {
            get { return m_goodCount; }
        }

        public int BadCount
        {
            get { return m_badCount; }
        }

        public int PoorCount
        {
            get { return m_poorCount; }
        }

        public int ErrorCount
        {
            get { return m_errorCount; }
        }

        public float TotalPoint
        {
            get { return m_totalPoint; }
        }

        public float BonusPoint
        {
            get { return m_bonusPoint; }
        }

        #region メンバフィールド

        private readonly List<HitStatus> m_statusHitory = new List<HitStatus>();
        private int m_greatCount;
        private int m_goodCount;
        private int m_badCount;
        private int m_poorCount;
        private int m_errorCount;
        private float m_totalPoint = 0.0f;
        private float m_bonusPoint = 1.0f;

        #endregion


    }


    /// <summary>
    /// エンディングシーンの共通変数・メソッドを定義
    /// </summary>
    public abstract class EndingSceneBase
    {

        protected abstract class PhaseBase
        {
            public PhaseBase(TextObj obj, TextureLoader loader, HitStatus status)
            {
                m_start = true;
                m_textObj = obj.Clone();
                m_textureLoader = loader;
                m_hitStatus = status;
            }

            public abstract void OnMove(IScreen screen);
            public abstract void OnDraw(IScreen screen);

            /// ヒットされたときにデフォルトの効果
            public virtual void OnDrawHitText(IScreen screen)
            {
            }

            public bool IsStart
            {
                get { return m_start; }
                set { m_start = value; }
            }

            public bool IsEnd
            {
                get { return m_end; }
                set { m_end = value; }
            }

            protected TextObj m_textObj;
            protected TextureLoader m_textureLoader;
            protected HitStatus m_hitStatus;

            //private RootCounterS m_hitTextAlpha;
            //private RootCounterS m_hitTextRate;
            private bool m_start;
            private bool m_end;
        }

        protected class Phase1Base : PhaseBase
        {
            /// 初期化処理
            public Phase1Base(TextObj obj, TextureLoader loader, HitStatus status)
                : base(obj, loader, status)
            {
                phase = new RootCounterS(0, 255, 2);
            }

            /// ローダの画像番号
            public void SetImgNo(int no)
            {
                imgNo = no;
            }

            /// 描画位置
            public void SetXY(int x, int y)
            {
                posx = x;
                posy = y;
            }
            public void GetXY(out int x, out int y)
            {
                x = posx;
                y = posy;
            }

            /// トランスブリッタ用のカウンタ
            public RootCounterS GetTransCounter()
            {
                return phase;
            }

            /// トランスブリッタの効果番号
            public void SetEffectNo(int no)
            {
                effectNo = no;
            }
            public int GetEffectNo()
            {
                return effectNo;
            }

            /// 移動処理
            public override void OnMove(IScreen IScreen)
            {
                if (IsStart)
                {
                    phase.Inc();
                }
            }
            /// 描画処理
            public override void OnDraw(IScreen IScreen)
            {
                if (IsStart && !IsEnd)
                {
                    SetScreenColorMax(IScreen);
                    TransBltter.Blt(effectNo, IScreen, m_textureLoader.GetTexture(imgNo), posx, posy, phase.Value());
                }
            }

            private int effectNo;
            private int posx;
            private int posy;
            private int imgNo;
            private RootCounterS phase;
        }

        #region 定数値

        public const long MUSIC_OFFSET_TIME = 4500;
        /** タンポポ色 */
        protected static readonly Color4ub GREAT_COLOR = new Color4ub(251, 236, 53, 255);
        /** ブルー */
        protected static readonly Color4ub GOOD_COLOR = new Color4ub(12, 0, 204, 255);
        /** 灰白色 */
        protected static readonly Color4ub BAD_COLOR = new Color4ub(231, 232, 226, 255);

        #endregion

        #region メンバフィールド

        protected static Color4ub colorOrg;
        protected static readonly GamePointCal gamePointCal = new GamePointCal();
        protected readonly List<TimingData[]> m_timingData = new List<TimingData[]>();
        protected int greatCount;
        protected int goodCount;
        protected int badCount;
        protected int poorCount;
        protected bool m_autoHit;

        #endregion


        public static GamePointCal GamePointcalculator()
        {
            return gamePointCal;
        }

        public abstract void OnMove(IScreen screen);

        public abstract void OnDraw(IScreen screen);


        public List<TimingData[]> TimingData
        {
            get { return m_timingData; }
        }

        public bool IsAutoHit()
        {
            return m_autoHit;
        }
        public bool IsAutoHit(bool value)
        {
            return m_autoHit = value;
        }

        public virtual void CacheTexture()
        {
            // キャッシュを実装してもＯＫ
        }

        // シーンは開始しているか
        public virtual bool IisStart
        {
            get { return true; }
        }

        // シーンが終了したか
        public virtual bool IsEnd
        {
            get { return false; }
        }

        // リソースの解放
        public virtual void Release()
        {
        }

        #region 保護メンバ

        protected static void CacheTextureAll(TextureLoader loader, string defFilename)
        {
            int num = YanesdkUtil.GetElementNum(defFilename);
            for (int i = 0; i < num; i++)
            {
                loader.GetTexture(i);
            }
        }

        protected static bool IsHitedStatus(HitStatus status)
        {
            return HitStatus.POOR != status;
        }

        protected static void SetScreenColorMax(IScreen screen)
        {
            colorOrg = YanesdkUtil.GetNowScreenColor(screen);
            screen.SetColor(255, 255, 255, 255);
        }

        protected static void RepairColor(IScreen screen)
        {
            screen.SetColor(colorOrg);
        }

        protected static HittingEffect CreateHitEffect(TextObj textObj)
        {
            switch (textObj.HitResultData.HitStatus)
            {
                case HitStatus.GREAT:
                    return new HittingEffect(textObj.Img, (int)textObj.Pos.X, (int)textObj.Pos.Y, textObj.Alpha,
                            textObj.Rate, textObj.Rad, GREAT_COLOR);
                case HitStatus.GOOD:
                    return new HittingEffect(textObj.Img, (int)textObj.Pos.X, (int)textObj.Pos.Y, textObj.Alpha,
                            textObj.Rate, textObj.Rad, GOOD_COLOR);
                case HitStatus.BAD:
                    return new HittingEffect(textObj.Img, (int)textObj.Pos.X, (int)textObj.Pos.Y, textObj.Alpha,
                            textObj.Rate, textObj.Rad, GREAT_COLOR);
                case HitStatus.POOR:
                    return null;
                default:
                    return null;
            }
        }

        /// ヒットステータスをカウントする
        protected void CountHitStatus(HitStatus status)
        {
            switch (status)
            {
                case HitStatus.GREAT:
                    ++greatCount;
                    break;
                case HitStatus.GOOD:
                    ++goodCount;
                    break;
                case HitStatus.BAD:
                    ++badCount;
                    break;
                case HitStatus.POOR:
                    ++poorCount;
                    break;
                default:
                    break;
            }
            gamePointCal.CalcHitPoint(status);
        }

        #endregion

    }

    /// <summary>
    /// ヒットしたときの効果クラス
    /// </summary>
    public class HittingEffect
    {
        #region 定数値

        /** 拡大率に使用しているスケール */
        private const float RATE_SCALE = 512.0f;
        /** 拡大スピード */
        private const int RATE_SPEED = 64;
        /** 消失スピード */
        private const int ALPHA_SPEED = 7;

        #endregion

        #region メンバフィールド

        private ITexture texture;
        private int posx;
        private int posy;
        private Color4ub drawColor;
        private readonly RootCounterS rateCounter;
        private readonly RootCounterS alphaCounter;
        private int rad;
        private bool drawEnd;

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="tex"></param>
        /// <param name="X"></param>
        /// <param name="Y"></param>
        /// <param name="startAlpha"></param>
        /// <param name="StartRate"></param>
        /// <param name="Rad"></param>
        /// <param name="color"></param>
        public HittingEffect(ITexture tex, int x, int y, int startAlpha, float startRate, int rad, Color4ub color)
        {
            this.texture = tex;
            this.rateCounter = new RootCounterS((int)(startRate * RATE_SCALE), 2560, RATE_SPEED);
            this.alphaCounter = new RootCounterS(startAlpha, 0, ALPHA_SPEED);
            this.posx = x;
            this.posy = y;
            this.rad = rad;
            this.drawColor = color;
        }

        /// <summary>
        /// 移動処理
        /// </summary>
        /// <param name="screen"></param>
        public void OnMove(IScreen screen)
        {
            if (!drawEnd)
            {
                rateCounter.Inc();
                alphaCounter.Inc();
                drawEnd = alphaCounter.Value() == 0;
            }
        }

        /// <summary>
        /// 描画処理
        /// </summary>
        /// <param name="screen"></param>
        public void OnPaint(IScreen screen)
        {
            if (!drawEnd)
            {
                Color4ub colorOrg = YanesdkUtil.GetNowScreenColor(screen);
                screen.SetColor(drawColor.R, drawColor.G, drawColor.B, alphaCounter.Value());
                screen.BltRotate(texture, posx, posy, rad, rateCounter.Value() / RATE_SCALE, 4);
                // カラー戻し
                screen.SetColor(colorOrg);
            }
        }

        /// <summary>
        /// 終了したか
        /// </summary>
        public bool IsEnd
        {
            get { return drawEnd; }
        }

    }


}
