if (!window.RichFaces) window.RichFaces = {};



RichFaces.SortController = function() {
	var controlsByTable = {};
	
	return {
		registerControl : function(control) {
			var tableId = control.tableId;
			var sortExpression = control.sortExpression;
			var controlId = control.id;
			var columnId = control.columnId;
			
			var byTable = controlsByTable[tableId];
			if (!byTable) {
				byTable = {columns: {}, expressions : {}};
				controlsByTable[tableId] = byTable;
			}
			var byExpression;
			if (sortExpression) {
				byExpression = byTable.expressions[sortExpression];
				if (!byExpression) {
					byExpression = {};
					byTable.expressions[sortExpression] = byExpression;
				}
			} else if (columnId) {
				byExpression = byTable.columns[columnId];
				if (!byExpression) {
					byExpression = {};
					byTable.columns[columnId] = byExpression;
				}
			}
			if(byExpression) {
				var byId = byExpression[controlId];
				if (byId) {
					//TODO: delete controls already registered??
				} else {
					byExpression[controlId] = control;
				}
			}
		},
		
		controlsByTable : function(tableId) {
			var map = controlsByTable[tableId] || {expressions: {}, columns :{}};
			var result = [];
			['expressions', 'columns'].each(
				function(part) {
					var parts = map[part];
					if (parts) {
						$H(parts).values().each(
							function(x) {
								result = result.concat($H(x).values());
							}
						);
					}
					
				}
			);		return result.uniq(); 
		},
		controls : function(tableId, sortExpression, columnId) {
			var map = controlsByTable[tableId] || {expressions: {}, columns :{}};
			var array;
			if (typeof sortExpression != 'undefined') {
				array = $H(map.expressions[sortExpression]).values();
			} 
			if (typeof columnId != 'undefined') {
				var a = $H(map.columns[columnId]).values();
				if (array) {
					array = array.concat(a).uniq();
				} else {
					array = a;
				}
			}
			return array;
			 
		}
	};
}();


RichFaces.SortControl = Class.create({
	initialize : function(id, tableId, sortExpression, columnId) {
		this.id = id;
		this.tableId = tableId;
		this.columnId = columnId;
		this.sortExpression = sortExpression;
		this.prepareEvents();		
		//TODO:Set cursor via clazz
		//element.setStyle({cursor: "pointer"});
		
		RichFaces.SortController.registerControl(this);
		
	},
	
	prepareEvents : function() {
		this.onclick = this.invoke.bindAsEventListener(this);
		var element = this.getElement();
		element.observe("click", this.onclick);
	},
	getElement : function () {
		return $($(this.id)/*.parentNode*/);
	}, 
	displaySortedAscending : function() {
		this.getElement()
			.removeClassName("rich-sort-desc")
			.addClassName("rich-sort-asc");
	},
	displaySortedDescending : function() {
		this.getElement()
			.removeClassName("rich-sort-asc")
			.addClassName("rich-sort-desc");
	},
	displayNotSortedAtAll : function() {
		this.getElement()
			.removeClassName("rich-sort-desc")
			.removeClassName("rich-sort-asc");
	}, 
	invoke : function(event) {
		var sortExpression;
		
		if (this.sortExpression) {
			sortExpression = this.sortExpression;	
		} else {
			var cell = Event.findElement(event, "th,td");
			if (cell) {
				sortExpression = cell.cellIndex;
			}
		}
		if (typeof sortExpression != 'undefined') {
			$(this.tableId).component.changeSorting(new RichFaces.SortOrder([new RichFaces.SortField(sortExpression)]), this.columnId);
		}
	}
});

RichFaces.SortOrder = Class.create({
	initialize : function(fields) {
		this.fieldz = fields || [];
	},
	fields : function() {
		return this.fieldz;
	}	
});




RichFaces.SortField = function(sortExpression, asc) {
	this.sortExpression = sortExpression;
	this.asc = asc;
};

RichFaces.SortMode = Class.create({
	merge : function(oldSortOrder, newSortOrder) {
		return oldSortOrder;
	}
});

