using System;
using System.Collections.Generic;
using System.Text;
using Yanesdk.System;
using Kyojin.Model;
using Yamalib.Util;
using Kyojin.Component.Ending;
using Yanesdk.Draw;
using Yanesdk.Sound;
using Yanesdk.Timer;
using Yamalib.Input;
using Yamalib;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;

namespace Kyojin.Scene.Ending
{
    class EndingScene : TaskBase, IDisposable
    {
        #region 定数値

        private static bool SCREEN_CAP_FLG = false;

        #endregion

        #region メンバフィールド

        private GameSystem m_gSys;
        //private bool taskEnd;
        private RootCounterS fadeCounter;

        private TimingData[] timing1_1;
        private TimingData[] timing1_2;
        private TimingData[] timing1_3;
        private TimingData[] timing1_4;
        private TimingData[] timing1_5;
        private TimingData[] timing1_6;
        private TimingData[] timing1_7;
        private TimingData[] timing2_1;
        private TimingData[] timing2_2;
        private TimingData[] timing3_1;
        private TimingData[] timing3_2;
        private TimingData[] timing3_3;
        private TimingData[] timing3_4;
        private TimingData[] timing3_5;
        private TimingData[] timing3_6;
        private TimingData[] timing3_7;
        private TimingData[] timing4_1;
        private TimingData[] timing4_2;
        private TimingData[] timing4_3;
        private TimingData[] timing4_4;

        private bool init;
        private int startPart = 0;
        private IMouseInput mouse;
        private readonly FixTimer masterTimer;
        private TextuaryTempo textuaryTempo1;

        // 自動プレイ
        private bool m_autoPlay = false;
        // タイム表示
        private bool m_showTime = false;
        // 照準の表示
        private bool m_showAimMark = false;
        // スコア
        private bool m_showScore = false;

        private bool m_useMovie = false;

        private bool startScene01 = false;
        private bool startScene02 = false;
        private bool startScene03 = false;
        private bool startScene04 = false;
        private bool startScene05 = false;
        private EndingSceneBase scene01;
        private EndingSceneBase scene02;
        private EndingSceneBase scene03;
        private EndingSceneBase scene04;
        private EndingSceneBase scene05;

        private List<EndingSceneBase> activeScene = new List<EndingSceneBase>();

        // イベント用
        private TextureLoader statusImgLoader;
        private SoundLoader bgmLoader;

        private FontRepository m_fontRep;
        private string tempoText;

        #endregion

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="gameSystem"></param>
        public EndingScene(GameSystem gameSystem)
        {
            m_gSys = gameSystem;
            masterTimer = new FixTimer();
        }


        #region IDisposable メンバ

        public void Dispose()
        {
            statusImgLoader.Dispose();
            bgmLoader.Dispose();
            YamalibUtility.Dispose(m_fontRep);
            YamalibUtility.Dispose(scene01);
            YamalibUtility.Dispose(scene02);
            YamalibUtility.Dispose(scene03);
            YamalibUtility.Dispose(scene04);
            YamalibUtility.Dispose(scene05);
        }

        #endregion

        private long taskLoopCount = 0;
        private int startTime = 0;

        public override int Task(object o)
        {
            GameSystem gameSystem = (GameSystem)o;

            // タイマー調整
            if (SCREEN_CAP_FLG)
            {
                masterTimer.Time = (int)(startTime + (taskLoopCount * (1000 / 60.0f)));
                Console.WriteLine("time:" + masterTimer.Time);
            }
            masterTimer.Update();

            if (0 == OnMove(gameSystem))
            {
                return 0;
            }
            gameSystem.OnMoveCommon();
            if (!gameSystem.FpsTimer.ToBeSkip || SCREEN_CAP_FLG)
            {
                gameSystem.Screen.Select();
                OnPaint(gameSystem);
                gameSystem.OnDrawCommon();
                gameSystem.Screen.Update();
            }
            else
            {
                OnPaint(gameSystem);
                gameSystem.OnDrawCommon();
            }

            if (SCREEN_CAP_FLG)
            {
                if (0 == taskLoopCount % 4)
                {
                    StoreScreenShot();
                }
                taskLoopCount++;
            }

            return 1;
        }

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

