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

namespace Yamalib.Draw.Effect
{
    public class SequenceDraw : IDisposable
    {
        /// <summary>
        /// 描画情報データ
        /// </summary>
        private class DrawInfo : IDisposable
        {
            public ITexture t;
            public int direct;
            public int posS;
            public int posE;
            public int speed;

            #region IDisposable メンバ

            public void Dispose()
            {
                YamalibUtility.Dispose(t);
            }

            #endregion
        }

        #region 定数値

        private enum DIRECTION : int { LEFT, TOP, RIGHT, BOTTOM };

        #endregion

        #region フィールドメンバ

        private readonly List<DrawInfo> drawInfos = new List<DrawInfo>();
        private readonly RootCounterS sizeCounter = new RootCounterS();
        private readonly Rect drawRc = new Rect();
        private int nowIndex;
        private int posx;
        private int posy;
        private float rate = 1.0f;

        #endregion

        #region IDisposable メンバ

        public void Dispose()
        {
            ClearDrawInfo();
        }

        #endregion

        /// 描画終了したか
        public bool IsFinish()
        {
            return (nowIndex >= drawInfos.Count);
        }

        /// 描画位置の設定
        public void SetPos(int x_, int y_)
        {
            this.posx = x_;
            this.posy = y_;
        }

        /// 描画位置の取得
        public void GetPos(out int x_, out int y_)
        {
            x_ = this.posx;
            y_ = this.posy;
        }

        /// 設定ファイルの読み込み
        public void LoadDefFile(string filename)
        {
            ClearDrawInfo();

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

            List<List<string>> data = reader.CsvData;
            foreach (List<string> line in data)
            {
                if (line.Count < 5)
                {
                    continue;
                }
                DrawInfo info = new DrawInfo();
                info.t = YamalibConst.CreateTexture(line[0]);
                // 方向
                int dire = Convert.ToInt32(line[1]);
                // 開始位置
                int poss = Convert.ToInt32(line[2]);
                // 終了位置
                int pose = Convert.ToInt32(line[3]);
                // ステップ
                int step = Convert.ToInt32(line[4]);

                info.direct = dire;
                info.posS = (int)(poss * rate);
                info.posE = (int)(pose * rate);
                info.speed = step;

                drawInfos.Add(info);

            }

            // 初期化
            nowIndex = 0;
            sizeCounter.Set(drawInfos[0].posS, drawInfos[0].posE, drawInfos[0].speed);
            //Log.print("Load Def File : SIZE = %s", drawInfos.length);
        }

        /// 毎回呼び出すなり
        public void OnMove(IScreen screen)
        {
            if (0 == drawInfos.Count || IsFinish()) return;

            sizeCounter++;

            if (!IsFinish() && sizeCounter.IsEnd)
            {
                ++nowIndex;

                // log...
                //Log.print("Finish..%s", nowIndex);

                if (!IsFinish())
                {
                    int start = 0, end = 0;

                    switch ((DIRECTION)drawInfos[nowIndex].direct)
                    {
                        case DIRECTION.LEFT:
                            start = drawInfos[nowIndex].posS;
                            end = drawInfos[nowIndex].posE;
                            break;
                        case DIRECTION.TOP:
                            start = drawInfos[nowIndex].posS;
                            end = drawInfos[nowIndex].posE;
                            break;
                        case DIRECTION.RIGHT:
                            start = drawInfos[nowIndex].posS;
                            end = drawInfos[nowIndex].posE;
                            break;
                        case DIRECTION.BOTTOM:
                            start = drawInfos[nowIndex].posS;
                            end = drawInfos[nowIndex].posE;
                            break;
                        default:
                            Debug.Assert(false);
                            break;
                    }
                    // 次のカウンター設定
                    sizeCounter.Set(start, end, drawInfos[nowIndex].speed);
                }
                else
                {
                    // 終端に達した！
                    return;
                }

            }

            SetDrawRect(drawInfos[nowIndex]);
        }

        /// 毎回呼び出すなり
        public void OnDraw(IScreen screen)
        {
            if (0 == drawInfos.Count) return;

            // 描画済み
            for (int i = 0; i < nowIndex; ++i)
            {
                screen.BltRotate(drawInfos[i].t, posx, posy, 0, rate, 0);
            }

            if (!IsFinish())
            {
                // 書きかけ描画
                int offsetx = 0;
                int offsety = 0;

                // 右から
                if (DIRECTION.RIGHT == (DIRECTION)drawInfos[nowIndex].direct)
                {
                    offsetx = (int)((drawInfos[nowIndex].t.Width - this.drawRc.Width) * rate);
                }
                else if (DIRECTION.BOTTOM == (DIRECTION)drawInfos[nowIndex].direct)
                {
                    // 下から
                    offsety = (int)((drawInfos[nowIndex].t.Height - this.drawRc.Height) * rate);
                }

                screen.BltRotate(drawInfos[nowIndex].t, posx + offsetx, posy + offsety, this.drawRc, 0, rate, 0, 0);
            }
        }

        /// 現在の情報より描画矩形を設定する
        private void SetDrawRect(DrawInfo di)
        {
            int tw = (int)(di.t.Width);
            int th = (int)(di.t.Height);

            switch ((DIRECTION)di.direct)
            {
                case DIRECTION.LEFT:
                    drawRc.SetRect(0, 0, sizeCounter.Value(), th);
                    break;
                case DIRECTION.TOP:
                    drawRc.SetRect(0, 0, tw, sizeCounter.Value());
                    break;
                case DIRECTION.RIGHT:
                    drawRc.SetRect(sizeCounter.Value(), 0, tw, th);
                    break;
                case DIRECTION.BOTTOM:
                    drawRc.SetRect(0, sizeCounter.Value(), tw, th);
                    break;
                default:
                    Debug.Assert(false);
                    break;
            }
        }

