// ************************************************************************************
//	Execution queue
// ************************************************************************************
// namespace
Type.registerNamespace("Competir.MiEmpresa");

// constructor
Competir.MiEmpresa.ExecutionQueue = function(maxConcurrentCalls, noOpTimeoutMS)
{
	Competir.MiEmpresa.ExecutionQueue.initializeBase(this);
	this._onOperationStartedDelegate = Function.createDelegate(this, this._onOperationStarted);
	this._onOperationFinishedDelegate = Function.createDelegate(this, this._onOperationFinished);
	this._Active = false;
	this._MaxConcurrentCalls = maxConcurrentCalls;
	this._NoOpTimeoutMS = (noOpTimeoutMS) ? noOpTimeoutMS: 0;
	this._Operations = new Array();
	this._ExecutingOperations = new Array();
	this._Timer = null;
};

// prototype
Competir.MiEmpresa.ExecutionQueue.prototype =
{
	// methods
	start: function()
	{
		if (!this.get_Active())
		{
			this.set_Active(true);
			this.process();
		}
	},
	stop: function()
	{
		this.set_Active(false);
		this.abortOperations(this.get_Operations());
		this.abortOperations(this.get_ExecutingOperations());
	},
	process: function()
	{
		var eq = this;
		var ms;
		if (this.get_Operations().length != 0)
		{
			ms = 200;
		}
		else if (this.get_NoOpTimeoutMS() != 0)
		{
			ms = this.get_NoOpTimeoutMS();
		}
		if (this._Timer)
		{
			clearTimeout(this._Timer);
		}
		this._Timer = setTimeout(function(){ eq.run() }, ms);
	},
	enqueue: function(o)
	{
		Array.add(this.get_Operations(), o);
		o.add_onStarted(this._onOperationStartedDelegate);
		o.add_onSucceeded(this._onOperationFinishedDelegate);
		o.add_onFailed(this._onOperationFinishedDelegate);
		o.onStarted();
		//this.reportStatus();
		this.process();
	},
	run: function()
	{
		if (this.get_Active())
		{
			var operations = this.get_Operations();
			if (operations.length != 0)
			{
				for (var i = 0; i < operations.length; i++)
				{
					if (this.get_Active())
					{
						var o = operations[i];
						if (this.get_ExecutingOperations().length < this.get_MaxConcurrentCalls())
						{
							if (o)
							{
								var execute = true;
								if (o.get_Command() == "webpart.relocate" && this.isExecuting("webpart.relocate"))
								{
									execute = false;
								}
								if (execute)
								{
									Array.add(this.get_ExecutingOperations(), o);
									Array.remove(operations, o);
									o.execute();
								}
							}
							//this.reportStatus();
						}
						else
						{
							//this.reportStatus();
							break;
						}
					}
				}
			}
			else if (this.get_NoOpTimeoutMS() != 0)
			{
				var o = new Competir.MiEmpresa.Operation("noop");
				o.execute();
				this.process();
			}
		}
	},
	abortOperations: function(operations)
	{
		if (operations.length != 0)
		{
			for (var i = 0; i < operations.length; i++)
			{
				var o = operations[i];
				if (o)
				{
					var r = o.get_Request();
					if (r)
					{
						var e = r.get_executor();
						if (e)
						{
							e._xmlHttpRequest.onreadystatechange = Function.emptyMethod;
							e.get_statusCode = function()
							{
								return 0;
							};
							if (e.get_started())
							{
								e.abort();
							}
						}
					}
				}
			}
			Array.clear(operations);
		}
	},
	isExecuting: function(command)
	{
		var rv = false;
		var executing = this.get_ExecutingOperations();
		if (command)
		{
			for (var i = 0; i < executing.length; i++)
			{
				if (executing[i].get_Command() == command)
				{
					rv = true;
					break;
				}
			}
		}
		else
		{
			rv = (executing.length != 0);
		}
		return rv;
	},
	reportStatus: function()
	{
		/*
		var out = "";
		out += "Total: " + this.get_Operations().length;
		out += " / ";
		out += "Executing: " + this.get_ExecutingOperations().length;
		document.title = out;
		*/
	},

	// properties
	get_Active: function()
	{
		return this._Active;
	},
	set_Active: function(value)
	{
		if (this._Active !== value)
		{
			this._Active = value;
			this.raisePropertyChanged("Active");
		}
	},
	get_MaxConcurrentCalls: function()
	{
		return this._MaxConcurrentCalls;
	},
	set_MaxConcurrentCalls: function(value)
	{
		if (this._MaxConcurrentCalls !== value)
		{
			this._MaxConcurrentCalls = value;
			this.raisePropertyChanged("MaxConcurrentCalls");
		}
	},
	get_NoOpTimeoutMS: function()
	{
		return this._NoOpTimeoutMS;
	},
	set_NoOpTimeoutMS: function(value)
	{
		if (this._NoOpTimeoutMS !== value)
		{
			this._NoOpTimeoutMS = value;
			this.raisePropertyChanged("NoOpTimeoutMS");
		}
	},
	get_Operations: function()
	{
		return this._Operations;
	},
	set_Operations: function(value)
	{
		if (this._Operations !== value)
		{
			this._Operations = value;
			this.raisePropertyChanged("Operations");
		}
	},
	get_ExecutingOperations: function()
	{
		return this._ExecutingOperations;
	},
	set_ExecutingOperations: function(value)
	{
		if (this._ExecutingOperations !== value)
		{
			this._ExecutingOperations = value;
			this.raisePropertyChanged("ExecutingOperations");
		}
	},

	// event delegates
	_onOperationStarted: function(sender, args)
	{
		//this.reportStatus();
	},
	_onOperationFinished: function(sender, args)
	{
		sender.remove_onStarted(this._onOperationStartedDelegate);
		sender.remove_onSucceeded(this._onOperationFinishedDelegate);
		sender.remove_onFailed(this._onOperationFinishedDelegate);
		Array.remove(this.get_ExecutingOperations(), sender);
		sender.dispose();
		//this.reportStatus();
		this.process();
	}
};

// registration
Competir.MiEmpresa.ExecutionQueue.registerClass("Competir.MiEmpresa.ExecutionQueue", Sys.Component);