/*
* FauxCanvas
* Visit http://createjs.com/ for documentation, updates and examples.
*
* Copyright (c) 2014 gskinner.com, inc.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

(function () {
	"use strict";

	/**
	 * Can be passed to a Stage in place of a Canvas element in order to eliminate the browser-specific cost of drawing graphics to screen, and thereby isolate the time spent in EaselJS.
	 * Still rough, and may be missing methods or properties that are necessary for certain features in EaselJS.
	 * 
	 * <b>Note:</b> You should disable DOM events with `myStage.enableDOMEvents(false)` to prevent errors generated by mouse events.
	 * @class FauxCanvas
	 * @param {Number} [width=300] The value for width property of the FauxCanvas instance.
	 * @param {Number} [height=150] The value for height property of the FauxCanvas instance.
	 * @param {Boolean} [replaceInternal=false] If true, FauxCanvas will be used for all EaselJS caches and offscreen canvases.
	 * @constructor
	 **/
	var FauxCanvas = function (width, height, replaceInternal) {
		this.initialize(width, height, replaceInternal);
	};
	var p = FauxCanvas.prototype;
	p.constructor = FauxCanvas;
	
	FauxCanvas.PROPERTIES = [
		// all browsers:
		"canvas","fillStyle","font","globalAlpha","globalCompositeOperation","lineCap","lineDashOffset","lineJoin","lineWidth","miterLimit","shadowBlur","shadowColor","shadowOffsetX","shadowOffsetY","strokeStyle","textAlign","textBaseline",
		// gecko / mozilla:
		"mozCurrentTransform","mozCurrentTransformInverse","mozDash","mozDashOffset","mozFillRule","mozImageSmoothingEnabled","mozTextStyle",
		// webkit:
		"webkitLineDash", "webkitLineDashOffset",
		// canvas:
		"style"
		];
	FauxCanvas.METHODS = [
		// all browsers:
		"arc","arcTo","beginPath","bezierCurveTo","clearRect","clip","closePath","createImageData","createLinearGradient","createPattern","createRadialGradient","drawCustomFocusRing","drawImage","drawSystemFocusRing","fill","fillRect","fillText","getImageData","getLineDash","isPointInPath","isPointInStroke","lineTo","measureText","moveTo","putImageData","quadraticCurveTo","rect","restore","rotate","save","scale","scrollPathIntoView","setLineDash","setTransform","stroke","strokeRect","strokeText","transform","translate",
		// gecko / mozilla:
		"asyncDrawXULElement","drawWindow","getFillStyle_multi","getImageData_explicit","getStrokeStyle_multi","mozDrawText","mozMeasureText","mozPathText","mozTextAlongPath","setFillStyle_multi","setStrokeStyle_multi",
		// webkit:
		"clearShadow","drawImageFromRect","setAlpha","setCompositeOperation","setLineWidth","setLineCap","setLineJoin","setMiterLimit","setStrokeColor","setFillColor","setShadow",
		// canvas:
		"addEventListener","removeEventListener",
		// webgl:
		"enable","blendFuncSeparate","pixelStorei","clearColor","viewport","attachShader","linkProgram","getProgramParameter","getProgramInfoLog","getAttribLocation","getUniformLocation","enableVertexAttribArray","useProgram","createShader","shaderSource","compileShader","getShaderParameter","createBuffer","bindBuffer","vertexAttribPointer","bufferData","bindTexture","texImage2D","texParameteri","activeTexture","uniform1i","uniformMatrix3fv","bufferSubData","drawElements","bindFrameBuffer","createFrameBuffer","uniform1iv","getShaderInfoLog","uniformMatrix4fv","uniformMatrix1i","createProgram","drawArrays","createTexture"
		];
	FauxCanvas.WEBGL_PROPERTIES = [
		"ACTIVE_TEXTURE","ALIASED_LINE_WIDTH_RANGE","ALIASED_POINT_SIZE_RANGE","ALPHA_BITS","ARRAY_BUFFER_BINDING","BLEND","BLEND_COLOR","BLEND_DST_ALPHA","BLEND_DST_RGB","BLEND_EQUATION_ALPHA","BLEND_EQUATION_RGB","BLEND_SRC_ALPHA","BLEND_SRC_RGB","BLUE_BITS","COLOR_CLEAR_VALUE","COLOR_WRITEMASK","COMPRESSED_TEXTURE_FORMATS","CULL_FACE","CULL_FACE_MODE","CURRENT_PROGRAM","DEPTH_BITS","DEPTH_CLEAR_VALUE","DEPTH_FUNC","DEPTH_RANGE","DEPTH_TEST","DEPTH_WRITEMASK","DITHER","ELEMENT_ARRAY_BUFFER_BINDING","FRAMEBUFFER_BINDING","FRONT_FACE","GENERATE_MIPMAP_HINT","GREEN_BITS","LINE_WIDTH","MAX_TEXTURE_MAX_ANISOTROPY_EXT","MAX_COMBINED_TEXTURE_IMAGE_UNITS","MAX_CUBE_MAP_TEXTURE_SIZE","MAX_FRAGMENT_UNIFORM_VECTORS","MAX_RENDERBUFFER_SIZE","MAX_TEXTURE_IMAGE_UNITS","MAX_TEXTURE_SIZE","MAX_VARYING_VECTORS","MAX_VERTEX_ATTRIBS","MAX_VERTEX_TEXTURE_IMAGE_UNITS","MAX_VERTEX_UNIFORM_VECTORS","MAX_VIEWPORT_DIMS","PACK_ALIGNMENT","POLYGON_OFFSET_FACTOR","POLYGON_OFFSET_FILL","POLYGON_OFFSET_UNITS","RED_BITS","RENDERBUFFER_BINDING","RENDERER","SAMPLE_BUFFERS","SAMPLE_COVERAGE_INVERT","SAMPLE_COVERAGE_VALUE","SAMPLES","SCISSOR_BOX","SCISSOR_TEST","SHADING_LANGUAGE_VERSION","STENCIL_BACK_FAIL","STENCIL_BACK_FUNC","STENCIL_BACK_PASS_DEPTH_FAIL","STENCIL_BACK_PASS_DEPTH_PASS","STENCIL_BACK_REF","STENCIL_BACK_VALUE_MASK","STENCIL_BACK_WRITEMASK","STENCIL_BITS","STENCIL_CLEAR_VALUE","STENCIL_FAIL","STENCIL_FUNC","STENCIL_PASS_DEPTH_FAIL","STENCIL_PASS_DEPTH_PASS","STENCIL_REF","STENCIL_TEST","STENCIL_VALUE_MASK","STENCIL_WRITEMASK","SUBPIXEL_BITS","TEXTURE_BINDING_2D","TEXTURE_BINDING_CUBE_MAP","UNPACK_ALIGNMENT","UNPACK_COLORSPACE_CONVERSION_WEBGL","UNPACK_FLIP_Y_WEBGL","UNPACK_PREMULTIPLY_ALPHA_WEBGL","VENDOR","VERSION","VIEWPORT"
		];