        /// <summary>
        /// DrawInfowをクリアする
        /// </summary>
        private void ClearDrawInfo()
        {
            if (null != drawInfos)
            {
                foreach (DrawInfo drawInfo in drawInfos)
                {
                    drawInfo.Dispose();
                }
            }
            drawInfos.Clear();
        }
    }

    /// <summary>
    /// 去人たちのアイキャッチで使用したSequenceDrawによる
    /// 文字描画風表示のクラス
    /// 
    /// 去人たちの namespece にあるべきなのだけど...
    /// </summary>
    public class SequenceDrawManager : IDisposable
    {
        #region フィールドメンバ

        private List<SequenceDraw> seqDraws = new List<SequenceDraw>();
        private bool init;
        private bool drawFinish;
        private int indexer;

        private ITexture texLine;
        private int linePosx;
        private int linePosy;
        private ITexture texBar;
        private int barPosx;
        private int barPosy;
        private ITexture texChara;
        private int charaPosx;
        private int charaPosy;
        //private ITexture texFlash;

        private readonly InteriorCounter linePos = new InteriorCounter();
        private readonly InteriorCounter barPos = new InteriorCounter();
        private readonly RootCounterS alphaCounter = new RootCounterS();

        #endregion

        #region IDisposable メンバ

        public void Dispose()
        {
            if (null != seqDraws)
            {
                for (int i = 0; i < seqDraws.Count; i++)
                {
                    YamalibUtility.Dispose(seqDraws[i]);
                }
            }
            YamalibUtility.Dispose(texLine);
            YamalibUtility.Dispose(texBar);
            YamalibUtility.Dispose(texChara);
            //YamalibUtility.Dispose(texFlash);
        }

        #endregion

        public void LoadDefFile(string filename)
        {
            CSVReader reader = new CSVReader();
            YanesdkResult result = reader.Read(filename);
            if (YanesdkResult.NoError != result)
            {
                return;
            }

            List<List<string>> data = reader.CsvData;
            foreach (List<string> line in data)
            {
                if (line.Count < 4)
                {
                    continue;
                }

                switch (line[0])
                {
                    case "#MOJI":
                        {
                            SequenceDraw sd = new SequenceDraw();
                            sd.LoadDefFile(line[1]);

                            if (sd.IsFinish())
                            {
                                // 読み込みに失敗した
                                continue;
                            }

                            // 描画位置
                            int x = Convert.ToInt32(line[2]);
                            int y = Convert.ToInt32(line[3]);
                            sd.SetPos(x, y);

                            seqDraws.Add(sd);
                        }
                        break;

                    case "#H_BAR":
                        {
                        }
                        this.texLine = YamalibConst.CreateTexture(line[1]);

                        this.linePosx = Convert.ToInt32(line[2]);
                        this.linePosy = Convert.ToInt32(line[3]);

                        linePos.Set(640, linePosx, 30);

                        break;


                    case "#V_BAR":
                        {
                            this.texBar = YamalibConst.CreateTexture(line[1]);

                            this.barPosx = Convert.ToInt32(line[2]);
                            this.barPosy = Convert.ToInt32(line[3]);

                            barPos.Set(480, this.barPosy, 30);
                        }
                        break;

                    case "#CHARA":
                        {
                            this.texChara = YamalibConst.CreateTexture(line[1]);

                            this.charaPosx = Convert.ToInt32(line[2]);
                            this.charaPosy = Convert.ToInt32(line[3]);
                        }
                        break;

                    default:
                        continue;
                }
            }
        }

        /// 毎回呼び出すなり
        public void OnMove(IScreen screen)
        {
            if (!init)
            {
                OnInit();
                init = true;
            }

            for (int i = 0; i <= indexer; ++i)
            {
                seqDraws[i].OnMove(screen);
            }

            // 次の文字
            if (seqDraws[indexer].IsFinish() && !drawFinish)
            {
                if (indexer < seqDraws.Count - 1)
                {
                    ++indexer;
                }
                else
                {
                    drawFinish = true;
                }
            }

            if (drawFinish)
            {
                linePos++;
                barPos++;
                alphaCounter++;
            }
        }

        /// 毎回呼び出すなり
        public void OnDraw(IScreen screen)
        {
            screen.BlendSrcAlpha();
            screen.SetColor(255, 255, 255);

            for (int i = 0; i <= indexer; ++i)
            {
                seqDraws[i].OnDraw(screen);
            }

            if (drawFinish)
            {

                screen.SetColor(255, 255, 255, alphaCounter.Value());
                screen.Blt(texChara, this.charaPosx, this.charaPosy);

                screen.SetColor(255, 255, 255);
                //			screen.blt(texFlash, X -= 20, this.linePosy-90);

                // ポーズきめ！
                screen.Blt(texLine, linePos.Value(), this.linePosy);
                screen.Blt(texBar, this.barPosx, barPos.Value());
            }
        }

        /// 描画が終了したか？
        public bool IsFinish()
        {
            return (alphaCounter.IsEnd && barPos.IsEnd);
        }

        /// 初期化処理
        private void OnInit()
        {
            drawFinish = false;
            alphaCounter.Set(0, 255, 2);
        }

    }
}
