function Filter(P,A){var r=new Array();for(var i=0;i<A.length;i++)if(P(A[i]))r.push(A[i]);return r;}
function Map(F,A){var r=new Array(A.length);for(var i=0;i<A.length;i++)r[i]=F(A[i]);return r;}
function Reduce(F,A){var r=A[0];for(var i=1;i<A.length;i++)r=F(r,A[i]);return r;}

function Todos(P,A){for(var i=0;i<A.length;i++)if(!P(A[i]))return false;return true;}
function Algum(P,A){for(var i=0;i<A.length;i++)if(P(A[i]))return true;return false;}
function Nenhum(P,A){return !Todos(P,A);}

function Intervalo(A,B,I){var S=I==null?1:I;var N=(B-A)/S+1;var r=new Array(N);for(var j=0;j<N;j++)r[j]=A+S*j;return r;}

function Igual(x){return function(y){return y==x;};}
function Menor(x){return function(y){return y<x;};}
function Maior(x){return function(y){return y>x;};}

// Handlers para eventos do tipo onkeydown
function KeyDownClass(){};
KeyDownClass.prototype = {
    // Controle
    BACKSPACE  :   8,
    BAIXO      :  40,
    CIMA       :  38,
    DELETE     :  46,
    DIREITA    :  39,
    ESQUERDA   :  37,
    TAB        :   9,
    
    // Caracteres não-alfanuméricos
    BARRA      : 193,
    BARRA_KP   : 111,
    BARRA_INV  : 226,
    HIFEN      : 109,
    HIFEN_KP   : 109,
    PONTO      : 190,
    PONTO_KP   : 194,
    VIRGULA    : 188,
    VIRGULA_KP : 110,
    
    // Caracteres numéricos
    ZERO       :  48,
    ZERO_KP    :  96,
    NOVE       :  57,
    NOVE_KP    : 105
}

// Funções auxiliares
KeyDownClass.prototype.Controles = function(){
    with(this){
        var r = new Array(BACKSPACE, BAIXO, CIMA, DELETE, DIREITA, ESQUERDA, TAB);
        return r;
    }
}

KeyDownClass.prototype.Numeros = function(){
    return Intervalo(this.ZERO, this.NOVE).concat(Intervalo(this.ZERO_KP, this.NOVE_KP));
}

KeyDownClass.prototype.N_AlfaNum = function(){
    with(this){
        var r = new Array(BARRA, BARRA_KP, BARRA_INV, HIFEN, HIFEN_KP, PONTO,
                          PONTO_KP, VIRGULA, VIRGULA_KP);
        return r;
    }
}

KeyDownClass.prototype.Padrao = function(e){
    return true;
}

// Métodos principais
KeyDownClass.prototype.AlfaNumerico = function(e){
    return this.Padrao(e);
}

KeyDownClass.prototype.Bairro = function(e){
    var Evento = e || window.event;
    var Campo = Evento.target || Evento.srcElement;
    Campo.maxLength = 20;
    return this.Padrao(e);
}

KeyDownClass.prototype.CEP = function(e){
    var Evento = e || window.event;
    var Tecla = Evento.which || Evento.keyCode;
    var Campo = Evento.target || Evento.srcElement;
    Campo.maxLength = 10;
    
    if(Algum(Igual(Tecla), this.Numeros())){
        if(Campo.value.length == 5){
            Campo.value += "-";
        }
        return true;
    }
    
    return Algum(Igual(Tecla), this.Controles());
}

KeyDownClass.prototype.CFOP = function(e){
    return this.Classificacao(e);
}

// Tipos é uma string com qualquer combinação das letras C, F, R e T
KeyDownClass.prototype.CFRT = function(e, Tipos){
    var Evento = e || window.event;
    var Campo = Evento.target || Evento.srcElement;
    Campo.maxLength = 10;
    return this.Padrao(e);
}

KeyDownClass.prototype.Chave = function(e){
    var Evento = e || window.event;
    var Tecla = Evento.which || Evento.keyCode;
    var Campo = Evento.target || Evento.srcElement;
    Campo.maxLength = 11;
    
    if(Algum(Igual(Tecla), this.Numeros())){
        if(Campo.value.length == 4) Campo.value += "-";
        return true;
    }
    
    return Algum(Igual(Tecla), this.Controles());
}

