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

namespace MegaManRipoff.UI
{
    /// <summary>
    /// An all-purpose 2D camera.
    /// </summary>
    class Camera
    {
        #region Member Variables

        /// <summary>
        /// The current graphics device.
        /// </summary>
        GraphicsDevice _graphicsDevice;

        /// <summary>
        /// Position of the top left of the viewport.
        /// </summary>
        protected Vector2 _position;

        /// <summary>
        /// The width of the camera view.
        /// </summary>
        public const int VIEWPORT_WIDTH = 512;

        /// <summary>
        /// The height of the camera view.
        /// </summary>
        public const int VIEWPORT_HEIGHT = 288;

        /// <summary>
        /// Vector representing the proportion between the size
        /// of the in-game viewport and the size of the game's window.
        /// </summary>
        Vector2 _scale;

        /// <summary>
        /// Holds the matrix scale transformation of the camera.
        /// </summary>
        Matrix _scaleTransformation;

        /// <summary>
        /// Holds the matrix scale and translation transformation of the camera.
        /// </summary>
        Matrix _transformation;

        #endregion

        #region Properties

        /// <summary>
        /// Gets the area that the camera is displaying.
        /// </summary>
        public Rectangle Area
        {
            get { return new Rectangle((int)_position.X, (int)_position.Y,
                VIEWPORT_WIDTH, VIEWPORT_HEIGHT); }
        }

        /// <summary>
        /// Gets or sets the centre point for the camera.
        /// </summary>
        public Vector2 FocusPoint
        {
            get
            { 
                return new Vector2(_position.X + (VIEWPORT_WIDTH / 2),
                                     _position.Y + (VIEWPORT_HEIGHT / 2)); 
            }
            set
            {
                _position = new Vector2(value.X - (VIEWPORT_WIDTH / 2),
                                        value.Y - (VIEWPORT_HEIGHT / 2)); 
            }
        }

        /// <summary>
        /// Gets the camera's matrix scale and translation transformation.
        /// </summary>
        public Matrix Transformation
        {
            get { return _transformation; }
        }

        /// <summary>
        /// Gets the camera's matrix scale transformation.
        /// </summary>
        public Matrix ScaleTransformation
        {
            get { return _scaleTransformation; }
        }

        #endregion

        /// <summary>
        /// Creates a new camera.
        /// </summary>
        /// <param name="graphicsDevice">The current graphics device.</param>
        /// <param name="position">The position of the camera.</param>
        public Camera(GraphicsDevice graphicsDevice, Vector2 position)
        {
            _graphicsDevice = graphicsDevice;
            _position = position;
        }

        #region Methods

        /// <summary>
        /// Updates the camera's transformation matrix.
        /// </summary>
        public virtual void Update()
        {
            //Update the scale based on the game's window size.
            _scale.X = _graphicsDevice.Viewport.Width / (float)VIEWPORT_WIDTH;
            _scale.Y = _graphicsDevice.Viewport.Height / (float)VIEWPORT_HEIGHT;

            _scaleTransformation = Matrix.Identity *
                                   Matrix.CreateScale(new Vector3(_scale.X, _scale.Y, _scale.X));

            _transformation = Matrix.Identity *
                              Matrix.CreateTranslation((int)-_position.X, (int)-_position.Y, 0) *
                              Matrix.CreateScale(new Vector3(_scale.X, _scale.Y, _scale.X));
        }

        #endregion
    }
}
