/**
 * VectorGrid jQuery Plugin
 * @author Rubens de Souza Silva (rubens21@gmail.com)
 * @requires jQuery v1.2.4 or later
 * @version 0.1
 * @revision $Rev: 1877 $ 
 * @date $Date: 2008-08-22 09:24:59 -0300 (sex, 22 ago 2008) $
 *
 * Copyright (c) 2008 Vector Internet Bussiness - Belo Hozironte - Brazil
 * www.vectornet.com.br
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 */
 
 
/**
var col = [
		{jsonName : "attname", //Nome do atributo que 'alimentará' essa coluna ÚNICO NÃO OPCIONAL
		headerTitle: "id",	   //Texto que será o título da coluna (Não use links!)
		headerId: "idCollumn", //id da celula do cabeçalho dessa coluna
		headerClass: "cabecalho_tabela",//classe CSS da celula do cabeçalho dessa coluna
		valueToSort: "exemplo",//valor que será atribuído ao parâmetro de ordenação para recarregar a grid ordenada.
		sortable: true //Indica se essa coluna será ordenável.
		},
		{ ... }
]
*/
$.fn.vectorGrid = function(vectorGridOptions) {
	//Opções de configuração do sistema, veja mais a cima a definição do array cols
	vectorGridOptions = $.extend({
		cols: [],//Array com as informações sobre como cada coluna deverá ser construída (veja documentação acima)
		method: "POST",//Método que será utilizado para as solicitações AJAX
		url: 'json_script.php',//endereço do script que fornecerá o jSon
		params: {},//Parâmetros para serem enviados no momento da solicitação
		classRow: null,//Classe CSS das linhas (cada linha também poderá indicar sua classe através do Json)
		classRowAlt: null,//Classe CSS aplicado as linhas ímpares
		classHeader: null,	//Classe da linha do cabeçalho da tabela
		classfoot: null,//classe da linha do rodapé da tabelha
		classLoading: "grid_loading",//classe da tabela enquanto está sendo carregada
		sort: "ASC",//Ordem inicial 

		noRecordsText: "Nenhum registro encontrado",//Frase que substitui linhas quando não há registros
		noRecordsClass: "grid_sem_linhas",//Classe da linha (de apenas uma coluna) que é usada para informa que não há registros

		classHeaderSorted: "order_coluna_ordenada",//classe da célula do cabeçalho que está ordenando os registros
		classHeaderSortedDesc: "order_coluna_ordenada_desc",//classe da célula do cabeçalho que está ordenando os registros de forma decerscente
		classRowAlt: 'grid_linha_impar',//Classe CSS aplicado as linhas ímpares
		paramToSort: "orderby",
				
		footPreviousText: "<<",//Palavra utilizada para o link para páginas anteriores
		footNextText: ">>",//Palavra utilizada para o link para próximas páginas
		footFirstText: "|<",//Palavra utilizada para o link para a primeira página
		footLastText: ">|",//Palavra utilizada para o link para a última página

		footPreviousClass: "grid_pagina_anterior",//Classe utilizada para o link para páginas anteriores
		footNextClass: "grid_pagina_proxima",//Classe utilizada para o link para próximas páginas
		footFirstClass: "grid_pagina_primeira",//Classe utilizada para o link para a primeira página
		footLastClass: "grid_pagina_ultima",//Classe utilizada para o link para a última página
		footJumpersClass: "grid_pagina_jumps",//Classe utilizada para o link para a última página
		footActualPageClass: "grid_pagina_atual",//Classe da página atual
		footNumRegsClass: "grid_qtd_registros", //classe da mensgem que conta a quantidade de registros.
		
		page: 1,//Número da página inicial
		rows: 20,//Quantidade de linhas por páginas
		rowsJump: 3,//Quantidade de páginas listadas para frente e para tráz 
		rowsOptions: [10, 20, 30],//opções de exibição de linhas por páginas.
		refreshCallbackFunction: null
	}, vectorGridOptions);
	
	//Seta os parâmetros passados pela URL
	vectorGridOptions.params.rows = vectorGridOptions.rows;
	vectorGridOptions.params.page = vectorGridOptions.page;
  	vectorGridOptions.params.sort = vectorGridOptions.sort;
  	vectorGridOptions.params.classRowAlt = vectorGridOptions.classRowAlt;
  	$.fn.vectorGridOptions = vectorGridOptions;
  	//método que carrega o Json baseado nos parâmetros de configuração e cria o TBody com as linhas dos registros.
	$.fn.loadVectorGrid = function()
	{
		this.each(function(){
			$(vectorGridOptions.referencia.getElementsByTagName('tbody')[0]).fadeTo("fast", 0.2);
			$.ajax({
				url: vectorGridOptions.url,
				data: vectorGridOptions.params,
				type: vectorGridOptions.method,
				async: false,
				dataType: "json",
				error: function(XMLHttpRequest, textStatus, errorThrown){alert(textStatus);},
				success: function(tabelaJson)
				{
					vectorGridOptions.json = tabelaJson;//armazena o Json recebido em um atributo do options
					$("#" + vectorGridOptions.referencia.id).clear();
					var TBody = document.createElement('tbody');//cria um Tbody na tabela
					vectorGridOptions.referencia.appendChild(TBody);
					if(tabelaJson.totalRecords > 0)
						$("#" + vectorGridOptions.referencia.id + " tbody").html(tabelaJson.html);
					else
						$("#" + vectorGridOptions.referencia.id + " tbody").html("<tr class=\"" + vectorGridOptions.noRecordsClass + "\"><td colspan=\"" + vectorGridOptions.cols.length +"\">" + vectorGridOptions.noRecordsText + "</td></tr>");
					$(vectorGridOptions.referencia.getElementsByTagName('tbody')[0]).fadeTo("fast", 1.0);
				}

			});
		});	
	};
	

	//Método para pular para determinada página
	$.fn.jumpToPage = function(page)
	{
		if(page <= vectorGridOptions.json.totalPages)
		{
			vectorGridOptions.params.page = page;
			$("#" + vectorGridOptions.referencia.id).refresh();
		}
	};
	
	//Método para ordenação das linhas por determinada coluna
	//ATENÇÃO: o plug não não ordena o Json para redesenhar a tabela! O Plug altera o parâmtro sort e recarrega o jSOn
	$.fn.sort = function(valueToSort)
	{
		eval('var ActualOrder = vectorGridOptions.params.' + vectorGridOptions.paramToSort + ';');
		if(ActualOrder == valueToSort)//verifica se a tabela já estava ordenada por essa coluna, pois necessa caso o que muda é de asc para desc ou vice-versa
			vectorGridOptions.params.sort = ((vectorGridOptions.params.sort == "DESC") ? "ASC" : "DESC");
		else
			vectorGridOptions.params.sort = "ASC";
		//altera o marâmetro enviado para o valor da coluna clicada
		eval('vectorGridOptions.params.' + vectorGridOptions.paramToSort + ' = "' + valueToSort + '"');
		
		var pos = false;//guardará a posição da coluna que foi clicada
		//varre o array de colunas para identificar qual delas possui esse valor para valueToSort e portanto foi a clicada
		for(i=0; i < vectorGridOptions.cols.length ; i++)
		{
			//vai removendo de todas a classe de ordenado e ordenado asc
			$($(vectorGridOptions.referencia).children()[0].childNodes[0].childNodes[i]).removeClass(vectorGridOptions.classHeaderSorted);
			$($(vectorGridOptions.referencia).children()[0].childNodes[0].childNodes[i]).removeClass(vectorGridOptions.classHeaderSortedDesc);
			if(vectorGridOptions.cols[i].valueToSort == valueToSort)
				pos = i;
		}
		//caso tenha identificado a coluna, coloca na coluna a classe que identica que ela foi ordenada
		if(pos !== false)
		{
			if(vectorGridOptions.params.sort == "ASC")//verifica qual o sentido da ordenação para colocar a classe adequada
				$($(vectorGridOptions.referencia).children()[0].childNodes[0].childNodes[pos]).addClass(vectorGridOptions.classHeaderSorted);
			else
				$($(vectorGridOptions.referencia).children()[0].childNodes[0].childNodes[pos]).addClass(vectorGridOptions.classHeaderSortedDesc);
		}
		//atualiza a grid
		$("#" + vectorGridOptions.referencia.id).refresh();
	};
	
	//limpa a grid removendo todos os Tbodys que possam existir
	$.fn.clear = function()
	{
		if(vectorGridOptions.referencia.getElementsByTagName('tbody').length)
		{
			for(var i=0; i<vectorGridOptions.referencia.getElementsByTagName('tbody').length; i++)
				$(vectorGridOptions.referencia.getElementsByTagName('tbody')).remove();//[i]);
			vectorGridOptions.referencia.removeChild(vectorGridOptions.referencia.getElementsByTagName('tfoot')[0]);
		}
	}
	
	//Atualiza a grid, limpando o que existir lá, carregando as linhas e montando o rodapé
	$.fn.refresh = function()
	{
		$("#" + vectorGridOptions.referencia.id).loadVectorGrid();
		$("#" + vectorGridOptions.referencia.id).mountFoot();
		if(typeof $.fn.vectorGridOptions.refreshCallbackFunction == 'function')
			$.fn.vectorGridOptions.refreshCallbackFunction();
		
	}
	
	//monta o rodapé baseado no Json carregado e nos parâmetros de configuração
	$.fn.mountFoot = function()
	{
		//cria o rodapé na tabela
		var rowfoot = vectorGridOptions.referencia.createTFoot().insertRow(0);
		$(rowfoot).addClass(vectorGridOptions.classfoot);//coloca a classe definida para o rodapé
		
		//cria uma célula no rodapé e cria o mesmo número de colunas que existe nas linhas e no cabeçalho
		var foot 	 = rowfoot.insertCell(0);
		foot.colSpan = vectorGridOptions.cols.length;
		
		//Prepara os links que poderão ser utilizados para navegação
		var previous = ' <a href="javaScript://" ' + ((vectorGridOptions.footPreviousClass) ? 'class="' + vectorGridOptions.footPreviousClass + '"' : '') + 'onclick="$(\'#'+ vectorGridOptions.referencia.id +'\').previous();">' + vectorGridOptions.footPreviousText + '</a> ';
		var next 	 = ' <a href="javaScript://" ' + ((vectorGridOptions.footNextClass) ? 'class="' + vectorGridOptions.footNextClass + '"' : '') + 'onclick="$(\'#'+ vectorGridOptions.referencia.id +'\').nextVectorGrid();">' + vectorGridOptions.footNextText + '</a> ';		

		var frist 	= ' <a href="javaScript://" ' + ((vectorGridOptions.footFirstClass) ? 'class="' + vectorGridOptions.footFirstClass + '"' : '') + 'onclick="$(\'#'+ vectorGridOptions.referencia.id +'\').first();">' + vectorGridOptions.footFirstText + '</a> ';
		var last 	= ' <a href="javaScript://" ' + ((vectorGridOptions.footLastClass) ? 'class="' + vectorGridOptions.footLastClass + '"' : '') + ' onclick="$(\'#'+ vectorGridOptions.referencia.id +'\').last();">' + vectorGridOptions.footLastText + '</a> ';		

		//Cria os números das páginas como links para pular diretamente para páginas mais a frente ou mais à tráz.
		var jumps = "";
		for(var i = -vectorGridOptions.rowsJump; i <= vectorGridOptions.rowsJump; i++)//o parâmetro começa negativo pois o número de páginas de salto pode ser posterior ou anterior a página exibida 
		{		
			if(parseInt(vectorGridOptions.params.page) + i <= vectorGridOptions.json.totalPages && parseInt(vectorGridOptions.params.page) + i > 0)
			{
				if(i == 0)//nesse caso essa posição é a página que está sendo exibida, portanto não precisa de link nela.
					jumps += ' <a ' + ((vectorGridOptions.footActualPageClass) ? 'class="' + vectorGridOptions.footActualPageClass + '"' : '') + ' >' + parseInt(vectorGridOptions.params.page) + '</a> ';
				else
					jumps += ' <a href="javaScript://" ' + ((vectorGridOptions.footJumpersClass) ? 'class="' + vectorGridOptions.footJumpersClass + '"' : '') + ' onclick="$(\'#'+ vectorGridOptions.referencia.id +'\').jumpToPage(' + (parseInt(vectorGridOptions.params.page) + i) + ');">' + (parseInt(vectorGridOptions.params.page) + i) + '</a> ';
			}
		}
		if(vectorGridOptions.params.page >  1)//caso não seja primeira página, oferece links para páginas anteriores e para a primeira
			foot.innerHTML += frist + previous;
		
		foot.innerHTML += jumps;//coloca os links para pular para páginas
		if(vectorGridOptions.params.page <  vectorGridOptions.json.totalPages)//caso não seja última página, ofere links para páginas posteriores e para a última
			foot.innerHTML += next + last;
		
		//Cria um select para oferecer os opções de linhas/páginas
		var select = document.createElement('select');
		//cria uma função que atualiza a grid quando o select é alterado
		
        //varre as opções do array rowsOptions que define as opções para serem exibidas
		for(var i=0; i < vectorGridOptions.rowsOptions.length;i++)
		{
			var opt   = document.createElement('option');//cria um option para a opção
			opt.value = vectorGridOptions.rowsOptions[i];
			opt.text  = vectorGridOptions.rowsOptions[i] + ' registros por página';
			opt.id    = "vectorGrid_option_" + vectorGridOptions.referencia.id + "_" + opt.value;
			
			/*if(vectorGridOptions.params.rows == opt.value){
				alert("entrou -> "+opt.value);
				opt.selected = "selected";
			}*/
			
			try
			{//adiciona o option no select criado
				select.add(opt,null); // standards compliant
			}
			catch(ex)
			{
				select.add(opt); // IE only
			}
  		}
		foot.appendChild(select);
		
  		foot.innerHTML += " <span class=\"" + vectorGridOptions.footNumRegsClass + "\">Total de registros: " + vectorGridOptions.json.totalRecords + "</span>";
  		
		$("#" + vectorGridOptions.referencia.id + " tfoot select").change(function () {
	          $('#'+ vectorGridOptions.referencia.id).chngPage(this.value);
	          return true;
        });
        
  		$("#vectorGrid_option_" + vectorGridOptions.referencia.id + "_" + vectorGridOptions.params.rows).attr("selected", "selected");
        //alert("vectorGrid_option_" + vectorGridOptions.referencia.id + "_" + vectorGridOptions.params.rows);
	}
		
	//Altera a quantidade de linhas por páginas
	$.fn.chngPage = function(size)
	{
		vectorGridOptions.params.rows = size;
		$("#" + vectorGridOptions.referencia.id).refresh();
		
	}
	
	//Retroce uma página baseada na página atual
	$.fn.previous = function()
	{
		vectorGridOptions.params.page = (vectorGridOptions.params.page > 1) ? vectorGridOptions.params.page - 1 : 1;
		$("#" + vectorGridOptions.referencia.id).refresh();
	}
	
	//Pula para a primeira página
	$.fn.first = function()
	{
		vectorGridOptions.params.page = 1;
		$("#" + vectorGridOptions.referencia.id).refresh();
	}
	
	//Pula para a ultiam página
	$.fn.last = function()
	{
		vectorGridOptions.params.page = vectorGridOptions.json.totalPages;
		$("#" + vectorGridOptions.referencia.id).refresh();
	}
	
	//avança uma página baseada na página atual	
	$.fn.nextVectorGrid = function()
	{
		vectorGridOptions.params.page = (vectorGridOptions.params.page < vectorGridOptions.json.totalPages) ? vectorGridOptions.params.page + 1 : vectorGridOptions.json.totalPages;
		$("#" + vectorGridOptions.referencia.id).refresh();
	}
	
	//Cria o objeto VectorGrid, criando o cabeçado
	this.each(function(){
		//guarda a referência ao objectr Table para facilitar o acesso a partide de outros métodos
		vectorGridOptions.referencia = this;
		//cria o Thead e insere uma linha e coloca a classe determinada para a linha de cabeçalho
		var header = this.createTHead().insertRow(0);
		header.className = vectorGridOptions.classHeader;
		
		//Cria uma coluna para cara uma defenida na configuração da VectorGrid
		for(i=0; i < vectorGridOptions.cols.length ; i++)
		{
			var headerCol = header.insertCell(i);
			//caso seja uma coluna ordenável, cria um link para ordena a tabela
			if(vectorGridOptions.cols[i].headerTitle)
			{
				if(vectorGridOptions.cols[i].sortable)
					headerCol.innerHTML = '<a href="javaScript://" onclick="$(\'#'+ vectorGridOptions.referencia.id +'\').sort(\'' + vectorGridOptions.cols[i].valueToSort + '\');">' + vectorGridOptions.cols[i].headerTitle + '</a>';
				else
					headerCol.innerHTML = vectorGridOptions.cols[i].headerTitle;
			}
			//cria os atributos ID e classe somente se eles forem setados, senão eles recebem o valor 'undefined'
			if(vectorGridOptions.cols[i].headerId)
				headerCol.id 		= vectorGridOptions.cols[i].headerId;
			if(vectorGridOptions.cols[i].headerClass)
				headerCol.className = vectorGridOptions.cols[i].headerClass;
		}
		//executa o método que recarrega a tabela
		$("#" + vectorGridOptions.referencia.id).refresh();
		
  	});

};