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

namespace MikuMikuDance.XNA.MultiThread
{
    /// <summary>
    /// マルチスレッド・マネージャ (元ネタは(http://www.sgtconker.com/2009/11/article-multi-threading-your-xna/))
    /// </summary>
    public class ThreadManager : IDisposable
    {
        internal GameTime gameTime { get; private set; }
        List<IGameThread> gameThreads = new List<IGameThread>();
        
        //GlobalSynchronizeが呼び出されない時の安全装置
        bool FrameStarted = false;

        /// <summary>
        /// 物理演算用ハードウェアスレッド番号(XBox360用)
        /// </summary>
        public const int PhysicsThreadNumber = 5;

        /// <summary>
        /// スレッドマネージャの作成
        /// </summary>
        public ThreadManager() {}
        /// <summary>
        /// スレッドのマネージャーへの登録
        /// </summary>
        /// <param name="gameThread">IGameThread</param>
        /// <remarks>GameThreadクラスは自動でこの処理を行う</remarks>
        public void AddThread(IGameThread gameThread)
        {
            gameThreads.Add(gameThread);
        }
        /// <summary>
        /// フレームの開始。Game.Updateの先頭で呼び出す。
        /// </summary>
        /// <param name="gameTime"></param>
        public void StartFrame(GameTime gameTime)
        {
            if (FrameStarted)
                Synchronize();//フレーム落ちか何かで呼ばれなかった。
            this.gameTime = gameTime;
            for (int i = 0; i < gameThreads.Count; i++)
            {
                gameThreads[i].StartFrame();
            }
            FrameStarted = true;
        }
        /// <summary>
        /// フレームの終了及び同期。Game.EndDrawの最後に呼び出す
        /// </summary>
        public void Synchronize()
        {
            for (int i = 0; i < gameThreads.Count; i++)
            {
                gameThreads[i].Synchronize();
            }
            FrameStarted = false;
        }

        #region IDisposable メンバ
        /// <summary>
        /// スレッドの破棄
        /// </summary>
        public void Dispose()
        {
            for (int i = 0; i < gameThreads.Count; )
            {
                gameThreads[0].Dispose();
                gameThreads.RemoveAt(0);
            }
        }

        #endregion
    }
}