/**
 * Basically toggle any existing
 */
RichFaces.SortMode.Single = Class.create(RichFaces.SortMode, {
	merge : function(oldSortOrder, newSortOrder) {
		var newFields = newSortOrder.fields();
		var oldFields = oldSortOrder.fields();
		var expr;
		var asc;
		if (oldFields.length > 0) {
			expr = oldFields[0].sortExpression;
			asc = oldFields[0].asc;
		}
		if (newFields.length > 0) {
			var xpr = newFields[0].sortExpression;
			if (xpr == expr) {
				asc = !asc;
			} else {
				expr = xpr;
				asc = true;
			}
		}
		oldSortOrder = new RichFaces.SortOrder([new RichFaces.SortField(expr, asc)]);
		return oldSortOrder;
	}	
});


RichFaces.DataTable = Class.create({
	initialize : function(id, options) {
		var table = $(id);
		table.component = this;
		
		this.sortMode = options.sortMode || new RichFaces.SortMode();
		this.id = id;
		this.sortOrder = options.sortOrder || new RichFaces.SortOrder();
		this._compare = this.compare.bind(this);
	},
	/**
	 * Call this method to sort the table
	 * @param sortOrder - new sortOrder
	 * @param force if true, new sortOrder will completely replace previous one, otherwise sortOrders are merged using sortMode
	 */
	changeSorting : function(sortOrder, columnId, force){
		if (force) {
			this.sortOrder = sortOrder;
		} else {
			this.sortOrder = this.sortMode.merge(this.sortOrder, sortOrder);
		}
		this.sort();
		var tableId = this.id;
		
		var cbt = $A(RichFaces.SortController.controlsByTable(tableId));
		cbt.each(
			function(control) {
				control.displayNotSortedAtAll();
			}
		);
		$A(this.sortOrder.fields()).each(
			function(field) {
				var ctrls = 
					RichFaces.SortController.controls(tableId, field.sortExpression, columnId);
				$A(ctrls).each(function(control) {
					if (field.asc) {
						control.displaySortedAscending();
					} else {
						control.displaySortedDescending();
					}
				});
			}
		);
	}, 
	
	sort : function() {
		var table = $(this.id);
		var tbody = table.tBodies[0];
		if (tbody) {
			var newTbody = tbody.cloneNode(false);
			var newCollection = $A(tbody.rows).clone();
			newCollection.sort(this._compare);
			for(var i = 0; i < newCollection.length; i++) {
				newTbody.appendChild(newCollection[i]);
			}
			tbody.parentNode.replaceChild(newTbody, tbody);
		}
		
	},
	compare : function(row1, row2) {
		var fields = this.sortOrder.fields();
		var result = 0;
		for(var i = 0; i < fields.length && result == 0; i++) {
			var field = fields[i];
			var expression = field.sortExpression;
			if (typeof (expression) == 'function') {
				result = expression(row1, row2);
			} else if (typeof (expression) == 'number') {
				var c1 = row1.cells[expression];
				var c2 = row2.cells[expression];
				if (c1) {
					c1 = c1.innerHTML.stripTags();
					
				}
				if (c2) {
					c2 = c2.innerHTML.stripTags();
				}
				
				result = ((c1 == c2) ? 0 : ((c1 < c2) ? -1 : 1));
			}
		
			if (field.asc == false) {
				result = -result;
			}
			
		}
		return result;
		
		
	}
});
RichFaces.SortControl.Server = Class.create(RichFaces.SortControl, {
	invoke : function(event) {
		$(this.id + 's').click();
	}
});
RichFaces.SortControl.Ajax = Class.create(RichFaces.SortControl, {
	initialize: function(id, f) {
		this.id = id;
		this.f = f;
		this.prepareEvents();
	},
	invoke : function(event) {
		this.f(event);
	}
});

RichFaces.blurFilterInput = function(event) {
	if (event.keyCode == Event.KEY_RETURN && Event.element(event)) {
		Event.element(event).blur();
		return false;
	}
};