            mouse.Update();
            m_gSys.Key.Update();
            textuaryTempo1.OnMove(m_gSys.Screen);

            // わけのわからんヒットされたら、hitCounter に教えてやる
            if (textuaryTempo1.IsInvalidHit())
            {
                EndingSceneBase.GamePointcalculator().CalcHitPoint(HitStatus.ERROR);
            }

            if (!startScene01 && scene01.IisStart)
            {
                activeScene.Add(scene01);
                ////Log.print("START SCENE [%s] %s", masterTimer.Get(), scene01.toString);
                startScene01 = true;
            }

            if (!startScene02 && scene02.IisStart)
            {
                activeScene.Add(scene02);
                ////Log.print("START SCENE [%s] %s", masterTimer.Get(), scene02.toString);
                startScene02 = true;
            }

            if (!startScene03 && scene03.IisStart)
            {
                activeScene.Add(scene03);
                ////Log.print("START SCENE [%s] %s", masterTimer.Get(), scene03.toString);
                startScene03 = true;
            }
            if (!startScene04 && scene04.IisStart)
            {
                activeScene.Add(scene04);
                ////Log.print("START SCENE [%s] %s", masterTimer.Get(), scene04.toString);
                startScene04 = true;
            }
            if (!startScene05 && scene05.IisStart)
            {
                textuaryTempo1.FadeStop(2500);
                activeScene.Add(scene05);
                ////Log.print("START SCENE [%s] %s", masterTimer.Get(), scene05.toString);
                startScene05 = true;
            }

            // シーン
            List<EndingSceneBase> aliveScene = new List<EndingSceneBase>();
            foreach (EndingSceneBase scene in activeScene)
            {
                if (scene == null)
                {
                    continue;
                }
                scene.OnMove(m_gSys.Screen);
                if (scene.IsEnd)
                {
                    ////Log.print("END SCENE %s", scene.toString);
                    scene.Release();
                    //scene = null;
                }
                else
                {
                    aliveScene.Add(scene);
                }
            }
            activeScene = aliveScene;

            if (scene05.IsEnd)
            {
                // フェードアウトしてシーン終了
                fadeCounter.Inc();
                if (fadeCounter.IsEnd)
                {
                    // ５万点以上なら、デバッグモードON
                    if (!m_autoPlay && 50000 <= EndingSceneBase.GamePointcalculator().TotalPoint)
                    {
                        m_gSys.ScenarioSceneParam.IsUseExtraMusic = true;
                    }
                    FinishScene();
                    return 0;
                }
            }
            return 1;
        }

        /// <summary>
        /// 描画処理
        /// </summary>
        /// <param name="gameSystem"></param>
        private void OnPaint(GameSystem gameSystem)
        {
            m_gSys.Screen.Clear();

            // シーン
            foreach (EndingSceneBase scene in activeScene)
            {
                scene.OnDraw(m_gSys.Screen);
            }

            m_gSys.Screen.BlendAddColorAlpha();
            textuaryTempo1.OnPaint(m_gSys.Screen);
            m_gSys.Screen.BlendSrcAlpha();

            // スコア表示
            if (m_showScore)
            {
                OnDrawScore(m_gSys.Screen, 0, 0);
            }

            // 時間表示
            if (m_showScore)
            {
                OnDrawTime(m_gSys.Screen, 450, 0);
            }

        }

        #region 非公開メンバ

