using System;
using System.Collections.Generic;
using System.IO;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Utilities;
using Microsoft.Xna.Framework.Windows;
using Microsoft.Xna.Framework.Design;
//using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Audio;

namespace PickupTheCrew
{
	public class Sprite
	{
		public string ID = Utilities.GetRandomId(); // the sprite's unique ID. Used when asving / loading who i sfollowing who.
		/*
		 *  ____           _ _   _             _             
		 * |  _ \ ___  ___(_) |_(_) ___  _ __ (_)_ __   __ _ 
		 * | |_) / _ \/ __| | __| |/ _ \| '_ \| | '_ \ / _` |
		 * |  __/ (_) \__ \ | |_| | (_) | | | | | | | | (_| |
		 * |_|   \___/|___/_|\__|_|\___/|_| |_|_|_| |_|\__, |
		 *                                             |___/ 
		 */
		public Vector2 StartPosition = Vector2.Zero;
		public Vector2 Position = Vector2.Zero;
		public Vector2 Speed = Vector2.Zero;
		public Vector2 Size = Vector2.Zero;

		/*
		 *     _                                                    
		 *    / \   _ __  _ __   ___  __ _ _ __ __ _ _ __   ___ ___ 
		 *   / _ \ | '_ \| '_ \ / _ \/ _` | '__/ _` | '_ \ / __/ _ \
		 *  / ___ \| |_) | |_) |  __/ (_| | | | (_| | | | | (_|  __/
		 * /_/   \_\ .__/| .__/ \___|\__,_|_|  \__,_|_| |_|\___\___|
		 *         |_|   |_|                                        
		 */
		public Texture2D Texture;
		public Vector2 TextureOrigin;
		public Color Colour = Color.White;
		public Rectangle DrawArea = new Rectangle();

		/*
		 *   ____                _                   _             
		 *  / ___|___  _ __  ___| |_ _ __ _   _  ___| |_ ___  _ __ 
		 * | |   / _ \| '_ \/ __| __| '__| | | |/ __| __/ _ \| '__|
		 * | |__| (_) | | | \__ \ |_| |  | |_| | (__| || (_) | |   
		 *  \____\___/|_| |_|___/\__|_|   \__,_|\___|\__\___/|_|   
		 *                                                         
		 */

		/// <summary>
		/// Constructs a new Sprite.
		/// </summary>
		/// <param name="inTexture">The texture to use.</param>
		/// <param name="inTextureOrigin">The origin of the texture. If omitted will be set to (0, 0).</param>
		/// <param name="inPosition">The initial position of the Sprite.</param>
		public Sprite(Texture2D inTexture, Vector2 inTextureOrigin, Vector2 inPosition)
		{
			Position = inPosition;
			StartPosition = Position;

			Texture = inTexture;

			Size.X = inTexture.Width;
			Size.Y = inTexture.Height;

			TextureOrigin = inTextureOrigin;
		}
		public Sprite(Texture2D inTexture, Vector2 inPosition) : this(inTexture, Vector2.Zero, inPosition)
		{
		}

		/*
		 *  __  __      _   _               _     
		 * |  \/  | ___| |_| |__   ___   __| |___ 
		 * | |\/| |/ _ \ __| '_ \ / _ \ / _` / __|
		 * | |  | |  __/ |_| | | | (_) | (_| \__ \
		 * |_|  |_|\___|\__|_| |_|\___/ \__,_|___/
		 *                                        
		 */
		/// <summary>
		/// Updates the sprite's position information.
		/// </summary>
		/// <param name="gameTime">The time since the last frame was drawn</param>
		/// <param name="game">A reference to the game that the sprite is part of.</param>
		public virtual void Update(GameTime gameTime, PickupTheCrew game)
		{
			Position.X += gameTime.ElapsedGameTime.Milliseconds * Speed.X;
			Position.Y += gameTime.ElapsedGameTime.Milliseconds * Speed.Y;

			// Clamp the Sprite's position to prevent it from going off the screen
			if (Position.X < 0)
				Position.X = 0;
			if (Position.Y < 0)
				Position.Y = 0;
			if (Position.X > game.GraphicsDevice.Viewport.Width - Size.X)
				Position.X = game.GraphicsDevice.Viewport.Width - Size.X;
			if (Position.Y > game.GraphicsDevice.Viewport.Height - Size.Y)
				Position.Y = game.GraphicsDevice.Viewport.Height - Size.Y;

			UpdateDrawArea();
		}

		/// <summary>
		/// Updates the DrawArea ready for rendering.
		/// </summary>
		public void UpdateDrawArea()
		{
			DrawArea.X = (int)(Position.X);
			DrawArea.Y = (int)(Position.Y);
			DrawArea.Width = (int)Size.X;
			DrawArea.Height = (int)Size.Y;
		}

		/// <summary>
		/// Draws the Sprite to the screen.
		/// </summary>
		/// <param name="gameTime">The time since the last frame was drawn.</param>
		/// <param name="spriteBatch">The SpriteBatch to use to draw the Sprite.</param>
		public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch)
		{
			spriteBatch.Draw(Texture, DrawArea, Colour);
		}

		/// <summary>
		/// Reset the Sprite.
		/// </summary>
		public virtual void Reset(PickupTheCrew game)
		{
			Position = StartPosition;
			Speed = Vector2.Zero;
		}

		/// <summary>
		/// Save the Sprite's data to a file.
		/// </summary>
		public virtual void Save(StreamWriter destination)
		{
			destination.WriteLine("type:{0}", this.GetType().Name);
			destination.Write("id:{0}|", ID);
			destination.Write("x:{0}|y:{1}|", Position.X, Position.Y);
			destination.Write("startx:{0}|starty:{1}|", StartPosition.X, StartPosition.Y);
			destination.Write("speedx:{0}|speedy:{1}|", Speed.X, Speed.Y);
			destination.Write("sizex:{0}|sizey:{1}|", Size.X, Size.Y);
			destination.Write("textureOriginX:{0}|textureOriginY:{1}|", TextureOrigin.X, TextureOrigin.Y);
			destination.Write("textureName:{0}", Texture.Name);
			//destination.Write("colour:{0}", Colour.ToString());

			destination.WriteLine();
		}

		/// <summary>
		/// Special constructor that takes a StreamReader as input.
		/// </summary>
		/// <param name="source">A StreamReader from which we can read a valid save file.</param>
		public Sprite(StreamReader source)
		{
			Dictionary<string, string> saveData = Utilities.DecodeSaveString(source.ReadLine());

			ID = saveData["id"];

			string textureName = saveData["textureName"];
			System.Diagnostics.Debug.WriteLine("textureName: " + textureName);
			foreach(string key in PickupTheCrew.textures.Keys)
			{
				System.Diagnostics.Debug.WriteLine("texture name: " + key);
			}
			Texture = PickupTheCrew.textures[textureName];

			TextureOrigin = new Vector2(float.Parse(saveData["textureOriginX"]), float.Parse(saveData["textureOriginY"]));

			Position = new Vector2(float.Parse(saveData["x"]), float.Parse(saveData["y"]));
			StartPosition = new Vector2(float.Parse(saveData["startx"]), float.Parse(saveData["starty"]));
			Size = new Vector2(float.Parse(saveData["sizex"]), float.Parse(saveData["sizey"]));
			Speed = new Vector2(float.Parse(saveData["speedx"]), float.Parse(saveData["speedy"]));
		}
	}
}
