using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MikuMikuDance.XNA.Motion.MotionData;

namespace MikuMikuDance.XNA.Stages
{
    /// <summary>
    /// カメラ・ライト用のモーションクラス
    /// </summary>
    public class MMDStageMotion
    {
        //内部データ
        internal MMDMotionData MotionData { get; private set; }
        internal MikuMikuDanceXNA mmdXNA { get; private set; }
        internal bool ToCameraUse = true;
        internal long MaxFrame { get { return ToCameraUse ? MotionData.CameraMotions.Last().FrameNo : MotionData.LightMotions.Last().FrameNo; } }

        internal MMDStageMotion() { }//外から作らせない
        internal void Initialize(MMDMotionData motionData, MikuMikuDanceXNA mmdxna)
        {
            MotionData = motionData;
            mmdXNA = mmdxna;
        }
        internal void GetCameraData(decimal NowFrame, out float Length, out Vector3 Locate, out Quaternion Rotate, out float ViewAngle)
        {
            //前後のフレームをチェック
            long BeforePos = 0;
            long NextPos = 0;
            for (NextPos = 0; NextPos < MotionData.CameraMotions.Length; NextPos++)
            {
                if (MotionData.CameraMotions[NextPos].FrameNo > NowFrame)
                    break;
            }
            BeforePos = NextPos - 1;
            if (NextPos >= MotionData.CameraMotions.Length)
            {
                if (BeforePos == -1)
                {
                    //モーションが無い……？
                    //仕方ないのでMMDのデフォルト値挿入
                    Length = 35;
                    Locate = new Vector3(0, 10, 0);
                    Rotate = Quaternion.Identity;
                    ViewAngle = MathHelper.PiOver4;
                }
                else
                {
                    Length = MotionData.CameraMotions[BeforePos].Length;
                    Locate = MotionData.CameraMotions[BeforePos].Location;
                    Rotate = MotionData.CameraMotions[BeforePos].Quatanion;
                    ViewAngle = MotionData.CameraMotions[BeforePos].ViewAngle;
                }
            }
            else if (BeforePos == -1)
            {
                Length = MotionData.CameraMotions[NextPos].Length;
                Locate = MotionData.CameraMotions[NextPos].Location;
                Rotate = MotionData.CameraMotions[NextPos].Quatanion;
                ViewAngle = MotionData.CameraMotions[NextPos].ViewAngle;
            }
            else
            {

                float Progress = ((float)(NowFrame - MotionData.CameraMotions[BeforePos].FrameNo)) / ((float)(MotionData.CameraMotions[NextPos].FrameNo - MotionData.CameraMotions[BeforePos].FrameNo));
                float ProgX, ProgY, ProgZ;
                ProgX = MotionData.CameraMotions[NextPos].Curve[0].Evaluate(Progress);
                ProgY = MotionData.CameraMotions[NextPos].Curve[1].Evaluate(Progress);
                ProgZ = MotionData.CameraMotions[NextPos].Curve[2].Evaluate(Progress);
                float ProgR = MotionData.CameraMotions[NextPos].Curve[3].Evaluate(Progress);
                float ProgLen = MotionData.CameraMotions[NextPos].Curve[4].Evaluate(Progress);
                float ProgVA = MotionData.CameraMotions[NextPos].Curve[5].Evaluate(Progress);

                float x, y, z;
                x = MathHelper.Lerp(MotionData.CameraMotions[BeforePos].Location.X, MotionData.CameraMotions[NextPos].Location.X, ProgX);
                y = MathHelper.Lerp(MotionData.CameraMotions[BeforePos].Location.Y, MotionData.CameraMotions[NextPos].Location.Y, ProgY);
                z = MathHelper.Lerp(MotionData.CameraMotions[BeforePos].Location.Z, MotionData.CameraMotions[NextPos].Location.Z, ProgZ);

                Locate = new Vector3(x, y, z);
                Rotate = Quaternion.Slerp(MotionData.CameraMotions[BeforePos].Quatanion, MotionData.CameraMotions[NextPos].Quatanion, ProgR);
                Length = MathHelper.Lerp(MotionData.CameraMotions[BeforePos].Length, MotionData.CameraMotions[NextPos].Length, ProgLen);
                ViewAngle = MathHelper.Lerp(MotionData.CameraMotions[BeforePos].ViewAngle, MotionData.CameraMotions[NextPos].ViewAngle, ProgVA);
            }
        }

        internal void GetLightData(decimal NowFrame, out Vector3 Direction, out Color Color)
        {
            //前後のフレームをチェック
            long BeforePos = 0;
            long NextPos = 0;
            for (NextPos = 0; NextPos < MotionData.LightMotions.Length; NextPos++)
            {
                if (MotionData.LightMotions[NextPos].FrameNo > NowFrame)
                    break;
            }
            BeforePos = NextPos - 1;
            if (NextPos >= MotionData.LightMotions.Length)
            {
                if (BeforePos == -1)
                {
                    //モーションが無い……？
                    //仕方ないのでMMDのデフォルト値挿入
                    Direction = new Vector3(-0.5f, -1f, -0.5f);
                    Color = new Color(154, 154, 154);
                }
                else
                {
                    Direction = MotionData.LightMotions[BeforePos].Location;
                    Color = new Color(MotionData.LightMotions[BeforePos].Color);
                }
            }
            else if (BeforePos == -1)
            {
                Direction = MotionData.LightMotions[NextPos].Location;
                Color = new Color(MotionData.LightMotions[NextPos].Color);
            }
            else
            {
                float Progress = ((float)(NowFrame - MotionData.LightMotions[BeforePos].FrameNo)) / ((float)(MotionData.LightMotions[NextPos].FrameNo - MotionData.LightMotions[BeforePos].FrameNo));
                Direction = Vector3.Lerp(MotionData.LightMotions[BeforePos].Location, MotionData.LightMotions[NextPos].Location, Progress);
                Color = new Color(Vector3.Lerp(MotionData.LightMotions[BeforePos].Color, MotionData.LightMotions[NextPos].Color, Progress));
            }
        }
    }
}