        /// <summary>
        /// タスクの初期化
        /// </summary>
        private void OnInit()
        {
            //Log.print("ENDING SETUP START");

            // 動作オプション
            // オートプレイ
            m_autoPlay = m_gSys.KyojinEndingSceneParam.IsAutoPlay;
            // ガイド表示
            m_showAimMark = m_gSys.KyojinEndingSceneParam.IsShowGuide;
            // ムービー表示
            m_useMovie = m_gSys.KyojinEndingSceneParam.IsShowMovie||true;
            // タイム表示し
            m_showTime = m_gSys.KyojinEndingSceneParam.IsShowTime;
            // スコア表示
            m_showScore = m_gSys.KyojinEndingSceneParam.IsShowScore;

            // パフォーマンス測定 これやると環境によっておかしくなる
            //		long drawPerformance = GetDrawPerformance(info.screen);
            //		Log.print("DRAW PERFORMANCE:%s", drawPerformance);
            //		if (drawPerformance < 10000) {
            //			// ムービーON
            //		}

            Initialize();

            // ヒットヒストリーを初期化
            EndingSceneBase.GamePointcalculator().ClearStatusHistory();

            // リソース読み込み
            statusImgLoader = new TextureLoader();
            statusImgLoader.IsDefRelativePath = false;
            statusImgLoader.LoadDefFile("img2\\ending\\status.lst");


            bgmLoader = new SoundLoader();
            bgmLoader.IsDefRelativePath = false;
            bgmLoader.LoadDefFile("img2\\ending\\bgm.lst");

            startPart = 0;

            // ボリューム０で再生しておく
            bgmLoader.GetSound(startPart).Volume = 0.0f;
            bgmLoader.PlayBGM(startPart);

            mouse = m_gSys.KeyDecolateMouse;

            // フォントリポジトリをセット
            SetupFontRepository();

            // テンポ用テキストの見込み
            tempoText = Yamalib.Util.YamalibUtility.ReadTextFile("img2/ending/tempo_text.txt");
            // ならしておく
            foreach (char wch in tempoText.ToCharArray())
            {
                m_fontRep.GetTexture(wch, 0);
            }

            textuaryTempo1 = new TextuaryTempo();
            SetupTextuaryTempo(textuaryTempo1, CreateTempoData());
            //		textuaryTempo2 = new TextuaryTempo();
            //		SetupTextuaryTempo(textuaryTempo2);

            // OSスワップとかGCを考慮して 5秒待つ
            Sdl.SDL.SDL_Delay(5000);

            textuaryTempo1.Reset();

            // BGM再生		
            bgmLoader.GetSound(startPart).Volume = m_gSys.OptionInfo.BGMVolume / 100.0f;
            bgmLoader.PlayBGM(startPart);
            Sdl.SDL.SDL_Delay(250);
            //Log.print("BGM VOLUME:%s", bgmLoader.Get(startPart).GetVolume());

            switch (startPart)
            {
                case 0:
                    masterTimer.Reset();
                    break;
                case 1:
                    masterTimer.Time = (int)(64900 + EndingSceneBase.MUSIC_OFFSET_TIME);
                    break;
                case 2:
                    masterTimer.Time = (int)(88491 + EndingSceneBase.MUSIC_OFFSET_TIME);
                    break;
                case 3:
                    masterTimer.Time = (int)(152741 + EndingSceneBase.MUSIC_OFFSET_TIME);
                    break;
                case 4:
                    masterTimer.Time = (int)(195704 + EndingSceneBase.MUSIC_OFFSET_TIME);
                    break;
                default:
                    Debug.Assert(false);
                    break;
            }

            startTime = masterTimer.Time;
            //Log.print("ENDING SETUP FINISH");
        }


        private void Initialize()
        {
            scene01 = new Scene01(masterTimer);
            scene01.CacheTexture();
            timing1_1 = scene01.TimingData[0];
            timing1_2 = scene01.TimingData[1];
            timing1_3 = scene01.TimingData[2];
            timing1_4 = scene01.TimingData[3];
            timing1_5 = scene01.TimingData[4];
            timing1_6 = scene01.TimingData[5];
            timing1_7 = scene01.TimingData[6];

            scene02 = new Scene02(masterTimer);
            scene02.CacheTexture();
            timing2_1 = scene02.TimingData[0];
            timing2_2 = scene02.TimingData[1];

            //−−−−−−−−−−−−−
            scene03 = new Scene03(masterTimer, m_useMovie);
            scene03.CacheTexture();
            timing3_1 = scene03.TimingData[0];
            timing3_2 = scene03.TimingData[1];
            timing3_3 = scene03.TimingData[2];
            timing3_4 = scene03.TimingData[3];
            timing3_5 = scene03.TimingData[4];
            timing3_6 = scene03.TimingData[5];
            timing3_7 = scene03.TimingData[6];

            scene04 = new Scene04(masterTimer);
            scene04.CacheTexture();
            timing4_1 = scene04.TimingData[0];
            timing4_2 = scene04.TimingData[1];
            timing4_3 = scene04.TimingData[2];
            timing4_4 = scene04.TimingData[3];

            scene05 = new Scene05(masterTimer);
            scene05.CacheTexture();

            // フェードアウト用
            fadeCounter = new RootCounterS(255, 0, 1);
        }