// initialization:
	/**
	 * Initialization method.
	 * @method initialize
	 * @protected
	 **/
	p.initialize = function (width, height, replaceInternal) {
		var methods = FauxCanvas.METHODS;
		for (var i= 0, l=methods.length; i<l; i++) {
			this[methods[i]] = function() { return {}; };
		}
		
		var props = FauxCanvas.PROPERTIES;
		for (i= 0, l=props.length; i<l; i++) {
			this[props[i]] = {};
		}
		
		this.width = width||300;
		this.height = height||150;
		
		if (replaceInternal) {
			createjs = createjs||{};
			createjs.createCanvas = function() {
				return new FauxCanvas();
			}
		}
	};

// public properties:

// private properties:

// public methods:
	
	/**
	 * Enables or disables logging by overriding (or restoring) the getContext method on the target canvas to return
	 * the FauxCanvas instance as a proxy for the "2d", "webgl", or "experimental-webgl" contexts.
	 * @method getContext
	 * @param {String} type
	 * @param {Object} options
	 **/
	p.getContext = function(type, options) {
		if (type == "2d") { return this; }

		if (type === "webgl" || type === "experimental-webgl"){
			var canvas = document.createElement("canvas");
			this._glCtx = canvas.getContext(type, options);

			var props = FauxCanvas.WEBGL_PROPERTIES;
			for (var i=0, l=props.length; i<l; i++) {
				this[props[i]] = this._glCtx[props[i]];
			}
			return this;
		}

		throw("Context not supported: "+type);
	};

	/**
	 * Mimics the return values of WebGl's context.
	 * @param {Number} type The parameter to look up.
	 */
	p.getParameter = function(type) {
		return this._glCtx.getParameter(type);
	};

// private methods:

	window.FauxCanvas = FauxCanvas;
})();