KeyDownClass.prototype.Classificacao = function(e){
    var Evento = e || window.event;
    var Tecla = Evento.which || Evento.keyCode;
    var Campo = Evento.target || Evento.srcElement;
    
    var EhNum = Algum(Igual(Tecla), this.Numeros());
    var EhCtrl = Algum(Igual(Tecla), this.Controles());
    var EhPto = Algum(Igual(Tecla), [this.PONTO, this.PONTO_KP]);
    return EhNum || EhCtrl || EhPto;
}

KeyDownClass.prototype.CNPJ = function(e){
    var Evento = e || window.event;
    var Campo = Evento.target || Evento.srcElement;
    var Tecla = Evento.which || Evento.keyCode;
    Campo.maxLength = 19;
    
    if(Algum(Igual(Tecla), this.Numeros())){
        if(Campo.value.length == 2 || Campo.value.length == 6) Campo.value += ".";
        if(Campo.value.length == 10) Campo.value += "/";
        if(Campo.value.length == 15) Campo.value += "-";
        return true;
    }
    
    return Algum(Igual(Tecla), this.Controles());
}

KeyDownClass.prototype.CNPJ_CPF = function(e, TipoPessoa){
    if(TipoPessoa == "F") return this.CPF(e);
    if(TipoPessoa == "J") return this.CNPJ(e);
}

KeyDownClass.prototype.CodigoMunicipio = function(e){
    var Evento = e || window.event;
    var Campo = Evento.target || Evento.srcElement;
    var Tecla = Evento.which || Evento.keyCode;
    Campo.maxLength = 8;
    return (Algum(Igual(Tecla), this.Numeros()) || Algum(Igual(Tecla), this.Controles()));
}

KeyDownClass.prototype.ComplementoEndereco = function(e){
    var Evento = e || window.event;
    var Campo = Evento.target || Evento.srcElement;
    Campo.maxLength = 20;
    return this.Padrao(e);
}

KeyDownClass.prototype.Conta = function(e){
    var Evento = e || window.event;
    var Campo = Evento.target || Evento.srcElement;
    Campo.maxLength = 10;
    return this.Padrao(e);
}

KeyDownClass.prototype.CPF = function(e){
    var Evento = e || window.event;
    var Tecla = Evento.which || Evento.keyCode;
    var Campo = Evento.target || Evento.srcElement;
    Campo.maxLength = 15;
    
    if(Algum(Igual(Tecla), this.Numeros())){
        if(Campo.value.length == 3 || Campo.value.length == 7) Campo.value += ".";
        if(Campo.value.length == 11) Campo.value += "-";
        return true;
    }
    
    if(Algum(Igual(Tecla), this.Controles())){
        return true;
    }
    
    return false;
}

KeyDownClass.prototype.Data = function(e){
    var Evento = e || window.event;
    var Tecla  = Evento.which || Evento.keyCode;
    var Campo  = Evento.target || Evento.srcElement;
    Campo.maxLength = 10;
    
    if(Algum(Igual(Tecla), this.Numeros())){
        if(Campo.value.length == 2 || Campo.value.length == 5){
            Campo.value += "/";
        }
        return true;
    }

    if(Algum(Igual(Tecla), this.Controles())){
        return true;
    }
    
    if(Algum(Igual(Tecla), this.N_AlfaNum())){
        if(Campo.value.length == 1){
            Campo.value = "0" + Campo.value + "/";
        } else if(Campo.value.length == 4){
            Campo.value = Campo.value.substr(0,3) + "0" + Campo.value.substr(3,1) + "/";
        }
    }
    
    return false;
}

KeyDownClass.prototype.DDD = function(e){
    var Evento = e || window.event;
    var Campo = Evento.target || Evento.srcElement;
    Campo.maxLength = 5;
    return this.Padrao(e);
}

KeyDownClass.prototype.Email = function(e){
    var Evento = e || window.event;
    var Campo = Evento.target || Evento.srcElement;
    Campo.maxLength = 64;
    return this.Padrao(e);
}

KeyDownClass.prototype.Endereco = function(e){
    var Evento = e || window.event;
    var Campo = Evento.target || Evento.srcElement;
    Campo.maxLength = 40;
    return this.Padrao(e);
}

KeyDownClass.prototype.Grade = function(e){
    var Evento = e || windo.event;
    var Campo = Evento.target || Evento.srcElement;
    Campo.maxLength = 5;
    return this.Padrao();
}

// A inscrição estadual muda por estado
KeyDownClass.prototype.InscricaoEstadual = function(e){
    return this.Padrao(e);
}

KeyDownClass.prototype.NumeroEndereco = function(e){
    var Evento = e || window.event;
    var Tecla = Evento.which || Evento.keyCode;
    var Campo = Evento.target || Evento.srcElement;
    Campo.maxLength = 10;
    
    return (Algum(Igual(Tecla), this.Numeros()) || Algum(Igual(Tecla), this.Controles()));
}

