using System;
using System.Collections.Generic;
using System.Text;
using Yanesdk.System;
using Kyojin.Model;
using Yanesdk.Math;
using Yamalib.Util;
using Yanesdk.Draw;
using Yanesdk.Timer;
using Yamalib.Draw;
using Yamalib;
using System.Diagnostics;
using Yamalib.Draw.Effect;

namespace Kyojin.Scene.Telop
{
    class TelopScene : TaskBase, IDisposable
    {
        #region 定数値

        private static readonly long OPENING_END_TIME = 15560;
        private static readonly string MESSAGE_TELOP1 = "img2\\eyecatch\\telop1.txt";
        private static readonly string MESSAGE_TELOP2 = "img2\\eyecatch\\telop2.txt";
        private static readonly string MESSAGE_TELOP3 = "img2\\eyecatch\\telop3.txt";
        private static readonly string TELOP_CONF1 = "img2\\eyecatch\\conf1.txt";
        private static readonly string TELOP_CONF2 = "img2\\eyecatch\\conf2.txt";
        private static readonly string TELOP_CONF3 = "img2\\eyecatch\\conf3.txt";

        private enum SCENE_ID { FADE_IN, OPENING, END_OPNING, SECTION_TELOP, END };

        #endregion

        #region メンバフィールド

        private readonly GameSystem m_gSys;
        private readonly Rand rand = new Rand();
        private bool init = false;
        private readonly List<SpreadStringBlur> spreadStringBlurs = new List<SpreadStringBlur>();
        private RootCounterS clearColorCounter;
        private RootCounter rotCounter;
        private ITexture imgBg;
        private ITexture imgBackup;
        private SCENE_ID sceneNo = SCENE_ID.FADE_IN;
        private FixTimer timer;
        // 展開描画クラス
        private readonly List<FontLoader> fontLoaders = new List<FontLoader>();
        private string[] messages;
        private RootCounterS alpha;
        private int drawRad = 0;

        private readonly List<FileSys.TmpFile> fontDefTmpFile = new List<FileSys.TmpFile>();

        // パラグラフタイトル用描画クラス
        private SlideShadeDraw shadeDraw;

        #endregion

        public TelopScene(GameSystem gameSystem)
        {
            m_gSys = gameSystem;
            rand.Randomize();
        }

        #region IDisposable メンバ

        public void Dispose()
        {
            foreach (FileSys.TmpFile tmpFile in fontDefTmpFile)
            {
                tmpFile.Dispose();
            }
            foreach (FontLoader fontLoader in fontLoaders)
            {
                fontLoader.Dispose();
            }
            YamalibUtility.Dispose(imgBg);
        }

        #endregion

        public override int Task(object o)
        {
            GameSystem gameSystem = (GameSystem)o;
            if (0 == OnMove(gameSystem))
            {
                return 0;
            }
            gameSystem.OnMoveCommon();
            if (!gameSystem.FpsTimer.ToBeSkip)
            {
                gameSystem.Screen.Select();
                OnPaint(gameSystem);
                gameSystem.OnDrawCommon();
                gameSystem.Screen.Update();
            }
            else
            {
                OnPaint(gameSystem);
                gameSystem.OnDrawCommon();
            }
            return 1;
        }

