/**
 * @constructor Construtor do objeto, pode ser configurado.
 * @requires Parser para validar e transformar o numero
 * @param {Array} com os objetos para configuracao
 * 
 * csDec: 		numero de casas decimais mostradas						Padrao: "0"
 * formatInt:	formatar a parte inteira do numero						Padrao: false
 * arredondar:	arredondar a parte decimal do numero					Padrao: false
 * sepDigIn:	separador de digitos do numero de entrada				Padrao: ""
 * sepDecIn:	separador decimal do numero de entrada					Padrao: ""
 * sepDigOut:	separador de digitos do numero de saida					Padrao: "."
 * sepDecOut:	separador decimal do numero de saida					Padrao: ","
 * unidIn:		unidade de entrada, use '#' para identificar a posicao	Padrao: ""
 * 				ex: "R$#", "#Kg", "# coisa(s)".
 * unidOut:		unidade de saida, use '#' para identificar a posicao	Padrao: ""
 * fatConv:		fator de conversao entre as unidades de entrada e saida Padrao: "1"
 * 				OBS: deve ser passado apenas com numeros, virgulas
 * 				e pontos
 * negIn:		formato negativo da entrada, use '#' para identificar	Padrao: "-#"
 * 				a posicao
 * negOut:		formato negativo da saida, use '#' para identificar		Padrao: "-#"
 * 				a posicao
 * posIn:		formato positivo da entrada, use '#' para identificar	Padrao: "#"
 * 				a posicao
 * posOut:		formato positivo da saida, use '#' para identificar		Padrao: "#"
 * 				a posicao
 * 
 * OBS: caso algum formato seja informado sem o #, sera trocado pelo padrao
 * 
 * @author Ataxexe
 * @version 1.1
 * 
 * 1.1 - 05/05/2006 - A funcao nao mais coloca o valor num campo, agora
 * 		 ela retorna a string do valor formatado.
 * 
 * Datas: 26/04/2006 - 1.0
 * 		  06/05/2006 - 1.1
 */