        /// <summary>
        /// テキストテンポオブジェクトのセットアップ
        /// </summary>
        /// <param name="textuaryTempo"></param>
        /// <param name="tempoData"></param>
        private void SetupTextuaryTempo(TextuaryTempo textuaryTempo, List<TempoData> tempoData)
        {
            textuaryTempo.Mouse = mouse;
            textuaryTempo.FontRepository = m_fontRep;
            textuaryTempo.TempoData = tempoData;
            textuaryTempo.IsAutoPlay = m_autoPlay;

            // 開始・終端の設定
            textuaryTempo.StartPos.X = 900;
            textuaryTempo.StartPos.Y = 100;
            textuaryTempo.EndPos.X = 50;
            textuaryTempo.EndPos.Y = 700;

            // 文字サイズ
            textuaryTempo.StartRate = 0.5f;
            textuaryTempo.EndRate = 2.5f;

            // 文字生成
            textuaryTempo.GenerateInterval = 100L;

            // 許容マージン
            textuaryTempo.HitMargin = 100L;

            // ヒットポイント到達時間
            textuaryTempo.ArrivalTime = 1250L;

            if (m_showAimMark)
            {
                // 照準画像
                ITexture scopImg = YamalibConst.CreateTexture("img2/ending/scope.png");
                textuaryTempo.ScopeImg = scopImg;
            }

            // タイマーを一元化する
            textuaryTempo.Timer = masterTimer;
            textuaryTempo.AlphaCounter.Set(0, 200, 1);

            // Scene05用に設定
            ((Scene05)scene05).SetFontRepository(m_fontRep);
        }

        /** 実行しているマシンの描画パフォーマンスを調べる */
        private long GetDrawPerformance(IScreen screen)
        {
            Yanesdk.Timer.GameTimer performanceTimer = new Yanesdk.Timer.GameTimer();
            ITexture img = YamalibConst.CreateTexture("img2/ending/test.jpg");
            long loopCount = 0;
            while (performanceTimer.Time < 2000)
            {
                loopCount++;
                screen.Blt(img, 0, 0);
            }
            screen.Clear();
            return loopCount;
        }

        /// <summary>
        /// フォントリポジトリを用意する
        /// </summary>
        private void SetupFontRepository()
        {
            m_fontRep = new FontRepository(YamalibConst.FONT_REP_TEXTURE_FACTORY);
            m_fontRep.SetLoader(m_gSys.CommonFontLoader, KyojinConst.SCENARIO_KYOJIN_TEXT_FONT_NO);
            m_fontRep.Max = 10000;
        }

        /// <summary>
        /// スコアを描画する
        /// </summary>
        /// <param name="screen"></param>
        /// <param name="X"></param>
        /// <param name="Y"></param>
        private void OnDrawScore(IScreen screen, int x, int y)
        {
            int scorePoint = (int)EndingSceneBase.GamePointcalculator().TotalPoint;
            string scorePointStr = "SCORE:" + scorePoint;
            List<ITexture> pointTexture = new List<ITexture>();
            foreach (char w in scorePointStr.ToCharArray())
            {
                pointTexture.Add(m_fontRep.GetTexture(w, 0));
            }
            OnDrawNumberTexture(screen, pointTexture, x, y, 1.0f);
        }

        /// <summary>
        /// 時間を表示
        /// </summary>
        /// <param name="screen"></param>
        /// <param name="X"></param>
        /// <param name="Y"></param>
        private void OnDrawTime(IScreen screen, int x, int y)
        {
            string scorePointStr = "TIME:" + masterTimer.Time.ToString();
            List<ITexture> pointTexture = new List<ITexture>();
            foreach (char w in scorePointStr.ToCharArray())
            {
                pointTexture.Add(m_fontRep.GetTexture(w, 0));
            }
            OnDrawNumberTexture(screen, pointTexture, x, y, 1.0f);
        }

