using System;
using System.Collections.Generic;
using System.Text;

namespace Vortex.Drawing {
	///<summary>Represents two dimensional sprite grid with the tiles of the same size</summary>
	public class SpriteGrid : ISpriteCollection {
		private Sprite _originalSprite;
		private Sprite[] _sprites;
		private int _width;
		private int _height;

		#region Constructors

		/// <summary>
		/// Initializes a new instance of the <see cref="SpriteGrid"/> class.
		/// </summary>
		/// <param name="sourceSprite">The source sprite.</param>
		/// <param name="gridWidth">Width of the grid.</param>
		/// <param name="gridHeight">Height of the grid.</param>
		public SpriteGrid(Sprite sourceSprite, int gridWidth, int gridHeight) {
			if (null == sourceSprite) throw new ArgumentNullException("sourceSprite");
			if (gridWidth < 1) throw new ArgumentException("Grid width should be greater then 0 ", "gridWidth");
			if (gridHeight < 1) throw new ArgumentException("Grid height should be greater then 0 ", "gridHeight");

			_originalSprite = sourceSprite;
			_width = gridWidth;
			_height = gridHeight;
			_sprites = new Sprite[gridWidth * gridHeight];

			Rect region = _originalSprite.Region;
			Vector2 stepSize = region.Size / new Vector2(gridWidth, gridHeight);

			for (uint n = 0; n < gridWidth; ++n) {
				float left = region.Left + n * stepSize.X;
				for (uint m = 0; m < gridHeight; ++m) {
					float top = region.Top + m * stepSize.Y;
					_sprites[m * gridWidth + n] = new Sprite(_originalSprite.Texture, Rect.FromBox(left, top, stepSize.X, stepSize.Y));
				}
			}
		}

		#endregion

		#region Properties

		/// <summary>
		/// Gets the width of grid.
		/// </summary>
		/// <value>The width of grid.</value>
		public int Width {
			get { return _width; }
		}

		/// <summary>
		/// Gets the height of grid.
		/// </summary>
		/// <value>The height if grid.</value>
		public int Height {
			get { return _height; }
		}

		/// <summary>
		/// Gets the original sprite of this grid.
		/// </summary>
		/// <value>The original sprite.</value>
		public Sprite OriginalSprite {
			get { return _originalSprite; }
		}

		/// <summary>
		/// Gets the <see cref="Vortex.Drawing.Sprite"/> at the specified cell by x and y coordinates.
		/// </summary>
		/// <value><see cref="Sprite"/> instance</value>
		public Sprite this[int x, int y] {
			get {
				if (x >= 0 && y >= 0 && x < _width && y < _height) {
					return _sprites[x + y * _width];
				} else {
					throw new IndexOutOfRangeException(string.Format("Indices {0}x{1} are out of bounds for sprite grid with size {2}x{3}", x, y, _width, _height));
				}
			}
		}

		#endregion

		#region ISpriteCollection Members

		/// <summary>
		/// Gets the count of sprites in collection.
		/// </summary>
		/// <value>The count of sprites.</value>
		public int Count {
			get { return _sprites.Length; }
		}

		/// <summary>
		/// Gets the <see cref="Vortex.Drawing.Sprite"/> at the specified index.
		/// </summary>
		/// <value><see cref="Vortex.Drawing.Sprite"/> at specified index</value>
		public Sprite this[int index] {
			get { return _sprites[index]; }
		}

		/// <summary>
		/// Looks for sprite and returns its index in collection
		/// </summary>
		/// <param name="sprite">The sprite to find.</param>
		/// <returns>Index of sprite in collection or -1</returns>
		public int IndexOf(Sprite sprite) {
			for (int n = 0; n < _sprites.Length; ++n) {
				if (sprite == _sprites[n]) {
					return n;
				}
			}
			return -1;
		}

		#endregion

		#region IEnumerable<Sprite> Members

		/// <summary>
		/// Returns an enumerator that iterates through the collection.
		/// </summary>
		/// <returns>
		/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
		/// </returns>
		public IEnumerator<Sprite> GetEnumerator() {
			foreach (Sprite sprite in _sprites) {
				yield return sprite;
			}
		}

		#endregion

		#region IEnumerable Members

		/// <summary>
		/// Returns an enumerator that iterates through a collection.
		/// </summary>
		/// <returns>
		/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
		/// </returns>
		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
			return _sprites.GetEnumerator();
		}

		#endregion
	}
}
