/*** Utility Plugins ***/
(function($) {
	$.fn.decorateAsGrid = function(options) {
		opts = jQuery.extend({
			itemsPerRow: 2,
			columnIndex: true,
			rowIndex: true
		}, options);

		return this.each(function(idx) {
			if(opts.columnIndex) { $(this).addClass("col" + (idx % opts.itemsPerRow)); }
			if(opts.rowIndex) { $(this).addClass("row" + Math.floor(idx / opts.itemsPerRow)); }
		});
	};
})(jQuery);

// setup: config: {center ({x,y}), phiUnits ("degrees", "radians")
// commands: "pageToPolar" ({x,y})
(function($) {
	$.fn.polarCoordinates = function() {
		if(arguments.length === 0 || typeof arguments[0] == "object") {
			opts = jQuery.extend({
				phiUnits: "degrees"
			}, arguments[0]);
			
			if(!opts.center) {
				opts.center = {
					x: this.width() / 2,
					y: this.height() / 2
				};
			}
			
			this.data("polarCoordinates.opts", opts);
			return this;
		}
		
		function _extractXY(src) {
			if(src.x != null && src.y != null) { return src; }
			if(src.X != null && src.Y != null) { return {x: X, y: Y }; }
			if(src.pageX != null && src.pageY != null) {
				return {x: src.pageX, y: src.pageY};
			} 
		}
		
		var opts = this.data("polarCoordinates.opts");
		
		if(arguments[0] == "pageToPolar") {
			var srcCoord = _extractXY(arguments[1]);
			var pos = this.offset();
			var vector = {
				x: srcCoord.x - pos.left - opts.center.x,
				y: srcCoord.y - pos.top - opts.center.y
			};
			var r = Math.sqrt(vector.x * vector.x + vector.y * vector.y);
			var phi = Math.atan2(vector.y, vector.x) + Math.PI / 2;
			if(phi < 0) {
				phi += Math.PI * 2;
			}
			
			if(opts.phiUnits == "degrees") {
				phi = phi / Math.PI * 180;
			}
				
			return {r: r, phi: phi};
		}
		return this;
	};
})(jQuery);

// setup: timeout (int), target, fn
// "invoke": args (for fn)
(function($) {
	$.fn.eventBlocker = function() {
		var opts;
		if(typeof arguments[0] === "number") {
			opts = {
				timeout: arguments[0],
				target: arguments[1],
				fn: arguments[2]
			};
			this.data("eventBlocker.opts", opts);
			return this;
		}
		
		if(arguments[0] !== "invoke") {
			return this;
		}

		this.data("eventBlocker.invocationArgs", Array.prototype.slice.call(arguments, 1));
		if(!this.data("eventBlocker.timeout")) {
			this.data("eventBlocker.timeout", true);
			opts = this.data("eventBlocker.opts");
			var blocker = this;
			setTimeout(
				function() {
					opts.fn.apply(opts.target, blocker.data("eventBlocker.invocationArgs"));
					blocker.data("eventBlocker.timeout", false);
				},
				opts.timeout
			);
		}
		
	};
})(jQuery);

// setup: array(DOMObj), {select (fn(DOMObj)), deselect (fn(DOMObj)), mirror (DOM obj)}
// commands: "select" (DOMObj/int)
(function($) {
	$.fn.itemSelector = function() {
		var opts;
		if(typeof arguments[0] === "object") {
			opts = jQuery.extend({
				items: arguments[0],
				curItem: null
			}, arguments[1]);
			if(typeof opts.mirror === "array") {
				opts.mirror = opts.mirror[0];
			}
			if(opts.mirror) {
				var mOpts = $(opts.mirror).data("itemSelector.opts");
				if(!mOpts)
					alert("itemSelector: mirror is no itemSelector!");
				mOpts.mirror = this[0];
				$(opts.mirror).data("itemSelector.opts", mOpts);
			}
 
			this.data("itemSelector.opts", opts);
			return this;
		}

		opts = this.data("itemSelector.opts");

		function _getItem(item) {
			if(typeof item == "object") { return item; }
			if(typeof item == "number") { return opts.items[item]; }
		}		
		
		if(typeof arguments[0] == "string") {
			var target = _getItem(arguments[1]);
			if(arguments[0] == "select" && target == opts.cur)
				return;

			if(opts.curItem !== null && opts.curItem != target) {
				opts.deselect(opts.curItem);
				opts.curItem = null;
				if(opts.mirror && arguments[arguments.length - 1] != opts.mirror) {
					$(opts.mirror).itemSelector("select", null, this[0]);
				}
			}
			
			if(target !== null) {
				opts.select(target);
				opts.curItem = target;
				if(opts.mirror && arguments[arguments.length - 1] != opts.mirror) {
					$(opts.mirror).itemSelector("select", jQuery.inArray(target, opts.items), this[0]);
				}
			}
			this.data("itemSelector.opts", opts);
			return this;
		}
	};
})(jQuery);

(function($) {
	$.fn.addGridMargins = function(margin) {
		var w = this.parent().width() + parseInt(this.parent().css("padding-left"));
		var curRow = [];
		var curTop = null;
		this.each(function() {
			var pos = $(this).position();
			if(curTop !== null && pos.top > curTop) {
				$.each(curRow, function() { $(this).css("margin-bottom", margin); });
				curRow = [];
			}
			curTop = pos.top;

			var right = pos.left + $(this).outerWidth();
			if(right <= w) {
				// case 1: same row
				if(right + margin <= w) {
					$(this).css("margin-right", margin);
				}
				curRow.push(this);
			}
		});
		return this;
	};
})(jQuery);
