/**
 * Create a HTML5 canvas element.
 * 
 * The `ep.canvas()` function creates canvas elements which also work in older browsers without
 * native canvas support (like the Internet Explorer 7 and 8). Therefor the excanvas and canvastext
 * plugins are used.
 * 
 * The plugin offers the default methods and attributes from the canvas api and a multiline text drawing
 * method.
 * 
 * ### Examples
 * Create a canvas and draw on it
 * 
 * JavaScript:
 * 
 *     $('<canvas />')
 *       .appendTo('body')
 *       .canvas()
 *         .fillStyle('#4E8DA6')
 *         .fillRect(10, 10, 200, 100)
 *         .strokeStyle('#F2EA79')
 *         .lineWidth(5)
 *         .lineJoin('round')
 *         .strokeRect(10, 10, 200, 100)
 *         .fillStyle('#011C40')
 *         .multiline({
 *            x: 40,
 *            y: 40,
 *            phi: 15,
 *            text: "Hello World",
 *            fontSize: 22,
 *            fontFamily: "Arial",
 *            align: 'center',
 *            delimiter: "\n",
 *            rp: 'c',
 *            style: 'fillText'
 *         });
 * 
 * 
 * @class jQuery.canvas
 * 
 * @uses jQuery.canvas.excanvas
 * @uses jQuery.canvas.canvastext
 * @since 6.14.0
 */

