using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace MikuMikuDance.XNA.Accessory
{
    /// <summary>
    /// 標準スクリーンマネージャクラス
    /// </summary>
    public class ScreenManager : IScreenManager, IDisposable
    {
        SpriteBatch spriteBatch;
        RenderTarget2D[] targets;
        Texture2D texture = null;
        int index;
        /// <summary>
        /// レンダリングターゲット
        /// </summary>
        public RenderTarget2D RenderTarget { get { return targets[index]; } }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public ScreenManager()
        {

        }
        /// <summary>
        /// コンストラクタ
        /// </summary>
        public ScreenManager(GraphicsDevice graphics)
        {
            PresentationParameters pp = graphics.PresentationParameters;
            Setup(graphics, pp.BackBufferWidth, pp.BackBufferHeight, 1, pp.BackBufferFormat,
                pp.MultiSampleType, pp.MultiSampleQuality, 2);
        }


        /// <summary>
        /// レンダリングターゲットを生成
        /// </summary>
        /// <param name="graphicDevice">グラフィックデバイス</param>
        /// <param name="width">幅</param>
        /// <param name="height">高さ</param>
        /// <param name="numberLevels">ミップマップレベル</param>
        /// <param name="format">フォーマット</param>
        /// <param name="NumTarget">フリップ数</param>
        /// <param name="multiSampleQuality">マルチサンプリングタイプ</param>
        /// <param name="multiSampleType">マルチサンプリングクォリティ</param>
        public void Setup(GraphicsDevice graphicDevice, int width, int height, int numberLevels,
            SurfaceFormat format, MultiSampleType multiSampleType, int multiSampleQuality, int NumTarget)
        {
            targets = new RenderTarget2D[NumTarget];
            for (int i = 0; i < NumTarget; i++)
            {
                targets[i] = new RenderTarget2D(graphicDevice, width, height, numberLevels, format, multiSampleType, multiSampleQuality);
            }
            //最終描画用のSpriteBatch作成
            spriteBatch = new SpriteBatch(graphicDevice);
        }

        /// <summary>
        /// 使用するレンダリングターゲットを切り替え
        /// </summary>
        public void Flip()
        {
            if (++index >= targets.Length)
                index = 0;
        }

        /// <summary>
        /// リソースの破棄
        /// </summary>
        public void Dispose()
        {
            for (int i = 0; i < targets.Length; ++i)
            {
                if (targets[i] != null)
                {
                    targets[i].Dispose();
                    targets[i] = null;
                }
            }
        }
        /// <summary>
        /// スクリーン用キャプチャの開始
        /// </summary>
        /// <param name="graphics"></param>
        public void Begin(GraphicsDevice graphics)
        {
            //レンダリングターゲット変更
            graphics.SetRenderTarget(0, RenderTarget);
        }
        /// <summary>
        /// スクリーン用キャプチャの終了
        /// </summary>
        /// <param name="graphics"></param>
        public void End(GraphicsDevice graphics)
        {
            graphics.SetRenderTarget(0, null);
            //画面をCornflowerBlue色で消去する
            graphics.Clear(Color.White);
            //spriteBatchを利用してRenderTargetを画面に書き出し
            spriteBatch.Begin(SpriteBlendMode.None,
                              SpriteSortMode.Immediate,
                              SaveStateMode.None);
            texture = RenderTarget.GetTexture();
            spriteBatch.Draw(texture, Vector2.Zero, Color.White);
            spriteBatch.End();
            IsDrawed = true;
            Flip();
        }

        #region IScreenManager メンバ
        long beforeTick = 0;
        bool IsDrawed = false;
        int m_ScreenMode = 1;
        /// <summary>
        /// スクリーンを取得する。
        /// </summary>
        /// <param name="totalTick">GameTime.TotalGameTime.Tickの値</param>
        /// <param name="tex">テクスチャ</param>
        /// <returns>1フレームの1回目ならtrue、2回目以降ならfalseを返す</returns>
        public bool GetScreenTex(long totalTick, out Texture2D tex)
        {
            if (targets == null || RenderTarget == null || ScreenMode == 9 || !IsDrawed)
                tex = null;
            else
                tex = texture;
            bool result = (totalTick > beforeTick);
            if (result)
                beforeTick = totalTick;
            return result;
        }
        /// <summary>
        /// スクリーンモード
        /// </summary>
        public int ScreenMode
        {
            get
            {
                return (IsDrawed ? m_ScreenMode : 0);
            }
            set { m_ScreenMode = value; }
        }

        /// <summary>
        /// スクリーンのズレ修正量
        /// </summary>
        public Vector2 ScreenFix
        {
            get {
                Vector2 result = new Vector2(RenderTarget.Width, RenderTarget.Height);
                if (result.X * 3.0f > result.Y * 4.0f)
                {
                    result.X = result.Y * 4.0f / 3.0f / result.X;
                    result.Y = 1.0f;
                }
                else
                {
                    result.Y = result.X * 3.0f / 4.0f / result.Y;
                    result.X = 1.0f;
                }
                return result;
            }
        }

        #endregion
    }
}
