using System;
using BulletX.BulletDynamics.Dynamics;
//using BulletCLI;

namespace MikuMikuDance.XNA.Model
{
    /// <summary>
    /// 物理演算のマネージャクラス
    /// </summary>
    public class MMDPhysicsManager
    {
        MMDBoneManager BoneManager;
        //MMDの剛体
        internal MMDRigidBody[] Rigids { get; private set; }
        //MMDのジョイント
        internal MMDPhysicJoint[] Joints { get; private set; }
        // コンストラクタ
        internal MMDPhysicsManager(MMDModel model, DiscreteDynamicsWorld Physic)
        {
            //初期化
            Rigids = new MMDRigidBody[model.ModelData.Rigids.Length];
            Joints = new MMDPhysicJoint[model.ModelData.Joints.Length];
            BoneManager = model.BoneManager;
            //剛体の作成
            for (int i = 0; i < model.ModelData.Rigids.Length; i++)
            {
                Rigids[i] = new MMDRigidBody(model.ModelData.Rigids[i], model, Physic);
            }
            //ジョイント(拘束)の作成
            for (int i = 0; i < model.ModelData.Joints.Length; i++)
            {
                MMDRigidBody phisic0 = Rigids[(int)model.ModelData.Joints[i].RigidBodyA];
                MMDRigidBody phisic1 = Rigids[(int)model.ModelData.Joints[i].RigidBodyB];
                Joints[i] = new MMDPhysicJoint(phisic0.body, phisic1.body, model.ModelData.Joints[i], Physic);
            }
            //剛体を関連ボーン番号をもとにソート
            Array.Sort(Rigids, new MMDPhisicsSorter());
        }
        internal void Update()
        {
            //剛体の運動差分→ボーンへの適応
            foreach (var i in Rigids)
            {
                i.ApplyRigitToBone();
            }
            //ボーンの運動→剛体への適応
            foreach (var i in Rigids)
            {
                i.ApplyBoneToRigit();
            }
        }
        /// <summary>
        /// 現在のボーンの位置に物理を合せる
        /// </summary>
        /// <remarks>少し重いです</remarks>
        public void ResetRigid(MMDModel model)
        {
            model.BoneManager.UpdateWorldTransforms();
            foreach (var i in Rigids)
            {
                i.ResetRigid();
            }
        }

        /// <summary>
        /// 現在のボーンの位置に物理を合せる
        /// </summary>
        /// <remarks>こちらはResetRigidと違いボーンのワールド座標系を更新せずに行います。軽い分正しく動作しない可能性があります</remarks>
        public void ResetRigidWithoutBoneUpdate()
        {
            foreach (var i in Rigids)
            {
                i.ResetRigid();
            }
        }
    }
}