        /// <summary>
        /// テクスチャーを左詰で表示
        /// </summary>
        /// <param name="screen"></param>
        /// <param name="textures"></param>
        /// <param name="X"></param>
        /// <param name="Y"></param>
        /// <param name="sizeRate"></param>
        private void OnDrawNumberTexture(IScreen screen, List<ITexture> textures, int x, int y, float sizeRate)
        {
            Color4ub colorOrg = YanesdkUtil.GetNowScreenColor(screen);
            screen.SetColor(255, 255, 255, 128);
            // スコアの描画
            float ox = 0.0f;
            foreach (ITexture texture in textures)
            {
                screen.BltRotate(texture, x + (int)ox, y, 0, sizeRate, 0);
                ox += texture.Width * sizeRate + 3.0f;
            }
            screen.SetColor(colorOrg);
        }



        /// <summary>
        /// テンポデータ
        /// </summary>
        /// <returns></returns>
        private List<TempoData> CreateTempoData()
        {
            List<TempoData> result = new List<TempoData>();
            List<TimingData> timingData = new List<TimingData>();
            AddTimingData(timingData, timing1_1);
            AddTimingData(timingData, timing1_2);
            AddTimingData(timingData, timing1_3);
            AddTimingData(timingData, timing1_4);
            AddTimingData(timingData, timing1_5);
            AddTimingData(timingData, timing1_6);
            AddTimingData(timingData, timing1_7);
            AddTimingData(timingData, timing2_1);
            AddTimingData(timingData, timing2_2);
            AddTimingData(timingData, timing3_1);
            AddTimingData(timingData, timing3_2);
            AddTimingData(timingData, timing3_3);
            AddTimingData(timingData, timing3_4);
            AddTimingData(timingData, timing3_5);
            AddTimingData(timingData, timing3_6);
            AddTimingData(timingData, timing3_7);
            AddTimingData(timingData, timing3_6);
            AddTimingData(timingData, timing4_1);
            AddTimingData(timingData, timing4_2);
            AddTimingData(timingData, timing4_3);
            AddTimingData(timingData, timing4_4);

            TempoData tempoData = new TempoData(tempoText, timingData);

            result.Add(tempoData);

            return result;
        }

        private static void AddTimingData(List<TimingData> timingData, TimingData[] srcData)
        {
            foreach (TimingData data in srcData)
            {
                timingData.Add(data);
            }
        }


        /** エンディングタスクを終了してタイトルに戻る */
        private void FinishScene()
        {
            mouse.Show();
            // エンディング終了
            // すべてのスタックを破棄		
            m_gSys.SceneController.ExitScene();
            m_gSys.SceneController.JumpScene(Scenes.Startmenu);

            //Log.print("%s#OnMove : ALL SCENE FINISHED.", super.toString());
        }


        private long fileNo = 0;
        private Rectangle windowRect = new Rectangle(new System.Drawing.Point(0, 0), new System.Drawing.Size(640, 480));
        private string basePath = "d:\\img\\";

        private void StoreScreenShot()
        {
            Bitmap bmp = new Bitmap(
              windowRect.Width, windowRect.Height, PixelFormat.Format32bppArgb);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.CopyFromScreen(windowRect.X, windowRect.Y, 0, 0,
                  windowRect.Size, CopyPixelOperation.SourceCopy);

                //// ビット・ブロック転送方式の切り替え例：
                //g.FillRectangle(Brushes.LightPink,
                //  0, 0, drawRc.Width, drawRc.Height);
                //g.CopyFromScreen(drawRc.X, drawRc.Y, 0, 0,
                //  drawRc.Size, CopyPixelOperation.SourceAnd);
            }

            long dirNum = (fileNo / 500);
            if (fileNo % 500 == 0)
            {
                System.IO.DirectoryInfo dirInfo = new System.IO.DirectoryInfo(basePath + dirNum.ToString());
                dirInfo.Create();
            }

            string filePath = basePath + dirNum.ToString() + "\\" + fileNo.ToString() + ".bmp";

            bmp.Save(filePath, ImageFormat.Bmp);
            fileNo++;
        }


        #endregion


    }
}