        /// <summary>
        /// 動作処理
        /// </summary>
        /// <param name="gameSystem"></param>
        private int OnMove(GameSystem gameSystem)
        {
            if (!init)
            {
                OnInit();
                init = true;
            }

            timer.Update();

            switch (sceneNo)
            {
                case SCENE_ID.FADE_IN:
                    alpha.Inc();
                    if (alpha.IsEnd)
                    {
                        sceneNo = SCENE_ID.OPENING;
                    }
                    break;

                case SCENE_ID.OPENING:
                    if (timer.Time > OPENING_END_TIME)
                    {
                        bool allEnd = true;
                        // 全部フェードアウトするまで待つ
                        foreach (SpreadStringBlur spreadStringBlur in spreadStringBlurs)
                        {
                            spreadStringBlur.OnMove(m_gSys.Screen);
                            if (!spreadStringBlur.IsEndAlpha())
                            {
                                allEnd = false;
                                break;
                            }
                        }
                        if (allEnd)
                        {
                            // 次のシーンのセットアップ
                            int i = 0;
                            foreach (SpreadStringBlur spreadStringBlur in spreadStringBlurs)
                            {
                                spreadStringBlur.OnMove(m_gSys.Screen);
                                if (spreadStringBlur.IsEndAlpha())
                                {
                                    spreadStringBlur.Reset();
                                    spreadStringBlur.SetCounterBase(0.96f);
                                    // 文字列を設定
                                    spreadStringBlur.SetStringUnicode(messages[rand.GetRand(messages.Length)]);
                                    // yを設定
                                    spreadStringBlur.SetY((i + 1) * 120);
                                    spreadStringBlur.SetX(320);
                                    spreadStringBlur.GetFront().SetRad((i % 2) != 0 ? 256 : 0);
                                    spreadStringBlur.GetBack().SetRad((i % 2) != 0 ? 256 : 0);
                                    spreadStringBlur.GetEssence().FrontAlpha.Set(200, 15, 5);
                                    spreadStringBlur.GetEssence().BackAlpha.Set(150, 0, 1);
                                }
                                ++i;
                            }
                            sceneNo = SCENE_ID.END_OPNING;
                        }
                    }
                    else
                    {
                        foreach (SpreadStringBlur spreadStringBlur in spreadStringBlurs)
                        {
                            spreadStringBlur.OnMove(m_gSys.Screen);
                            if (spreadStringBlur.IsEndAlpha())
                            {
                                ReloadTelop1(spreadStringBlur);
                            }
                        }
                    }
                    break;

                case SCENE_ID.END_OPNING:	// セクション
                    {
                        bool allEnd = true;
                        // 全部フェードアウトするまで待つ
                        foreach (SpreadStringBlur spreadStringBlur in spreadStringBlurs)
                        {
                            spreadStringBlur.OnMove(m_gSys.Screen);
                            if (!spreadStringBlur.IsEndAlpha())
                            {
                                allEnd = false;
                            }
                        }
                        if (allEnd)
                        {
                            sceneNo = SCENE_ID.SECTION_TELOP;
                            shadeDraw.OnMove(m_gSys.Screen);
                        }
                    }
                    break;
                case SCENE_ID.SECTION_TELOP:
                    shadeDraw.OnMove(m_gSys.Screen);
                    if (shadeDraw.IsEnd())
                    {
                        JumpScenario();
                        return 0;
                    }
                    break;

                default:
                    break;
            }

            return 1;
        }

