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

namespace MegaManRipoff.MainGameClasses
{
    /// <summary>
    /// An element of a background, which can move independently to 
    /// the camera to create parallax effects.
    /// </summary>
    class BackgroundElement
    {
        #region Member Variables

        /// <summary>
        /// The texture of the current background element.
        /// </summary>
        Texture2D _texture;

        /// <summary>
        /// The name of this background element's texture.
        /// </summary>
        string _textureAssetName;

        /// <summary>
        /// The background this element belongs to.
        /// </summary>
        Background _background;

        /// <summary>
        /// Destination area that the texture will be drawn to.
        /// </summary>
        Vector2 _position;

        /// <summary>
        /// Whether or not the element texture tiles horizontally.
        /// </summary>
        bool _tileX;

        /// <summary>
        /// Whether or not the element texture tiles vertically.
        /// </summary>
        bool _tileY;

        /// <summary>
        /// The speed vector of the element.
        /// </summary>
        Vector2 _speed;

        /// <summary>
        /// The amount the element moves relative to the camera.
        /// A factor of 0 will not move relative to the camera.
        /// A factor of 1 will follow the camera exactly.
        /// </summary>
        Vector2 _scrollFactor;

        /// <summary>
        /// A vector that accumulates the speed vector.
        /// </summary>
        Vector2 _appliedSpeed;

        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new, non-moving background element.
        /// </summary>
        /// <param name="background">The background this element belongs to.</param>
        /// <param name="textureAssetName">The name of the asset for the background element's
        /// texture.</param>
        /// <param name="position">The position of the element relative to the room.</param>
        public BackgroundElement(Background background, string textureAssetName, Vector2 position)
        {
            _background = background;
            _position = position;
            _textureAssetName = textureAssetName;
        }

        /// <summary>
        /// Creates a new background element.
        /// </summary>
        /// <param name="background">The background this element belongs to.</param>
        /// <param name="textureAssetName">The name of the asset for the background element's
        /// texture.</param>
        /// <param name="position">The position of the element relative to the room.</param>
        /// <param name="tileX">Whether or not the element tiles horizontally.</param>
        /// <param name="tileY">Whether or not the element tiles vertically.</param>
        /// <param name="speed">The speed vector of the element.</param>
        /// <param name="scrollFactor">The amount the element moves relative to the camera.
        /// A factor of 0 will not move relative to the camera.
        /// A factor of 1 will follow the camera exactly.</param>
        public BackgroundElement(Background background, string textureAssetName, Vector2 position,
            bool tileX, bool tileY, Vector2 speed, Vector2 scrollFactor)
            : this(background, textureAssetName, position)
        {
            _tileX = tileX;
            _tileY = tileY;
            _speed = speed;
            _scrollFactor = scrollFactor;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Loads the content for this background element.
        /// </summary>
        /// <param name="content">The game's content manager.</param>
        /// <param name="assetPath">The directory of the background element's texture.</param>
        public void LoadContent(ContentManager content, string textureDirectory)
        {
            _texture = content.Load<Texture2D>(textureDirectory + _textureAssetName);
        }

        /// <summary>
        /// Updates the background element.
        /// </summary>
        /// <param name="gameTime">The current snapshot of time.</param>
        public void Update(GameTime gameTime)
        {
            //Move the texture according the speed vector.
            _appliedSpeed += _speed;
        }

        /// <summary>
        /// Draws the background element.
        /// </summary>
        /// <param name="spriteBatch">The sprite batch to draw to.</param>
        /// <param name="offset">The absolute offset of the current room.</param>
        /// <param name="cameraPosition">The absolute area that the camera currently occupies.</param>
        public void Draw(SpriteBatch spriteBatch, Rectangle roomArea, Rectangle cameraArea)
        {
            int destinationWidth, destinationHeight;

            //Calculate the drawing area based on how the element is set to tile.
            if (_tileX)
                destinationWidth = roomArea.Width - (int)_position.X;
            else
                destinationWidth = _texture.Width;

            if (_tileY)
                destinationHeight = roomArea.Height - (int)_position.Y;
            else
                destinationHeight = _texture.Height;

            //Draw the tiled background element, applying any parallax effects.
            spriteBatch.Draw(_texture,
                             new Rectangle(roomArea.Left + (int)_position.X,
                                           roomArea.Top + (int)_position.Y,
                                           destinationWidth,
                                           destinationHeight),
                             //This reeeaaalllly long line applies all the modifications to
                             //the position of the element and draws it. A source area larger
                             //than the texture means that it will tile (assuming that
                             //SamplerState is *Wrap).
                             new Rectangle(roomArea.Left + (int)_position.X - (int)(cameraArea.Left * _scrollFactor.X) - (int)_appliedSpeed.X,
                                           roomArea.Top + (int)_position.Y - (int)(cameraArea.Top * _scrollFactor.Y) - (int)_appliedSpeed.Y,
                                           destinationWidth,
                                           destinationHeight),
                             Color.White,
                             0,
                             Vector2.Zero,
                             SpriteEffects.None,
                             0.49f);
        }

        #endregion
    }
}
