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

namespace Vortex.Drawing {
	/// <summary>
	/// Contains list of operators which provides easy-to-use canvas state scoped shortcuts '<='
	/// </summary>
	public abstract class StateScope : IDisposable {
		///<summary>Previous scope in scope chain</summary>
		protected StateScope _prevScope;

		/// <summary>
		/// Initializes a new instance of the <see cref="StateScope"/> class.
		/// </summary>
		protected StateScope() {
		}

		/// <summary>
		/// Initializes a <see cref="StateScope"/> with a previous scope.
		/// </summary>
		/// <param name="prevScope">The previous scope in scope chain.</param>
		protected StateScope(StateScope prevScope) {
			_prevScope = prevScope;
		}

		/// <summary>
		/// Gets the referred canvas .
		/// </summary>
		/// <value>The canvas instance.</value>
		protected virtual Canvas2D ReferredCanvas {
			get { return _prevScope.ReferredCanvas; }
		}

		/// <summary>
		/// Closes the scope: setting initial canvas state, closing previous scope in chain...
		/// </summary>
		protected virtual void CloseScope() {
			_prevScope.CloseScope();
		}

		#region Canvas Operators

		public static StateScope operator <=(StateScope scope, VertexShader state) {
			return new CanvasStateScopes.VertexShaderScope(scope, state);
		}

		public static StateScope operator <=(StateScope scope, PixelShader state) {
			return new CanvasStateScopes.PixelShaderScope(scope, state);
		}

		public static StateScope operator <=(StateScope scope, CanvasBrush state) {
			return new CanvasStateScopes.CanvasBrushScope(scope, state);
		}

		public static StateScope operator <=(StateScope scope, AlphaTest state) {
			return new CanvasStateScopes.AlphaTestScope(scope, state);
		}

		public static StateScope operator <=(StateScope scope, ZEffect state) {
			return new CanvasStateScopes.ZEffectScope(scope, state);
		}

		public static StateScope operator <=(StateScope scope, Blending state) {
			return new CanvasStateScopes.BlendingScope(scope, state);
		}

		public static StateScope operator <=(StateScope scope, Clipping state) {
			return new CanvasStateScopes.ClippingScope(scope, state);
		}

		public static StateScope operator <=(StateScope scope, TextureIndex state) {
			return new CanvasStateScopes.TextureIndexScope(scope, state);
		}

		/// <summary>
		/// Implements the operator &lt;= for applying transform.
		/// </summary>
		/// <param name="scope">The parent scope.</param>
		/// <param name="transform">The transform to apply.</param>
		/// <returns>The result of the operator - new scope.</returns>
		public static StateScope operator <=(StateScope scope, Transform2D transform) {
			return new CanvasStateScopes.TransformScope(scope, ref transform, false);
		}

		/// <summary>
		/// Implements the operator &lt; for overriding transform.
		/// </summary>
		/// <param name="scope">The parent scope.</param>
		/// <param name="transform">The transform to override.</param>
		/// <returns>The result of the operator - new scope.</returns>
		public static StateScope operator <(StateScope scope, Transform2D transform) {
			return new CanvasStateScopes.TransformScope(scope, ref transform, true);
		}

		/// <summary>
		/// Implements the operator &lt;= for applying transform.
		/// </summary>
		/// <param name="scope">The parent scope.</param>
		/// <param name="transform">The transform to apply.</param>
		/// <returns>The result of the operator - new scope.</returns>
		public static StateScope operator <=(StateScope scope, ITransform transform) {
			if (null == transform) throw new ArgumentNullException("transform");

			Transform2D temp;
			transform.GetTransform(out temp);
			return new CanvasStateScopes.TransformScope(scope, ref temp, false);
		}

		/// <summary>
		/// Implements the operator &lt; for overriding transform.
		/// </summary>
		/// <param name="scope">The parent scope.</param>
		/// <param name="transform">The transform to override.</param>
		/// <returns>The result of the operator - new scope.</returns>
		public static StateScope operator <(StateScope scope, ITransform transform) {
			if (null == transform) throw new ArgumentNullException("transform");

			Transform2D temp;
			transform.GetTransform(out temp);
			return new CanvasStateScopes.TransformScope(scope, ref temp, true);
		}

		public static StateScope operator <=(StateScope scope, float zValue) {
			return new CanvasStateScopes.ZValueScope(scope, zValue);
		}

		#endregion

		#region Just for C# Compiler

		public static StateScope operator >=(StateScope scope, VertexShader state) {
			throw new NotImplementedException();
		}

		public static StateScope operator >=(StateScope scope, PixelShader state) {
			throw new NotImplementedException();
		}

		public static StateScope operator >=(StateScope scope, CanvasBrush state) {
			throw new NotImplementedException();
		}

		public static StateScope operator >=(StateScope scope, AlphaTest state) {
			throw new NotImplementedException();
		}

		public static StateScope operator >=(StateScope scope, ZEffect state) {
			throw new NotImplementedException();
		}

		public static StateScope operator >=(StateScope scope, Blending state) {
			throw new NotImplementedException();
		}

		public static StateScope operator >=(StateScope scope, Clipping state) {
			throw new NotImplementedException();
		}

		public static StateScope operator >=(StateScope scope, TextureIndex state) {
			throw new NotImplementedException();
		}

		public static StateScope operator >=(StateScope scope, Transform2D transform) {
			throw new NotImplementedException();
		}

		public static StateScope operator >(StateScope scope, Transform2D transform) {
			throw new NotImplementedException();
		}

		public static StateScope operator >=(StateScope scope, ITransform transform) {
			throw new NotImplementedException();
		}

		public static StateScope operator >(StateScope scope, ITransform transform) {
			throw new NotImplementedException();
		}

		public static StateScope operator >=(StateScope scope, float zValue) {
			throw new NotImplementedException();
		}

		#endregion

		#region IDisposable Members

		/// <summary>
		/// Tricky method for using canvas state changes with operator 
		/// </summary>
		public void Dispose() {
			CloseScope();
		}

		#endregion
	}
}