/**
 * Setter and getter method to define the fill color or style of a shape or text.
 * 
 * Possible color formats:
 * - color name as string
 * - rgb(a)
 * - hex
 * 
 * @param {Color, Style} [value] A value to define the color or style.
 * 
 * @method fillStyle
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Setter and getter method to define the stroke color or style of a shape or text.
 * 
 * Possible color formats:
 * - color name as string
 * - rgb(a)
 * - hex
 * 
 * @param {Color, Style} [value] A value to define the color or style.
 * 
 * @method strokeStyle
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Setter and getter method to define the width of a stroke.
 * 
 * @param {Float} [value] The width of the stroke being drawed.
 * 
 * @method lineWidth
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Setter and getter method to define the style of the ending of a line.
 * 
 * @param {String} [value] The style of the ending of the line (possible values: butt, round, square).
 * 
 * @method lineCap
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Setter and getter method to define the style of the corners of a line.
 * 
 * @param {String} [value] The style of the corners of the line (possible values: bevel, round,  miter).
 * 
 * @method lineJoin
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Setter and getter method to define the transparency of a drawing.
 * 
 * @param {Integer} [value] The value of the transparency.
 * 
 * @method globalAlpha
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Setter and getter method to define how shapes and drawings are positioned onto the canvas.
 * 
 * @param {String} [value] The position on the canvas (possible values: source-atop, source-in, source-out,source-over, destination-atop, destination-in, destination-out, destination-over, lighter, copy, xor,vendorName-operationName) .
 * 
 * @method globalCompositeOperation
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Setter and getter method to define the horizontal distance of a shadow.
 * 
 * @param {Integer} [value] The horizontal distance of the shadow.
 * 
 * @method shadowOffsetX
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Setter and getter method to define the vertical distance of a shadow.
 * 
 * @param {Integer} [value] The vertical distance of the shadow.
 * 
 * @method shadowOffsetY
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Setter and getter method to define the size of the blurring effect.
 * 
 * @param {Integer} [value] The size of the blurring effect.
 * 
 * @method shadowBlur
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Setter and getter method to define the color of a shadow.
 * 
 * @param {Color} [value] The color of the shadow.
 * 
 * @method shadowColor
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Setter and getter method to define the limit size of the corners in a line.
 * 
 * @param {Integer} [value] The limit size of the corners in a line.
 * 
 * @method miterLimit
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Setter and getter method to define the font properties used for writing on the canvas.
 * 
 * @param {String} [value] The font properties used for writing on the canvas.
 * 
 * @method font
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Draws a filled rectangle using the color/style of the fillStyle attribute.
 * 
 * @param {Float} x The x-coordinate of where to place the upperleft corner of the rectangle.
 * @param {Float} y The y-coordinate of where to place the upperleft corner of the rectangle.
 * @param {Float} width The width of the rectangle, in pixels.
 * @param {Float} height The height of the rectangle, in pixels.
 * 
 * @method fillRect
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Draws the lines of a rectangle using the color/style of the strokeStyle attribute.
 * 
 * @param {Float} x The x-coordinate of where to place the upperleft corner of the rectangle.
 * @param {Float} y The y-coordinate of where to place the upperleft corner of the rectangle.
 * @param {Float} width The width of the rectangle, in pixels.
 * @param {Float} height The height of the rectangle, in pixels.
 * 
 * @method strokeRect
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Clears a rectangle area. All pixels inside this area will be erased.
 * 
 * @param {Float} x The x-coordinate of where to place the upperleft corner of the rectangle.
 * @param {Float} y The y-coordinate of where to place the upperleft corner of the rectangle.
 * @param {Float} width The width of the rectangle, in pixels.
 * @param {Float} height The height of the rectangle, in pixels.
 * 
 * @method clearRect
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Draws an image onto the canvas.
 * 
 * @param {Image, Video, Canvas} img The image object to use in the drawing.
 * @param {Float} x The x coordinate of where to position the top-left corner of the image.
 * @param {Float} y The y coordinate of where to position the top-left corner of the image.
 * @param {Float} [width] The width of the drawing (image), in pixels.
 * @param {Float} [height] The height of the drawing (image), in pixels.
 * @param {Float} [dx] The x coordinate of where to position the clipped part of the image.
 * @param {Float} [dy] The y coordinate of where to position the clipped part of the image.
 * @param {Float} [dwidth] The width of the clipped part of the image, in pixels.
 * @param {Float} [dheight] The height of the clipped part of the image, in pixels.
 * 
 * @method drawImage
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Draws text on the canvas and fills it with the color set by the fillStyle attribute.
 * 
 * @param {String} text The text that will be written on the canvas.
 * @param {Float} x The canvas' x-coordinate of where to place the text.
 * @param {Float} y The canvas' y-coordinate of where to place the text.
 * @param {Float} [maxWidth] The maximum allowed width of the text, in pixels.
 * 
 * @method fillText
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Draws text on the canvas, without filling, using the color set by the strokeStyle attribute.
 * 
 * @param {String} text The text that will be written on the canvas.
 * @param {Float} x The canvas' x-coordinate of where to place the text.
 * @param {Float} y The canvas' y-coordinate of where to place the text.
 * @param {Float} [maxWidth] The maximum allowed width of the text, in pixels.
 * 
 * @method strokeText
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Measures the given text string, returns the result in pixels.
 * 
 * @param {String} text The text that will be measured.
 * 
 * @method measureText
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Rotates the drawings based on the given angle.
 * 
 * @param {Float} angle The value of the angle in degree.
 * 
 * @method rotate
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Scales the drawings based on the x and y parameters.
 * 
 * @param {Float} x The scaling factor of the the width.
 * @param {Float} y The scaling factor of the the height.
 * 
 * @method scale
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Moves the drawings horizontally and vertically.
 * 
 * @param {Float} x Moves the canvas horizontally to the given coordinate.
 * @param {Float} y Moves the canvas vertically to the given coordinate.
 * 
 * @method translate
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Pushes the current state onto the stack.
 * 
 * @method save
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Pops the top state on the stack, restoring the context to that state.
 * 
 * @method restore
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Creates a gradient object. Use this object as a value to the strokeStyle or fillStyle attributes.
 * 
 * @param {Float} x0 The x-coordinate of the start of the gradient.
 * @param {Float} y0 The y-coordinate of the start of the gradient.
 * @param {Float} x1 The x-coordinate of the end of the gradient.
 * @param {Float} y1 The y-coordinate of the end of the gradient.
 * 
 * @method createLinearGradient
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Creates a gradient object as a circle. Use this object as a value to the strokeStyle or fillStyle attributes.
 * 
 * @param {Float} x0 The x-coordinate of the start of the gradient.
 * @param {Float} y0 The y-coordinate of the start of the gradient.
 * @param {Float} r0 The radius of the start-circle of the gradient.
 * @param {Float} x1 The x-coordinate of the end of the gradient.
 * @param {Float} y1 The y-coordinate of the end of the gradient.
 * @param {Float} r1 The radius of the start-circle of the gradient.
 * 
 * @method createRadialGradient
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Creates a pattern from an image to be used by the fillStyle or strokeStyle attributes.
 * 
 * @param {Image} img The image object to use when creating the pattern.
 * @param {String} repeat Describes how the pattern will be repeated (possible values: repeat, repeat-x, repeat-y, no-repeat).
 * 
 * @method createPattern
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Creates a new imagedata object, containing data from the canvas.
 * 
 * @param {Float} x The x coordinate, in the canvas, of the rectangle-area you will get.
 * @param {Float} y The y coordinate, in the canvas, of the rectangle-area you will get.
 * @param {Float} width The width of the rectangle-area you will get.
 * @param {Float} height The height of the rectangle-area you will get.
 * 
 * @method getImageData
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Draws imagedata onto the canvas.
 * 
 * @param {Image} imgData The imagedata object to put on the canvas.
 * @param {Float} x The x coordinate, in the canvas, of where to put the drawings.
 * @param {Float} y The y coordinate, in the canvas, of where to put the drawings.
 * @param {Float} dirtyX The x coordinate, of the drawings you want to put onto the canvas.
 * @param {Float} dirtyY The y coordinate, of the drawings you want to put onto the canvas.
 * @param {Float} dirtyWidth The width of the drawings you want to put onto the canvas.
 * @param {Float} dirtyHeight The height of the drawings you want to put onto the canvas.
 * 
 * @method putImageData
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Creates a circle, or parts of a circle.
 * 
 * @param {Float} x The x-coordinate of the center of the circle.
 * @param {Float} y The y-coordinate of the center of the circle.
 * @param {Image} r The radius of the circle.
 * @param {Float} sAngle Specifies where in the circle's angle the drawing should start.
 * @param {Float} eAngle Specifies where in the circle's angle the drawing should end.
 * @param {Boolean} [clockwise] Specifies whether the drawing should be clockwise or not.
 * 
 * @method arc
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Creates an arc between two points.
 * 
 * @param {Float} x1 The x-coordinate of the beginning of the arc.
 * @param {Float} y1 The y-coordinate of the beginning of the arc.
 * @param {Float} x2 The x-coordinate of the end of the arc.
 * @param {Float} y2 The y-coordinate of the end of the arc.
 * @param {Float} r The radius of the arc.
 * 
 * @method arcTo
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Starts a new path, or clears the current path.
 * 
 * @method beginPath
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Creates a cubic Bezier curve from the current point in the path to the specified path.
 * 
 * @param {Float} x1 The x-coordinate of the first controlpoint.
 * @param {Float} y1 The y-coordinate of the first controlpoint.
 * @param {Float} x2 The x-coordinate of the second controlpoint.
 * @param {Float} y2 The y-coordinate of the second controlpoint.
 * @param {Float} x The x-coordinate of where to create the line to.
 * @param {Float} y The y-coordinate of where to create the line to.
 * 
 * @method bezierCurveTo
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Creates an area in the canvas, and this area is the only visible area in the canvas.
 * 
 * @method clip
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Creates a line (path) from the last point in the path, to the first point. Completes the path.
 * 
 * @method closePath
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Fills the current path with the selected colorh.
 * 
 * @method fill
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Returns a Boolean value, `true` if the specified point is in the path, otherwise `false`.
 * 
 * @param {Float} x The x-coordinate of the point.
 * @param {Float} y The y-coordinate of the point.
 * 
 * @method isPointInPath
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Creates a line from the last point in the path to the given point.
 * 
 * @param {Float} x The x-coordinate of where to create the line to.
 * @param {Float} y The y-coordinate of where to create the line to.
 * 
 * @method lineTo
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Moves the path to the specified point, without creating a line.
 * 
 * @param {Float} x The x-coordinate of where to move the path to.
 * @param {Float} y The y-coordinate of where to move the path to.
 * 
 * @method moveTo
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Creates a quadratic Bezier curve from the current point in the path to the specified path.
 * 
 * @param {Float} cpx The x-coordinate of the controlpoint.
 * @param {Float} cpy The y-coordinate of the controlpoint.
 * @param {Float} x The x-coordinate of where to create the line to.
 * @param {Float} y The y-coordinate of where to create the line to.
 * 
 * @method quadraticCurveTo
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Creates a rectangle.
 * 
 * @param {Float} x The canvas' x-coordinate of where to place the upperleft corner of the rectangle.
 * @param {Float} y The canvas' y-coordinate of where to place the upperleft corner of the rectangle.
 * @param {Float} width The width of the rectangle, in pixels.
 * @param {Float} height The height of the rectangle, in pixels.
 * 
 * @method rect
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/**
 * Creates a stroke/path described with the specified path methodse.
 * 
 * @method stroke
 * @member jQuery.canvas
 * 
 * @since 6.14.0
 */