        /// <summary>
        /// 描画処理
        /// </summary>
        /// <param name="gameSystem"></param>
        private void OnPaint(GameSystem gameSystem)
        {
            switch (sceneNo)
            {
                case SCENE_ID.FADE_IN:
                    m_gSys.Screen.SetClearColor(0, 0, 0);
                    m_gSys.Screen.Clear();
                    m_gSys.Screen.BlendSrcAlpha();
                    m_gSys.Screen.SetColor(255, 255, 255, alpha.Value());

                    // バックアップしたテクスチャは反転している
                    m_gSys.Screen.Blt(imgBackup, 0, 0, new Rect(0, 480, 640, 0), null);
                    break;

                case SCENE_ID.OPENING:
                    m_gSys.Screen.SetClearColor(0, 0, 0);
                    m_gSys.Screen.Clear();
                    m_gSys.Screen.BlendSrcAlpha();
                    m_gSys.Screen.SetColor(190, 190, 190);
                    foreach (SpreadStringBlur spreadStringBlur in spreadStringBlurs)
                    {
                        spreadStringBlur.OnDraw(m_gSys.Screen);
                    }
                    break;

                case SCENE_ID.END_OPNING:
                    m_gSys.Screen.SetClearColor(0, 0, 0);
                    m_gSys.Screen.Clear();
                    m_gSys.Screen.BlendSrcAlpha();
                    m_gSys.Screen.SetColor(190, 190, 190);
                    foreach (SpreadStringBlur spreadStringBlur in spreadStringBlurs)
                    {
                        spreadStringBlur.OnDraw(m_gSys.Screen);
                    }
                    break;

                case SCENE_ID.SECTION_TELOP:
                    m_gSys.Screen.SetClearColor(0, 0, 0);
                    m_gSys.Screen.Clear();
                    m_gSys.Screen.BlendSrcAlpha();
                    m_gSys.Screen.SetColor(255, 255, 255);
                    shadeDraw.OnDraw(m_gSys.Screen);
                    break;

                case SCENE_ID.END:
                    m_gSys.Screen.SetClearColor(0, 0, 0);
                    m_gSys.Screen.Clear();
                    m_gSys.Screen.SetColor(255, 255, 255);
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 初期化処理
        /// </summary>
        private void OnInit()
        {
            imgBackup = m_gSys.TelopParam.ScreenImg;
            alpha = new RootCounterS();
            alpha.Set(255, 0, 1);

            switch ((KyojinConst.ScenarioID)m_gSys.TelopParam.CallScenarioNo)
            {
                case KyojinConst.ScenarioID.KYOJIN01:
                    messages = LoadMessage(MESSAGE_TELOP1, 15);
                    shadeDraw = SlideShadeDraw.CreateInstance(TELOP_CONF1, m_gSys.SmartTextureLoader);
                    break;
                case KyojinConst.ScenarioID.KYOJIN02:
                    messages = LoadMessage(MESSAGE_TELOP2, 15);
                    shadeDraw = SlideShadeDraw.CreateInstance(TELOP_CONF2, m_gSys.SmartTextureLoader);
                    break;
                case KyojinConst.ScenarioID.KYOJIN03:
                    messages = LoadMessage(MESSAGE_TELOP3, 15);
                    shadeDraw = SlideShadeDraw.CreateInstance(TELOP_CONF3, m_gSys.SmartTextureLoader);
                    break;
                default:
                    messages = LoadMessage(MESSAGE_TELOP1, 15);
                    shadeDraw = SlideShadeDraw.CreateInstance(TELOP_CONF1, m_gSys.SmartTextureLoader);
                    Debug.Assert(false, "未定義の去人パートテロップが指定された");
                    break;
            }


            // フォントのロード
            FontRepository frontRep = CreateFontRepository("fonts/FS-Mincho.ttf", 40, 0, 150);
            FontRepository backRep = CreateFontRepository("fonts/FS-Mincho.ttf", 10, 0, 150);

            // フォントリポジトリを埋めておく
            for (int i = 0; i < 150; ++i)
            {
                frontRep.GetTexture(messages[rand.GetRand(messages.Length)], 0);
                backRep.GetTexture(messages[rand.GetRand(messages.Length)], 0);
            }

            // インスタンス生成
            spreadStringBlurs.Add(CreateSpread1(frontRep, backRep));
            spreadStringBlurs.Add(CreateSpread2(frontRep, backRep));
            spreadStringBlurs.Add(CreateSpread3(frontRep, backRep));

            // 描画スタートタイミングをずらす	
            for (int i = 1; i < spreadStringBlurs.Count; ++i)
            {
                spreadStringBlurs[i].SetStartWait(333 * i);
            }

            // クリアカラーカウンター
            clearColorCounter = new RootCounterS();
            clearColorCounter.Set(255, 255, 1);

            // 回転カウンター
            rotCounter = new RootCounter();
            rotCounter.Set(0, 512, -5);

            imgBg = YamalibConst.CreateTexture("img2/eyecatch/bg.png");

            timer = new FixTimer();
            timer.Reset();
        }

        /// テロップ１での文字列リロード設定
        void ReloadTelop1(SpreadStringBlur spreadStringBlur)
        {
            spreadStringBlur.Reset();
            // 文字列を設定
            spreadStringBlur.SetStringUnicode(messages[rand.GetRand(messages.Length)]);
            // yを設定
            spreadStringBlur.SetY(50 + rand.GetRand(400));
            spreadStringBlur.SetX(150 + rand.GetRand(240));
            // 角度を設定
            drawRad += 14;
            bool reverce = (drawRad % 2 == 0);
            spreadStringBlur.GetFront().SetRad(reverce ? drawRad + 256 : drawRad);
            spreadStringBlur.GetBack().SetRad(reverce ? drawRad + 256 : drawRad);
        }

        /// シナリオタスクに遷移する
        void JumpScenario()
        {
            m_gSys.ScenarioSceneParam.IsReadTop = true;
            if (m_gSys.ScenarioSceneParam.ScenarioInfo == null)
            {
                m_gSys.ScenarioSceneParam.ScenarioInfo = new ScenarioInfo();
            }
            m_gSys.ScenarioSceneParam.ScenarioInfo.ScenarioID = m_gSys.TelopParam.CallScenarioNo;


            // すべてのスタックを破棄		
            m_gSys.SceneController.ExitScene();

            // 強制バックアップを行う
            m_gSys.SceneController.CallScene(Scenes.Scenario);
        }

        private SpreadStringBlur CreateSpread1(FontRepository frontRep, FontRepository backRep)
        {
            int rad = 0; //480;
            int step = 256;
            int startWidth = -30;
            int endWidth = 20;
            // エッセンス生成
            SpreadStringBlur.EssencePram essence = new SpreadStringBlur.EssencePram();
            essence.FrontFont = frontRep;
            essence.BackFont = backRep;
            essence.SpreadStartWidth = startWidth;
            essence.SpreadEndWidth = endWidth;
            essence.SpreadSpeed = step;
            essence.Rad = rad;
            essence.FrontRate = 2.0f;
            essence.BackRate = 8.0f;
            {
                RootCounterS alphaCounter = new RootCounterS();
                alphaCounter.Set(200, 15, 26);
                essence.FrontAlpha = alphaCounter;
            }
            {
                RootCounterS alphaCounter = new RootCounterS();
                alphaCounter.Set(150, 15, 5);
                essence.BackAlpha = alphaCounter;
            }
            SpreadStringBlur instance = new SpreadStringBlur(essence);
            instance.SetStringUnicode(messages[rand.GetRand(messages.Length)]);
            instance.SetPosXY(320, 100);
            return instance;
        }

        private SpreadStringBlur CreateSpread2(FontRepository frontRep, FontRepository backRep)
        {
            int rad = 256;
            int step = 256;
            int startWidth = -30;
            int endWidth = 20;
            // エッセンス生成
            SpreadStringBlur.EssencePram essence = new SpreadStringBlur.EssencePram();
            essence.FrontFont = frontRep;
            essence.BackFont = backRep;
            essence.SpreadStartWidth = startWidth;
            essence.SpreadEndWidth = endWidth;
            essence.SpreadSpeed = step;
            essence.Rad = rad;
            essence.FrontRate = 2.0f;
            essence.BackRate = 8.0f;
            {
                RootCounterS alphaCounter = new RootCounterS();
                alphaCounter.Set(200, 15, 26);
                essence.FrontAlpha = alphaCounter;
            }
            {
                RootCounterS alphaCounter = new RootCounterS();
                alphaCounter.Set(150, 15, 5);
                essence.BackAlpha = alphaCounter;
            }
            SpreadStringBlur instance = new SpreadStringBlur(essence);
            instance.SetStringUnicode(messages[rand.GetRand(messages.Length)]);
            instance.SetPosXY(320, 150);
            return instance;
        }

        private SpreadStringBlur CreateSpread3(FontRepository frontRep, FontRepository backRep)
        {
            int rad = 0;
            int step = 256;
            int startWidth = -30;
            int endWidth = 20;
            // エッセンス生成
            SpreadStringBlur.EssencePram essence = new SpreadStringBlur.EssencePram();
            essence.FrontFont = frontRep;
            essence.BackFont = backRep;
            essence.SpreadStartWidth = startWidth;
            essence.SpreadEndWidth = endWidth;
            essence.SpreadSpeed = step;
            essence.Rad = rad;
            essence.FrontRate = 2.0f;
            essence.BackRate = 8.0f;
            {
                RootCounterS alphaCounter = new RootCounterS();
                alphaCounter.Set(200, 15, 26);
                essence.FrontAlpha = alphaCounter;
            }
            {
                RootCounterS alphaCounter = new RootCounterS();
                alphaCounter.Set(150, 15, 5);
                essence.BackAlpha = alphaCounter;
            }
            SpreadStringBlur instance = new SpreadStringBlur(essence);
            instance.SetStringUnicode(messages[rand.GetRand(messages.Length)]);
            instance.SetPosXY(320, 300);
            return instance;
        }

        private FontRepository CreateFontRepository(string fontFilename, int fontSize, int fontIndex, int max)
        {
            FontLoader fontLoader = CreateFontLoader(fontFilename, fontSize, fontIndex);
            fontLoaders.Add(fontLoader);
            return SetupFontRepository(fontLoader, 0, max);
        }

        /// FontLoader を動的につくるヘルパ (外部にもってくことも検討してちょ)
        private FontLoader CreateFontLoader(string fontFile, int fontSize, int fontIndex)
        {
            FontLoader fontloader = new FontLoader();
            fontloader.IsDefRelativePath = false;
            fontloader.LoadDefFile(CreateFontLoaderDefStr(fontFile, 0, fontSize, fontIndex));
            return fontloader;
        }

        /// FontRepository をつくるヘルパ (外部にもってくことも検討してちょ)
        private FontRepository SetupFontRepository(FontLoader fontloader, int fontNo, int max)
        {
            FontRepository fr = new FontRepository(YamalibConst.FONT_REP_TEXTURE_FACTORY);
            fr.SetLoader(fontloader, fontNo);
            fr.Max = max;
            return fr;
        }

        /// <summary>
        /// 指定したフォント定義からフォントローダを作成する。
        /// 文字列を一時ファイルに書き出してそれを読み込むのでsmartFontLoaderを使う意味はない。
        /// また、このメソッドで作成したFontLoaderは適宜Disposeすること。
        /// </summary>
        /// <param name="fontFile"></param>
        /// <param name="fontNo"></param>
        /// <param name="fontSize"></param>
        /// <param name="fontIndex"></param>
        /// <returns></returns>
        private string CreateFontLoaderDefStr(string fontFile, int fontNo, int fontSize, int fontIndex)
        {
            string defFileText = fontFile + "," + fontSize.ToString() + "," + fontIndex.ToString() + "," + fontNo.ToString();
            FileSys.TmpFile tmpFile = new FileSys.TmpFile(Encoding.Default.GetBytes(defFileText));
            fontDefTmpFile.Add(tmpFile);
            return tmpFile.FileName;
        }

        private string[] LoadMessage(string filename, int maxLength)
        {
            string strText = Yamalib.Util.YamalibUtility.ReadTextFile(filename);
            string[] strs = strText.Split(new char[] { '\r', '\n' });
            List<string> result = new List<string>();
            for (int i = 0; i < strs.Length; i++)
            {
                if (strs[i] == null || strs[i] == string.Empty)
                {
                    continue;
                }
                if (strs[i].Length > maxLength)
                {
                    result.Add(strs[i].Substring(0, maxLength));
                }
                else
                {
                    result.Add(strs[i]);
                }
            }

            return result.ToArray();
        }


    }
}
