using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MikuMikuDance.XNA;
using MikuMikuDance.XNA.Forms.Graphics;
using Microsoft.Xna.Framework.Content;
using System.Windows.Forms;
using MikuMikuDance.XNA.Forms.Content;
using Microsoft.Xna.Framework.Graphics;

namespace MikuMikuDance.XNA.Forms
{
    /// <summary>
    /// MikuMikuDance for XNAのFormアプリケーション用拡張
    /// コントロールに対して描画するルーチンを提供
    /// </summary>
    public class MMDXExpantion
    {
        ServiceContainer container = new ServiceContainer();
        GraphicsDeviceService service = null;
        /// <summary>
        /// MMDXオブジェクト
        /// </summary>
        public MikuMikuDanceXNA MMDX { get; private set; }
        /// <summary>
        /// コンテントマネージャ
        /// </summary>
        public ContentManager Content { get; private set; }
        /// <summary>
        /// ターゲットコントロール
        /// </summary>
        public Control TargetControl { get; private set; }
        /// <summary>
        /// グラフィックスデバイス
        /// </summary>
        public GraphicsDevice GraphicsDevice { get { return service.GraphicsDevice; } }
        /// <summary>
        /// 既定のコンストラクタ
        /// </summary>
        /// <param name="target">ターゲットコントロール</param>
        public MMDXExpantion(Control target)
        {
            TargetControl = target;
            //GraphicsDeviceServiceに参照の追加
            service = GraphicsDeviceService.AddRef(target.Handle, target.Width, target.Height);
            //コンテナに追加
            container.AddService<IGraphicsDeviceService>(service);
            //コンテントマネージャの作成
            Content = new ContentManager(container);
            //MMDXの作成
            MMDX = new MikuMikuDanceXNA(Content);
        }
        /// <summary>
        /// オブジェクトの破棄。コントロールからDispose時にこのメソッドを呼び出す必要があります
        /// </summary>
        public void Dispose(bool disposing)
        {
            if (service != null)
            {
                service.Release(disposing);
                service = null;
            }
        }
        /// <summary>
        /// 描画の開始
        /// </summary>
        /// <returns>エラー文字列</returns>
        /// <remarks>描画の開始に失敗した場合はエラー文字列を返します</remarks>
        public string BeginDraw()
        {
            return BeginDraw(0, 0);
        }
        /// <summary>
        /// コントロールへの描画開始
        /// </summary>
        /// <param name="ViewX">描画するスクリーンがコントロールより広い場合の、スクリーン内でのコントロールのX座標</param>
        /// <param name="ViewY">描画するスクリーンがコントロールより広い場合の、スクリーン内でのコントロールのY座標</param>
        /// <returns>エラー文字列</returns>
        /// <remarks>描画の開始に失敗した場合はエラー文字列を返します</remarks>
        public string BeginDraw(int ViewX, int ViewY)
        {
            //デバイスの描画の大きさとロストチェック
            string deviceResetError = HandleDeviceReset();

            if (!string.IsNullOrEmpty(deviceResetError))
            {
                return deviceResetError;
            }
            //位置のチェック
            PresentationParameters pp = GraphicsDevice.PresentationParameters;
            //ビューポート設定
            Viewport vp = new Viewport();
            vp.X = Math.Min(ViewX, pp.BackBufferWidth - TargetControl.Width);
            vp.Y = Math.Min(ViewY, pp.BackBufferHeight - TargetControl.Height);
            vp.Width = TargetControl.Width;
            vp.Height = TargetControl.Height;
            vp.MinDepth = 0;
            vp.MaxDepth = 1;
            GraphicsDevice.Viewport = vp;
            return null;
        }
        // デバイスリセットチェック
        private string HandleDeviceReset()
        {
            bool ResetFlag = false;
            switch (GraphicsDevice.GraphicsDeviceStatus)
            {
                case GraphicsDeviceStatus.Lost:
                    return "Graphics Device Lost";
                case GraphicsDeviceStatus.NotReset:
                    ResetFlag = true;
                    break;
                default:
                    PresentationParameters pp = GraphicsDevice.PresentationParameters;
                    ResetFlag = (TargetControl.ClientSize.Width > pp.BackBufferWidth) ||
                                (TargetControl.ClientSize.Height > pp.BackBufferHeight);
                    break;
            }
            if (ResetFlag)
            {
                try
                {
                    service.ResetDevice(TargetControl.Width, TargetControl.Height);
                }
                catch (Exception e)
                {
                    return "Graphics Device Reset Failed\r\n" + e.ToString();
                }
            }
            return null;
        }
        /// <summary>
        /// コントロールへの描画を終了する
        /// </summary>
        /// <returns></returns>
        public void EndDraw()
        {
            try
            {
                Microsoft.Xna.Framework.Rectangle sourceRECT = new Microsoft.Xna.Framework.Rectangle(
                    GraphicsDevice.Viewport.X, GraphicsDevice.Viewport.Y, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
                GraphicsDevice.Present(sourceRECT, null, TargetControl.Handle);
            }
            catch { }
        }

        
    }
}
