/*encoding: utf-8 */
/*jslint onevar: false, browser: true, strict: true, white: false, passfail: false, maxerr: 10, plusplus: false */
/*global window, jQuery */
"use strict";
(function($) {
	var Queue = function(options) {
		var defaults = {
			'cancel': function(item) {
				if (!$.isFunction(item.abort())) {
					return;
				}
				
				item.abort();
			}
		};
		if ('undefined' === typeof options) {
			options = {};
		}
		this.options = $.extend(defaults, options);
		
		this.queue = [];
		this.time = new Date().getTime();
	};
	
	var Manager = function(options) {
		var defaults = {
			'delay': 500,
			'cancelRequest': function(request) {
				if (!$.isFunction(request.abort())) {
					return;
				}
				
				request.abort();
			},
			'makeRequest' : $.noop,
			'getData': $.noop,
			'forceFirst': false,
			'queue': new Queue()
		};
		if ('undefined' === typeof options) {
			options = {};
		}
		this.options = $.extend(defaults, options);
		
		this.counter = 0;
		this.data = this.options.getData();
	};
	
	Queue.prototype.add = function(item) {
		this.queue.push(item);
	};
	
	Manager.prototype.checkTime = function() {
		return this.options.queue.checkTime.apply(this.options.queue, arguments);
	};
	Queue.prototype.checkTime = function(time) {
		if (this.time > time) {
			return false;
		}
		
		this.time = time;
		return true;
	};
	
	Manager.prototype.handle = function(ev, force) {
		var self = this;
		var data = this.options.getData();
		if ('undefined' === typeof force) {
			force = false;
		}
		if (!force && !this.options.forceFirst && 0 !== this.counter && this.data === data) {
			return;
		}
		this.counter++;
		this.data = data;
		
		setTimeout(function() {
			if (self.data !== data) {
				return;
			}
			
			var time = new Date().getTime();
			var request = self.options.makeRequest(ev, self.data, time);
			if ('undefined' !== typeof request) {
				self.options.queue.add({ 'time': time, 'request': request });
			}
		}, this.options.delay);
	};
	
	Queue.prototype.clear = function(time) {
		var self = this;
		if ('undefined' === typeof time) {
			time = new Date().getTime();
		}
		
		var queue = [];
		$.each(this.queue, function(i, v) {
			if (time > v.time) {
				self.options.cancel(v.request);
				return;
			}
			
			queue.push(v);
		});
		this.queue = queue;
	};
	
	window.RequestQueue = Queue;
	window.RequestManager = Manager;
}(jQuery));