/*
 * @copyright   © Copyright 2006-2012, epages GmbH, All Rights Reserved.
 *
 * @module      ep.canvas
 *
 * @base      http://canvas.quaese.de/
 *
 * @revision    $Revision: 1.9 $
 */

define("ep/canvas", ["jquery", "ep"].concat(this.HTMLCanvasElement ? [] : ["jquery/canvas/excanvas", "jquery/canvas/canvastext"]), function ($, ep) {

	var init = function(canvas){
			//if the context feature don't exist and the IE CanvasManager-Object is available
			if((!canvas.getContext) && (G_vmlCanvasManager !== undefined)){
				canvas = G_vmlCanvasManager.initElement(canvas);
			}

			// if the context feature exists
			if(canvas.getContext){
				canvas.ctx = canvas.getContext('2d');
				return canvas;
			}

			return null;
		},

		degToRad = function(angle){
			return angle * Math.PI/180;
		},

		calcDimensions = function(lineHeight, defaults, ctx){
			var multiLines = defaults.text.split(defaults.delimiter),
					multiObj = {},
					measureWidth = 0,
					newWidth, newHeight;

			// determine the max line width
			for(var i=0, iLen=multiLines.length; i<iLen; i++){
				multiObj[i] = {};
				multiObj[i].width = ctx.measureText(multiLines[i]).width;
				measureWidth = (multiObj[i].width > measureWidth)? multiObj[i].width : measureWidth;
			}

			var arcTan = Math.atan(measureWidth/(lineHeight*multiLines.length)),
					diagonal = Math.sqrt(measureWidth*measureWidth + lineHeight*multiLines.length*lineHeight*multiLines.length),
					newAngle = defaults.phi,
					argument = {};

			if(newAngle > 90 && newAngle < 180 || newAngle > 270 && newAngle < 360){
				argument.x = degToRad(newAngle) - arcTan - degToRad(90);
				argument.y = degToRad(180) - degToRad(newAngle) - arcTan ;
			}else{
				argument.x = degToRad(90) - degToRad(newAngle) - arcTan;
				argument.y = arcTan - degToRad(newAngle);
			}

			newWidth = Math.abs(Math.cos(argument.x) * diagonal);
			newHeight = Math.abs(Math.cos(argument.y) * diagonal);

			return {w: newWidth, h: newHeight, measureWidth: measureWidth, multiLines: multiLines, lineHeight: lineHeight};
		},

		qpCanvas = function(){

		},

		// extend qpCanvas-prototype with own attributes and methods
		// @ this   = canvas-element (collection)
		// @ this.ctx = context (getContext('2d') (collection)
		// @ this[0]  = first canvas-element
		// @ this[0]  = first context (getContext('2d'))
		fn = $.extend(qpCanvas.prototype, {
			length: 0,                      // length property
			push: Array.prototype.push,     // inherit push-method from Array-Object
			each: jQuery.fn.each,           // inherit each-method from JQuery-Object

			end: function(){                // simulate jQuery end-method
				return this.prevObject || $();
			},

			// calculates the dimensions of an multiline text
			// returns an object, containing some useful sizes/dimensions as
			// - w: (float) new width of surrounding canvas,
			// - h: (float) new height of surrounding canvas,
			// - innerW: (float) new width of text element,
			// - innerH: (float) new height of text element,
			// - measureWidth: (float) new width of text element,
			// - multiLines: (array) splitted text,
			// - lineHeight: (float) height of a single line,
			// - scale: (float) scale factor (can be set to a differ value from 1 when resizableCanvas is set to false),
			// - text: (string) text that fits into the maxHeight and maxWidth dimensions,
			// - x: (float) horizontal offset of multiline text in canvas element,
			// - y: (float) vertical offset of multiline text in canvas element
			rescaleDimensions: function(options){
				var defaults = $.extend({
					x: 0,                   // horizontal coordinate
					y: 0,                   // vertical coordinate
					style: 'fillText',      // text method (fillText or strokeText)
					fontSize: 12,           // font size
					fontFamily: 'Arial',    // font family
					fontUnit: 'pt',         // font unit
					phi: 0,                 // rotate angle (in degree)
					delimiter: "\n",        // delimter t o detect new lines
					align: "left",          // text align (left, right, center)
					rp: 'c',                // rotation coordinates: nw, n, ne, w, c (default), e, sw, s, se
					correctLineHeight: 0,   // useful to adjust the lineheight
					minSize: 10,            // minimal size a text can be scaled
					maxWidth: undefined,    // if set to an number, the multitext dimensions will be calculated depending to its borders
					maxHeight: undefined,   // if set to an number, the multitext dimensions will be calculated depending to its borders
					resizeCanvas: false,    // if set to true, the multiline will be trimmed so that it fits into the borders (maxWidth and/or maxHeight)
					resizable: true,        // if set to true font size will be scaled when size of multiline is greater than maxWidth and/or maxHeight and fit into the borders
					text: 'dummy\ndummy'
				}, options);

				// test text method
				defaults.style = (defaults.style.match(/fillText|strokeText/))? defaults.style : 'fillText';

				// set font
				this[0].ctx.save();
				this[0].ctx.font = defaults.fontSize + defaults.fontUnit + " " + defaults.fontFamily;

				// insert temp. div which contains the text
				var isOldIE = ($.browser.msie && parseInt($.browser.version, 10) < 9)? true : false,
						$textElem = $("<div />").html("QjÖ").css({
							'font-size': defaults.fontSize + defaults.fontUnit,
							'line-height': (isOldIE ? '150%' : ''),
							'font-family': defaults.fontFamily,
							'position': 'absolute',
							'left': '-9999px',
							'padding': 0
						});

				$((isOldIE ? 'body' : 'html')).append($textElem);

				var lineHeight = $textElem.height() + defaults.correctLineHeight, // get line-height for one text line
						scale = 1,
						newDimensions = calcDimensions(lineHeight, defaults, this[0].ctx),
						newWidth = newDimensions.w,
						newHeight = newDimensions.h,
						measureWidth = newDimensions.measureWidth,
						multiLines = newDimensions.multiLines,
						newInnerWidth = measureWidth,
						newInnerHeight = lineHeight * multiLines.length;

				// remove temp. text element again
				$textElem.remove();
				this[0].ctx.restore();

				return {
					lineHeight: lineHeight,
					scale: scale,
					newDimensions: newDimensions,
					newWidth: newWidth,
					newHeight: newHeight,
					measureWidth: measureWidth,
					multiLines: multiLines,
					newInnerWidth: newInnerWidth,
					newInnerHeight: newInnerHeight,
					defaults: defaults
				};
			},

			/**
			 * Calculates the size of a text.
			 * 
			 * @param {Float} [x] The canvas' x-coordinate of where to place the text.
			 * @param {Float} [y] The canvas' y-coordinate of where to place the text.
			 * @param {String} text The text that will be written on the canvas.
			 * @param {String} [style] The style of the text that will be written on the canvas (possible values: fillText, strokeText).
			 * @param {Float} [fontSize] The font size the text that will be written on the canvas.
			 * @param {String} [fontFamily] The font family of the text that will be written on the canvas.
			 * @param {String} [fontUnit] The font unit of the text that will be written on the canvas.
			 * @param {Float} [phi] The rotation angle (in degree) of the text that will be written on the canvas.
			 * @param {String} [rp] The point around the text will be rotated (possible values: nw, n, ne, w, c (default), e, sw, s, se).
			 * @param {String} [delimiter] The delimiter used to detect a new line.
			 * @param {String} [align] The text align of the text that will be written on the canvas.
			 * @param {Float} [maxWidth] The maximal width of the text drawing.
			 * @param {Float} [maxHeight] The maximal height of the text drawing.
			 * @param {Boolean} [resizeCanvas] A boolean that defines whether a text will be scaled if the maximum size is reached.
			 * @param {Boolean} [resizable] A boolean that defines whether a text will be trimmed if the maximum size is reached .
			 * @param {Float} [correctLineHeight] An offset to correct the line height.
			 * 
			 * @method calcTextDimensions
			 * @member jQuery.canvas
			 * 
			 * @since 6.14.0
			 */
			calcTextDimensions: function(options){
				this[0].ctx.save();

				var rescaledDimensions = this.rescaleDimensions(options),
						lineHeight = rescaledDimensions.lineHeight,
						scale = rescaledDimensions.scale,
						newDimensions = rescaledDimensions.newDimensions,
						newWidth = newDimensions.w,
						newHeight = newDimensions.h,
						measureWidth = newDimensions.measureWidth,
						multiLines = newDimensions.multiLines,
						newInnerWidth = measureWidth,
						newInnerHeight = lineHeight * multiLines.length,
						defaults = rescaledDimensions.defaults;

				// if multiline text should fit into borders
				if(defaults.maxWidth || defaults.maxHeight){

					if(defaults.resizable){
						var scaleWidth = defaults.maxWidth/newWidth,
							scaleHeight = defaults.maxHeight/newHeight,
							testScale = 1,
							rescaled = false;

						if(defaults.maxWidth && newWidth>defaults.maxWidth){
							testScale = scaleWidth;
						}
						if(defaults.maxHeight && newHeight>defaults.maxHeight){
							testScale = (scaleHeight < scale)? scaleHeight : scale;
						}

						if(testScale*newHeight < defaults.minSize*multiLines.length){
							rescaled = true;
							$.extend(options, {
								fontSize: defaults.fontSize*testScale * (defaults.minSize*multiLines.length)/(testScale*newHeight)
							});

							rescaledDimensions = this.rescaleDimensions(options);
							lineHeight = rescaledDimensions.lineHeight;
							scale = rescaledDimensions.scale;
							newDimensions = rescaledDimensions.newDimensions;
							newWidth = newDimensions.w;
							newHeight = newDimensions.h;
							measureWidth = newDimensions.measureWidth;
							multiLines = newDimensions.multiLines;
							newInnerWidth = measureWidth;
							newInnerHeight = lineHeight * multiLines.length;
							defaults = rescaledDimensions.defaults;
						}
					}

					// if text should be scaled so that it fits into borders (maxWidth & maxHeight)
					if(defaults.resizable && newHeight > defaults.minSize*multiLines.length && !rescaled){
						if(defaults.maxWidth && newWidth>defaults.maxWidth){
							scale = defaults.maxWidth/newWidth;
						}
						if(defaults.maxHeight && newHeight>defaults.maxHeight){
							scale = (defaults.maxHeight/newHeight < scale)? defaults.maxHeight/newHeight : scale;
						}
						defaults.fontSize *= scale;
					// if text should be trimmed so that it fits into borders (maxWidth & maxHeight)
					}else{
						if(defaults.resizeCanvas){

							while(newWidth>=defaults.maxWidth || newHeight>=defaults.maxHeight){
								defaults.text = defaults.text.substr(0, defaults.text.length-1);

								newDimensions = calcDimensions(lineHeight, defaults, this[0].ctx);
								newWidth = newDimensions.w;
								newHeight = newDimensions.h;
							}

							measureWidth = newDimensions.measureWidth;
							multiLines = newDimensions.multiLines;
							newInnerWidth = measureWidth;
							newInnerHeight = lineHeight * multiLines.length;
						}
					}

					newHeight = Math.ceil(scale*newHeight);
					newWidth = Math.ceil(scale*newWidth);
					newInnerHeight = Math.ceil(scale*newInnerHeight);
					newInnerWidth = Math.ceil(scale*newInnerWidth);
				}

				if(defaults.resizeCanvas || defaults.phi !== 0){
					defaults.x = 0.5 * (newWidth - newInnerWidth);
					defaults.y = 0.5 * (newHeight - newInnerHeight);
				}

				this[0].ctx.restore();

				return {
					w: newWidth,
					h: newHeight,
					innerW: newInnerWidth,
					innerH: newInnerHeight,
					measureWidth: measureWidth,
					multiLines: multiLines,
					lineHeight: lineHeight,
					scale: scale,
					text: defaults.text,
					x: defaults.x,
					y: defaults.y,
					fontSize: defaults.fontSize
				};
			},

			// multiline for canvas
			/**
			 * Draws a multiline text onto the selected canvas elements.
			 * 
			 * @param {Float} [x] The canvas' x-coordinate of where to place the text.
			 * @param {Float} [y] The canvas' y-coordinate of where to place the text.
			 * @param {String} text The text that will be written on the canvas.
			 * @param {String} [style] The style of the text that will be written on the canvas (possible values: fillText, strokeText).
			 * @param {Float} [fontSize] The font size the text that will be written on the canvas.
			 * @param {String} [fontFamily] The font family of the text that will be written on the canvas.
			 * @param {String} [fontUnit] The font unit of the text that will be written on the canvas.
			 * @param {Float} [phi] The rotation angle (in degree) of the text that will be written on the canvas.
			 * @param {String} [rp] The point around the text will be rotated (possible values: nw, n, ne, w, c (default), e, sw, s, se).
			 * @param {String} [delimiter] The delimiter used to detect a new line.
			 * @param {String} [align] The text align of the text that will be written on the canvas.
			 * @param {Float} [correctLineHeight] An offset to correct the line height.
			 * 
			 * @method multiline
			 * @member jQuery.canvas
			 * 
			 * @since 6.14.0
			 */
			multiline: function(options){
				var defaults = $.extend({
				x: 0,                   // horizontal coordinate
				y: 0,                   // vertical coordinate
				style: 'fillText',      // text method (fillText or strokeText)
				fontSize: 12,
	//        resizable: true,
				fontFamily: 'Arial',
				fontUnit: 'pt',
				phi: 0,                 // rotate angle (in degree)
				delimiter: "\n",        // delimter to detect new lines
				align: "left",          // text align (left, right, center)
				rp: 'c',                // rotation coordinates: nw, n, ne, w, c (default), e, sw, s, se
	//        maxWidth: undefined,
	//        maxHeight: undefined,
	//        resizeCanvas: false,
				correctLineHeight: 0,
				text: 'default'
				}, options);

				// execute multiline for every element in the jQuery-query
				return this.each(function(){

					// test text method
					defaults.style = (defaults.style.match(/fillText|strokeText/))? defaults.style : 'fillText';

					// set font
					this.ctx.font = defaults.fontSize + defaults.fontUnit + " " + defaults.fontFamily;

					// insert temp. div which contains the text
					var isOldIE = ($.browser.msie && parseInt($.browser.version, 10) < 9)? true : false,
							$textElem = $("<div />").html("QjÖ").css({
								'font-size': defaults.fontSize + defaults.fontUnit,
								'line-height': (isOldIE ? '150%' : ''),
								'font-family': defaults.fontFamily,
								'position': 'absolute',
								'left': '-9999px',
								'padding': 0
							});

					// append text element to body or html element - depending on used user agent
					$((isOldIE ? 'body' : 'html')).append($textElem);

					// get line-height for one text line
					var lineHeight = $textElem.height() + defaults.correctLineHeight,
							newDimensions = calcDimensions(lineHeight, defaults, this.ctx),
							scale = newDimensions.scale,
							newWidth = newDimensions.w,
							newHeight = newDimensions.h,
							measureWidth = newDimensions.measureWidth,
							multiLines = newDimensions.multiLines,
							multiObj = {};

					// remove temp. text element again
					$textElem.remove();

					// save context
					this.ctx.save();

					// determine the max line width
					for(var i=0, iLen=multiLines.length; i<iLen; i++){
						multiObj[i] = {};
						multiObj[i].width = this.ctx.measureText(multiLines[i]).width;
					}

					// move origin to the start coordinate transfered by the parameters x and y
					this.ctx.translate(defaults.x, defaults.y);

					// set font attributes again
					this.ctx.font = defaults.fontSize + defaults.fontUnit + " " + defaults.fontFamily;
					this.ctx.fontSize = defaults.fontSize;
					this.ctx.fontFamily = defaults.fontFamily;
					this.ctx.fontUnit = defaults.fontUnit;
					this.ctx.textBaseline = 'middle'; // top, hanging, middle, alphabetic, ideographic, bottom

					// calculate rotation coorinates
					var rotPoint = {x: 0, y: 0};
					switch(defaults.rp){
						case 'nw':  // north-west
						rotPoint.x = 0;
						rotPoint.y = 0;
						break;
						case 'n':  // north
						rotPoint.x = measureWidth/2;
						rotPoint.y = 0;
						break;
						case 'ne': // north-east
						rotPoint.x = measureWidth;
						rotPoint.y = 0;
						break;
						case 'w':  // west
						rotPoint.x = 0;
						rotPoint.y = lineHeight*multiLines.length/2;
						break;
						case 'c':  // center
						rotPoint.x = measureWidth/2;
						rotPoint.y = lineHeight*multiLines.length/2;
						break;
						case 'e':  // east
						rotPoint.x = measureWidth;
						rotPoint.y = lineHeight*multiLines.length/2;
						break;
						case 'sw': // south-west
						rotPoint.x = 0;
						rotPoint.y = lineHeight*multiLines.length;
						break;
						case 's':  // south
						rotPoint.x = measureWidth/2;
						rotPoint.y = lineHeight*multiLines.length;
						break;
						case 'se': // south-east
						rotPoint.x = measureWidth;
						rotPoint.y = lineHeight*multiLines.length;
						break;
					}

					// move origin to rotation coordinates
					this.ctx.translate(rotPoint.x, rotPoint.y);

					// for debug only: show rotation coordinates
					//this.ctx.fillRect(0, 0, 3, 3);

					// rotate
					this.ctx.rotate(defaults.phi*Math.PI/180);


					// draw multilines
					for(var j=0, jLen=multiLines.length; j<jLen; j++){
						var leftIndent = (defaults.align==="left")
								? 0-rotPoint.x                                          // align left
								: ((defaults.align==="right")
									? (measureWidth-multiObj[j].width-rotPoint.x)         // align right
									: (measureWidth/2-multiObj[j].width/2-rotPoint.x));   // align center

						// draw line in context
						this.ctx[defaults.style](multiLines[j], leftIndent, (j+0.5)*lineHeight-rotPoint.y);
					}

					// restore context
					this.ctx.restore();

				});
			},

			/**
			 * Returns the content of the current canvas as an image. In browsers with no native canvas support it
			 * returns `undefined`.
			 * 
			 * @param {String} type The type of the image that will be generated.
			 * @param {Integer} index The index of the canvas from which the image that will be generated.
			 * 
			 * @method toDataURL
			 * @member jQuery.canvas
			 * 
			 * @since 6.14.0
			 */
			toDataURL: function(options){
				var defaults = $.extend({
					type: 'image/png',    // default MIME-Type
					index: 0        // index of the canvas-element
					}, options);

				return (this[defaults.index] && (this[defaults.index].toDataURL !== undefined))? this[defaults.index].toDataURL(defaults.type) : undefined;
			}

		});

	// default canvas attributes (getter and setter)
	$.each([
		'fillStyle',
		'strokeStyle',
		'lineWidth',
		'lineCap',
		'lineJoin',
		'globalAlpha',
		'globalCompositeOperation',
		'shadowOffsetX',
		'shadowOffsetY',
		'shadowBlur',
		'shadowColor',
		'miterLimit',
		'font'
	], function(i, method){
		fn[method] = function(){
			var args = arguments[0];

			// getter
			if(args === undefined){
				return this[0].ctx[method];
			// setter
			}else{
				return this.each(function(){
					this.ctx[method] = args;
				});
			}
		};
	});

	// default canvas methods
	$.each([
		'fillRect',
		'strokeRect',
		'clearRect',
		'drawImage',
		'fillText',
		'strokeText',
		'measureText',
		'rotate',
		'scale',
		'translate',
		'save',
		'restore',
		'createLinearGradient',
		'createRadialGradient',
		'createPattern',
		'getImageData',
		'putImageData',
		'arc',
		'arcTo',
		'beginPath',
		'bezierCurveTo',
		'clip',
		'closePath',
		'fill',
		'isPointInPath',
		'lineTo',
		'moveTo',
		'quadraticCurveTo',
		'rect',
		'stroke'
	], function(i, method){
		fn[method] = function(){
			var args = arguments;
			return this.each(function(){
				this.ctx[method].apply(this.ctx, args);
			});
		};
	});

	// write canvas plugin in jQuery Prototype
	/**
	 * See `jQuery.canvas` for details.
	 * 
	 * @method canvas
	 * @member jQuery
	 * 
	 * @since 6.14.0
	 */
	$.fn.canvas = function(options){
		var result = new qpCanvas();

		this.each(function(){
			result.push(init(this));
		});

		result.prevObject = this;

		return result;
	};

	return ep;

});