KeyDownClass.prototype.Produto = function(e){
    var Evento = e || window.event;
    var Campo = Evento.target || Evento.srcElement;
    Campo.maxLength = 20;
    return this.Padrao(e);
}

KeyDownClass.prototype.Telefone = function(e){
    var Evento = e || window.event;
    var Campo = Evento.target || Evento.srcElement;
    Campo.maxLength = 9;
    return this.Padrao(e);
}

KeyDownClass.prototype.Valor = function(e){
    var Evento = e || window.event;
    var Campo = Evento.target || Evento.srcElement;
    Campo.maxLength = 13;
    return this.Padrao(e);
}
var KeyDown = new KeyDownClass();

// Classe para lidar com mudanças de foco (onBlur e onFocus)
function FocusChangeClass(ClasseCss){
    this.Estilo = ClasseCss;
}

FocusChangeClass.prototype.Padrao = function(e){
    var Evento = e || window.event;
    var Campo  = Evento.target || Evento.srcElement;
    Campo.className = this.Estilo;
}

FocusChangeClass.prototype.AlfaNumerico = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.Bairro = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.CEP = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.CFOP = function(e){
    this.Padrao(e);
}

// Tipos é uma string com qualquer combinação das letras C, F, R e T
FocusChangeClass.prototype.CFRT = function(e, Tipos){
    this.Padrao(e);
}

FocusChangeClass.prototype.Chave = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.Classificacao = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.CNPJ = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.CNPJ_CPF = function(e, TipoPessoa){
    if(TipoPessoa == "F") this.CPF(e);
    if(TipoPessoa == "J") this.CNPJ(e);
}

FocusChangeClass.prototype.CodigoMunicipio = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.ComplementoEndereco = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.Conta = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.CPF = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.Data = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.DDD = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.Email = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.Endereco = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.Grade = function(e){
    this.Padrao(e);
}

// A máscara da Inscrição estadual muda de estado para estado
FocusChangeClass.prototype.InscricaoEstadual = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.NumeroEndereco = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.Produto = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.Telefone = function(e){
    this.Padrao(e);
}

FocusChangeClass.prototype.Valor = function(e){
    this.Padrao(e);
}

// Classe para lidar com coisas específicas do OnBlur
function BlurClass(ClasseCss){
    this.Estilo = ClasseCss;
    this.RegExChave = /^\d{4}\-\d{6}$/;
    this.RegExCNPJ  = /^\d{2}\.\d{3}\.\d{3}\/\d{4}-\d{2,3}$/;
    this.RegExCPF   = /^\d{3}\.\d{3}\.\d{3}\-\d{2,3}$/;
    this.RegExData  = /^\d{2}\/\d{2}\/(\d{2}|\d{4})$/;
}
BlurClass.prototype = new FocusChangeClass();

BlurClass.prototype.Chave = function(e){
    var Evento = e || window.event;
    var Campo  = Evento.target || Evento.srcElement;
    
    this.Padrao(e);
    if(Campo.value != "" && !this.RegExChave.test(Campo.value)){
        alert("Formato da chave inválido.");
        Campo.focus();
    }
}

BlurClass.prototype.CNPJ = function(e){
    var Evento = e || window.event;
    var Campo  = Evento.target || Evento.srcElement;
    
    this.Padrao(e);
    if(Campo.value != "" && !this.RegExCNPJ.test(Campo.value)){
        alert("Formato de CNPJ inválido.");
        Campo.focus();
    }
}

BlurClass.prototype.CPF = function(e){
    var Evento = e || window.event;
    var Campo  = Evento.target || Evento.srcElement;
    
    this.Padrao(e);
    if(Campo.value != "" && !this.RegExCPF.test(Campo.value)){
        alert("Formato de CPF inválido.");
        Campo.focus();
    }
}

BlurClass.prototype.Data = function(e){
    var Evento = e || window.event;
    var Campo  = Evento.target || Evento.srcElement;

    this.Padrao(e);
    if(Campo.value != "" && !this.RegExData.test(Campo.value)){
        alert("Formato de data inválido.");
        Campo.focus();
    }
}
var Blur = new BlurClass("campoOut");

// Classe para lidar com coisas específicas do OnFocus
function FocusClass(ClasseCss){
    this.Estilo = ClasseCss;
}
FocusClass.prototype = new FocusChangeClass();
var Focus = new FocusClass("campoOver");
