using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using GraphiXNA.Graphics;
using GraphiXNA.MathHelpers;

namespace GraphiXNA.Cameras
{
    public class Camera
    {
        internal static Camera _ActiveCamera = new Camera();
        internal static bool isFirstCamera = true;

        public static Camera ActiveCamera
        {
            get
            {
                return _ActiveCamera;
            }
        }


        internal Rotation _Rotation = new Rotation(0.0f, 0, 0);
        public Vector3 Position;
        internal Matrix _Projection;
        internal Matrix _ViewProjection;
        internal Matrix _View = Matrix.Identity;
        internal Matrix _ViewInverse = Matrix.Identity;

        internal float NearPlane = 1;
        internal float FarPlane = 800;

        static Camera()
        {
        }


        public Camera()
        {
            SetProjectionPerspectiveFieldOfView(MathHelper.PiOver4, 4f / 3f, 1, 800);
            Commit();

            if (isFirstCamera)
            {
                isFirstCamera = false;
                Activate();
            }
        }

        public void Activate()
        {
            _ActiveCamera = this;
        }

        public virtual void Commit()
        {
            Matrix.CreateFromQuaternion(ref _Rotation._Quaternion, out _ViewInverse);
            _ViewInverse.Translation = Position;
            Matrix.Invert(ref _ViewInverse, out _View);
            Matrix.Multiply(ref _View, ref _Projection, out _ViewProjection);
        }

        public void SetProjectionPerspectiveFieldOfView(float fieldOfView, float aspectRatio, float zNear, float zFar)
        {
            Matrix.CreatePerspectiveFieldOfView(fieldOfView, aspectRatio, zNear, zFar, out _Projection);
            NearPlane = zNear;
            FarPlane = zFar;

            Matrix.Multiply(ref _View, ref _Projection, out _ViewProjection);
        }

        public void CopyTo(Camera camera)
        {
            camera._Rotation._Quaternion = _Rotation._Quaternion;
            camera.Position = Position;
            camera._Projection = _Projection;
            camera.Commit();
        }

        public Rotation Rotation
        {
            get
            {
                return _Rotation;
            }
        }

        public Matrix View
        {
            get
            {
                return _View;
            }
        }

        public Matrix Projection
        {
            get
            {
                return _Projection;
            }
        }

        public Matrix ViewProjection
        {
            get
            {
                return _ViewProjection;
            }
        }

        public Matrix ViewInverse
        {
            get
            {
                return _ViewInverse;
            }
        }

        public bool IsActiveCamera
        {
            get
            {
                return this == _ActiveCamera;
            }
        }

        public virtual void Update(GameTime gameTime)
        {
        }
    }
}
