var TableBuilder = function(options){
	
	// default options
	options = Object.extend({
		url        : '',
		id         : false,
		pageId     : false,
		maxPage    : 0,
		infoId     : false,
		infoMsg    : '$rowStart s/d $rowEnd dari $dataCount data ($pageCount halaman)',
		onCreate   : Prototype.emptyFunction,
		onSuccess  : Prototype.emptyFunction,
		onFailure  : Prototype.emptyFunction,
		onComplete : Prototype.emptyFunction
	}, options || {});
	
	////////////////////////////////////////////////////////////////////////////////
	
	// variables
	var cache = {
		page     : null,
		maxPage  : null,
		offset   : null,
		rowCount : null,
		data     : null
	};
	
	var cacheParams = {};
	
	var table   = $(options.id);
	var headers = table.down('th').up('tr').select('th');
	var tbody   = $(table.tBodies[0]);	// IE6 harus menggunakan $()
	
	var pageDiv = $(options.pageId);
	var pageState = { page : null };
	
	var infoDiv = $(options.infoId);
	
	var REQUEST_ON_PROGRESS = false;
	
	////////////////////////////////////////////////////////////////////////////////
	
	// table rendering function
	function deleteRows(){
		var index = 0;
		while (tbody.rows.length > index) {
			if (tbody.rows[index].getElementsByTagName('th').length > 0) index++;
			else tbody.deleteRow(index);
		}
	}
	
	function insertRow(row){
		var tr, td;
		tr = new Element('tr');
		for (var i=0; row.length && i<row.length; i++) {
			td = new Element('td').update(row[i]);
			tr.insert(td);
		}
		tbody.insert(tr);
	}
	
	function renderData(data){
		deleteRows();
		for (var i=0; data.length && i<data.length; i++)
			insertRow(data[i]);
	}
	
	function getData(params){
		if (REQUEST_ON_PROGRESS) return;
		else REQUEST_ON_PROGRESS = true;
		
		cacheParams.json = params.json ? params.json : cacheParams.json;
		cacheParams.jenjang = params.jenjang ? params.jenjang : cacheParams.jenjang;
		cacheParams.npsn = params.npsn ? params.npsn : cacheParams.npsn;
		cacheParams.tingkat = params.tingkat ? params.tingkat : cacheParams.tingkat;
		cacheParams.type = params.type ? params.type : cacheParams.type;
		cacheParams.page = params.page ? params.page : cacheParams.page;
		
		new Ajax.Request(options.url, {
			parameters : cacheParams,
			onCreate   : options.onCreate,
			onSuccess  : function(t){
				var json = t.responseText.evalJSON(true);
				if (json && json.page && json.maxPage && json.data) {
					cache.page     = json.page;
					cache.maxPage  = json.maxPage;
					cache.offset   = json.offset;
					cache.rowCount = json.rowCount;
					cache.data     = json.data;
					
					pageState.page = json.page;
					
					renderData(cache.data);
					renderPage(cache.page, cache.maxPage);
				}
				REQUEST_ON_PROGRESS = false;
			},
			onFailure  : function(){
				options.onFailure();
				REQUEST_ON_PROGRESS = false;
			},
			onComplete : function(){
				options.onComplete(table, tbody);
				REQUEST_ON_PROGRESS = false;
			}
		});
	}
	
	////////////////////////////////////////////////////////////////////////////////
	
	// page rendering function
	function renderPage(page, maxPage){
		if (!pageDiv) return;
		pageDiv.update();
		
		var link, span;
		
		// interval
		var pageStart = 1 + Math.floor((page-1)/options.maxPage) * options.maxPage;
		var pageEnd   = pageStart+options.maxPage-1 < maxPage ? pageStart+options.maxPage-1 : maxPage;
		
		// prev
		if (pageStart > 1) {
			span = new Element('span').update('&laquo;');
			link = new Element('a', { href: '#', title: 'sebelumnya' }).update(span);
			span.__PAGE = pageStart-1;
			link.__PAGE = pageStart-1;
			link.observe('click', function(e){
				e.stop();
				getData({ page : e.target.__PAGE });
			});
			pageDiv.insert(link);
		}
		
		for (var i=pageStart; i<=pageEnd; i++) {
			span = new Element('span', { 'class': (i==page ? 'selected' : '') }).update(i);
			link = new Element('a', { href: '#', title: i }).update(span);
			span.__PAGE = i;
			link.__PAGE = i;
			link.observe('click', function(e){
				e.stop();
				getData({ page : e.target.__PAGE });
			});
			pageDiv.insert('&nbsp;').insert(link);
		}
		
		// next
		if (pageEnd < maxPage) {
			span = new Element('span').update('&raquo;');
			link = new Element('a', { href: '#', title: 'berikutnya' }).update(span);
			span.__PAGE = pageEnd+1;
			link.__PAGE = pageEnd+1;
			link.observe('click', function(e){
				e.stop();
				getData({ page : e.target.__PAGE });
			});
			pageDiv.insert('&nbsp;').insert(link);
		}
		
		if (!infoDiv) return;
		infoDiv.update();
		
		var infoMsg  = options.infoMsg;
		infoMsg = infoMsg.replace('$rowStart', cache.offset);
		infoMsg = infoMsg.replace('$rowEnd', cache.offset + (cache.data.length ? cache.data.length-1 : 0));
		infoMsg = infoMsg.replace('$dataCount', cache.rowCount);
		infoMsg = infoMsg.replace('$pageCount', maxPage);
		infoDiv.update(infoMsg);
	}
	
	////////////////////////////////////////////////////////////////////////////////
	// extra functionality
	
	return {
		overrideOptions: function(_options){
			options = Object.extend(options, _options || {});
		},
		
		getData: function(params){
			getData( params );
		},
		
		refreshData: function(){
			getData();
		}
	}
}