function Formatter(params) {
	/**
	 * Funcao que formata um valor e devolve o valor formatado
	 * 
	 * OBS: o valor nao precisa estar em float, o metodo o converte
	 * automaticamente baseado nas informacoes da configuracao de entrada
	 * 
	 * @param: {String} Valor a ser formatado
	 * @return {String} Valor formatado
	 * 
	 * @author Ataxexe
	 */
	function format(valor){
		valor = this.parser.toFloat(valor);
		
		if(isNaN(valor)){
			valor = 0;
			alert('Valor inválido!');
		}
		
		//transformando o valor na nova unidade
		valor *= this.fatorConversao;
		
		var negativo = false;
		
		if(valor.toString().charAt(0) == "-"){
			valor = valor.toString().replace("-","");
			negativo = true;
			valor = parseFloat(valor);
		}
		
		var splitString = valor.toString().split(".");
		
		var inteiro = splitString[0];
		var decimal = splitString[1];
		
		if(this.arredondar && decimal != null){
			if(decimal.length > this.casasDecimais){
				//arredondamento
				if(decimal.charAt(this.casasDecimais) >= 5){
					//fazendo o arredondamento na ultima casa decimal mostrada pelo numero formatado
					valor += Math.pow(10,-(this.casasDecimais));
					//divide-se o valor de novo para o caso de o arredondamento alterar a parte inteira
					splitString = valor.toString().split(".");
					
					inteiro = splitString[0];
					decimal = splitString[1];
				}
			}
		}
		
		//nao tem parte decimal
		if(decimal == null){
			decimal = "";
			for(var i = 0; i < this.casasDecimais ; i ++) {
				decimal += "0";
			}
		}
		//parte decimal menor do que o tamanho desejado
		else if(decimal.length < this.casasDecimais){
			//preenche com os zeros que faltam
			for(var i = decimal.length ; i < this.casasDecimais ; i++ ){
				decimal = decimal + "0";
			}		
		}
		//parte decimal maior ou igual ao tamanho desejado
		else{
			decimal = decimal.substring(0,this.casasDecimais);
		}
		
		if(this.formatarInteiro){
			var inteiroFormatado = "";
			//formatacao do valor inteiro, feita de tras pra frente
			for(var i = inteiro.length - 1, aux = 0 ; i >= 0 ; i--,aux++){
				inteiroFormatado = inteiro.charAt(i).concat(inteiroFormatado);
				if(aux == 2 && i > 0){
					inteiroFormatado = this.separadorDigitosSaida + inteiroFormatado;
					aux = -1;
				}
			}
			inteiro = inteiroFormatado;
		}
		var texto = inteiro + (this.casasDecimais > 0 ? this.separadorDecimalSaida + decimal : "");
		
		var indice = this.unidadeSaida.indexOf("#");
		if(indice != -1){
			texto = this.unidadeSaida.toString().replace("#",texto);
		}
		
		if(negativo){
			texto = this.formatoNegativoSaida.toString().replace("#",texto);
		}
		else{
			texto = this.formatoPositivoSaida.toString().replace("#",texto);
		}
		
		return texto;
	}
	//funcao para armazenar as configuracoes padrao
	function param_default(pname, value) {
		//undefined significa que o atributo nao foi configurado
		if (typeof params[pname] == "undefined" || params[pname] == ""){
			params[pname] = value;
		}
	}
	//funcao para armazenar as configuracoes padrao de formato
	function format_default(pname, value) {
		//undefined significa que o atributo nao foi configurado
		if ((typeof params[pname] == "undefined") || (params[pname] == "") || (params[pname].toString().indexOf("#") == -1)){
			params[pname] = value;
		}
	}
	//funcao que gera o alerta de erro caso a configuracao seja mal sucedida
	function erroConfiguracao(){
		var msg = "Erro de configuracao do Formatter:\n\n";
		msg += this.msgErro;
		alert(msg);
	}
	//caso o construtor seja chamado sem o parametro
	if(params == null){
		var params = new Object();
	}
	
	param_default("csDec","0");
	param_default("formatInt",false);
	param_default("arredondar",false);
	param_default("sepDigIn","");
	param_default("sepDecIn","");
	param_default("sepDigOut",".");
	param_default("sepDecOut",",");
	param_default("unidIn","");
	param_default("unidOut","");
	param_default("fatConv","1");
	
	format_default("negIn","-#");
	format_default("negOut","-#");
	format_default("posIn","#");
	format_default("posOut","#");

	this.casasDecimais = params["csDec"];
	this.formatarInteiro = params["formatInt"];
	this.arredondar = params["arredondar"];
	this.separadorDigitosEntrada = params["sepDigIn"];
	this.separadorDecimalEntrada = params["sepDecIn"];
	this.separadorDigitosSaida = params["sepDigOut"];
	this.separadorDecimalSaida = params["sepDecOut"];
	this.unidadeEntrada = params["unidIn"];
	this.unidadeSaida = params["unidOut"];
	this.formatoNegativoEntrada = params["negIn"];
	this.formatoNegativoSaida = params["negOut"];
	this.formatoPositivoEntrada = params["posIn"];
	this.formatoPositivoSaida = params["posOut"];
	var parserFator = new Parser();
	this.fatorConversao = parserFator.toFloat(params["fatConv"]);
	//o objeto necessitara de um objeto Parser para fazer as conversoes para float
	this.parser = new Parser({
		sepDig : this.separadorDigitosEntrada,
		sepDec : this.separadorDecimalEntrada,
		unidade : this.unidadeEntrada,
		neg : this.formatoNegativoEntrada,
		pos : this.formatoPositivoEntrada
	});
	
	this.msgErro = "";
	
	var erro = false;
	
	//nao pode ser igual ao outro separador se ambos forem utilizados
	if(this.formatarInteiro && (this.separadorDigitosSaida == this.separadorDecimalSaida)){
		this.msgErro += "Separadores de saida iguais\n";
		erro = true;
	}
	//nao pode ser igual ao outro separador
	if(this.separadorDigitosEntrada == this.separadorDecimalEntrada && this.separadorDecimalEntrada != ""){		
		this.msgErro += "Separadores de entrada iguais\n";
		erro = true;
	}
	//prevencao de erro nas casas decimais
	if(this.casasDecimais == "" || this.casasDecimais < 0){
		this.msgErro += "Numero de casas decimais invalido\n";
		erro = true;
	}
	//prevencao de erro no fator de conversao
	if(this.fatorConversao == 0 || isNaN(this.fatorConversao)){
		this.msgErro += "Fator de conversao invalido\n";
		erro = true;
	}
	//o fator de conversao nao pode ser diferente de 1 se as unidades sao iguais
	if((this.unidadeEntrada == this.unidadeSaida && this.unidadeEntrada != "") && this.fatorConversao != 1){
		this.fatorConversao = 1;
	}
	//os formato positivos nao podem ser iguais aos negativos
	if((this.formatoPositivoEntrada == this.formatoNegativoEntrada ||
		this.formatoPositivoEntrada == this.formatoNegativoSaida ||
		this.formatoPositivoSaida == this.formatoNegativoEntrada) ||
		this.formatoPositivoSaida == this.formatoNegativoSaida){
		this.msgErro += "Os formatos positivos devem ser diferentes dos negativos\n";
		erro = true;
	}
	//se houver erro de configuracao
	if(erro){
		this.format = erroConfiguracao;
		return;
	}
	
	//as funcoes so serao atribuidas ao objeto se nao houver erro de configuracao
	this.format = format;
}