var Sorter = function(prefix, criteria, pageSize) {  
	this.prefix = prefix;
	this.criteria = criteria || [];
	this.directions = [];
	this.pageSize = pageSize || 0;
	this.page = 0;
	while ($(prefix + "crit" + this.directions.length)) {
		var i = this.directions.length;
		this.directions.push({ field : "v" + i, dir : 1, 
								   element_id : prefix + "crit" + i,
								   clicker_id : prefix + "click" + i });
	}
};

Sorter.prototype.setDirection = function(field, dir) {
	field = 'v' + field
	for (var i in  this.directions) {
		if (this.directions[i].field == field) {
			this.directions[i].dir = dir >= 1 ? 1 : -1;
			return i; 
		}
	}
}

Sorter.prototype.getState = function() {
	var st = "";
	for (var i in this.directions) {
		st = st + this.directions[i].field + 'dr' + this.directions[i].dir;
	}
	return st;
};

Sorter.prototype.setState = function(st) {
	var parts = st.split('v');
	parts.shift();
	
	var first;
	for (var i in parts){
		var dstart = parts[i].indexOf('dr');
		if ((dstart == -1) || (dstart == 0)) continue;

		var v = parts[i].substring(0, dstart);
		var dr = parts[i].substring(dstart + 2, parts[i].length);
		var index = this.setDirection(v, dr);
		if (i == 0){
			first = index;
		}
		
	}
	this.moveDirectionToFront(first);
	this.redisplayAll($(this.directions[0].clicker_id));
}; 

Sorter.prototype.getPageCount = function() { var n = this.criteria.length;
	return Math.floor((n-1) / this.pageSize) + 1;
}

Sorter.prototype.addCriterion = function(c) {
	this.criteria.push(c);
};

Sorter.prototype.sortCriteria = function() {
	if (this.directions.length) {
		this.criteria.sort(bind(this._dosort, this));
	}
};

var remapElementId = function (s) { 
	  return $(s.element_id); 
};

var redrawByArray = function(lst, first, count) {
	var elements = list(filter(null, imap(remapElementId, lst)));
	if (elements.length) {
		replaceChildNodes(elements[0].parentNode, elements);
	}
	if (first || count) {
		for (var i in elements) {
			if ((i >= first) && ( (i-first) < count)) {
				showElement(elements[i]);
			} else {
				hideElement(elements[i]);
			}
		}
	}
};

Sorter.prototype.redisplaySubjects = function() {
	redrawByArray(this.criteria, this.page * this.pageSize, this.pageSize);
};

Sorter.prototype.redisplayLegend = function(elem) {
	var upclass = "tslegendup";
	var downclass = "tslegenddown";

	forEach(this.directions,
			function (dr) {
				if (elem && elem['id'] == dr.clicker_id) {
					if (dr.dir > 0) {
						addElementClass($(dr.clicker_id), upclass); 
						removeElementClass($(dr.clicker_id), downclass); 
					} else {
						addElementClass($(dr.clicker_id), downclass); 
						removeElementClass($(dr.clicker_id), upclass); 
					}
				} else {
					removeElementClass($(dr.clicker_id), upclass); 
					removeElementClass($(dr.clicker_id), downclass); 
				} } );
};


Sorter.prototype.onClick = function(elem) {
	this.page = 0;
	this.handleClick(elem);
	this.redisplayAll(elem);
	return false;
};

Sorter.prototype.redisplayAll = function(elem) {
	this.redisplayLegend(elem);
	this.sortCriteria();
	this.redisplaySubjects();
};

Sorter.prototype.setPage = function(n) {
	this.page = n;
	this.redisplaySubjects();
}

Sorter.prototype.dumpCriteria = function() {
	$("out").innerHTML += list(imap(function(c) { return c.v0; }, this.criteria));
	$("out").innerHTML += "<br/>";
};
		

Sorter.prototype.handleClick = function(elem) {
	for (var d in this.directions) {
		var dr = this.directions[d];
		if (elem['id'] == dr.clicker_id) {
			if (d == 0) {
				dr.dir *= -1;
			} else {
				this.moveDirectionToFront(d);
			}
		}
	}
};

Sorter.prototype.moveDirectionToFront = function(index) {
	var dr = this.directions[index];
	this.directions.splice(index,1);
	this.directions.unshift(dr);
};

Sorter.prototype._dosort = function(a, b) {
	for (var d in this.directions) {
		var dr = this.directions[d];
		if (a[dr.field] > b[dr.field]) return dr.dir;
		if (a[dr.field] < b[dr.field]) return -dr.dir;
	}
	return 0;
};
