/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var DomEvent = {
	add: function(el, events) {
		for (var type in events) {
			var func = events[type];
			if (el.addEventListener) {
				el.addEventListener(type, func, false);
			} else if (el.attachEvent) {
				// Make a bound closure that calls on the right object and
				// passes on the global event object as a parameter.
				el.attachEvent('on' + type, func.bound = function() {
					func.call(el, window.event);
				});
			}
		}
	},

	remove: function(el, events) {
		for (var type in events) {
			var func = events[type];
			if (el.removeEventListener) {
				el.removeEventListener(type, func, false);
			} else if (el.detachEvent) {
				// Remove the bound closure instead of func itself
				el.detachEvent('on' + type, func.bound);
			}
		}
	},

	getPoint: function(event) {
		var pos = event.targetTouches
				? event.targetTouches.length
					? event.targetTouches[0]
					: event.changedTouches[0]
				: event;
		return Point.create(
			pos.pageX || pos.clientX + document.documentElement.scrollLeft,
			pos.pageY || pos.clientY + document.documentElement.scrollTop
		);
	},

	getElement: function(event) {
		return event.target || event.srcElement;
	},

	getOffset: function(event) {
		// Remove target offsets from page coordinates
		return DomEvent.getPoint(event).subtract(
				DomElement.getOffset(DomEvent.getElement(event), true));
	},

	preventDefault: function(event) {
		if (event.preventDefault) {
			event.preventDefault();
		} else {
			// IE
			event.returnValue = false;
		}
	},

	stopPropagation: function(event) {
		if (event.stopPropagation) {
			event.stopPropagation();
		} else {
			event.cancelBubble = true;
		}
	},

	stop: function(event) {
		DomEvent.stopPropagation(event);
		DomEvent.preventDefault(event);
	},
};

DomEvent.requestAnimationFrame = new function() {
	var part = 'equestAnimationFrame',
		request = window['r' + part] || window['webkitR' + part]
			|| window['mozR' + part] || window['oR' + part]
			|| window['msR' + part];
	if (request) {
		// Chrome shipped without the time arg in m10. We need to check if time
		// is defined in callbacks, and if not, clear request again so we won't
		// use the faulty method.
		request(function(time) {
			if (time == undefined)
				request = null;
		});
	}

	// So we need to fake it. Define helper functions first:
	var callbacks = [],
		focused = true,
		timer;

	DomEvent.add(window, {
		focus: function() {
			focused = true;
		},
		blur: function() {
			focused = false;
		}
	});

	return function(callback, element) {
		// See if we can handle natively first
		if (request)
			return request(callback, element);
		// If not, do the callback handling ourself:
		callbacks.push([callback, element]);
		if (!timer) {
			// Installs interval timer that checks all callbacks. This results
			// in faster animations than repeatedly installing timout timers.
			timer = window.setInterval(function() {
				// Checks all installed callbacks for element visibility and
				// execute if needed.
				for (var i = callbacks.length - 1; i >= 0; i--) {
					var entry = callbacks[i],
						func = entry[0],
						element = entry[1];
					if (!element || element.getAttribute('keepalive') == 'true'
							|| focused && DomElement.isVisible(element)) {
						// Handle callback and remove it from callbacks list.
						callbacks.splice(i, 1);
						func(Date.now());
					}
				}
			}, 1000 / 60);
		}
	};
};