function alertWithAllMessages(errors) {
    var msg = "";
    for (var i=0; i<errors.length; i++) {
        err = errors[i];
        msg += err.message + "\n";
    }
    alert(msg);
}

function getDomain(ctl) {
    var arr = ctl.id.split("-");
    var formName = arr[0];
    var fieldName = arr[2];
    var index = arr[3];
    var domId = formName + "-dar-" + fieldName + "-" + index;
    var darElem = document.getElementById(domId);
    if (darElem) {
        var domClassName = darElem.className.split(" ")[1];
        return eval("new " + domClassName + "(formName, fieldName, index)");
    } else {
        return null;
    }
}

function Domain(formName, fieldName, index) {

    var self = new Object();

    self.formName = formName;
    self.fieldName = fieldName;
    self.index = index;

    self.getZoneName = function(zoneName) {
        return this.formName +
        "-" + zoneName +
        "-" + this.fieldName +
        "-" + this.index
    }

    self.getZoneElement = function(zoneName) {
        return document.getElementById(this.getZoneName(zoneName));
    }

    self.setValue = function(value) {
        this.getZoneElement("val").value = value;
    }

    self.getValue = function() {
        return this.getZoneElement("val").value;
    }

    self.setErrorMessage = function(msg) {
        var err = this.getZoneElement("err");
        if (!err) {
            var dar = this.getZoneElement("dar");
            var err = document.createElement("span");
            err.id = this.getZoneName("err");
            dar.appendChild(err);
        }
        err.innerHTML = msg;
        if (msg.length == 0) {
            err.className = "hidden";
        } else {
            err.className = "error";
        }
    }

    self.isRequired = function() {
        return this.getZoneElement("dar").className.indexOf(" required") >= 0;
    }

    self.getErrorMessage = function() {
        var err = this.getZoneElement("err");
        if (err) {
            return err.innerHTML;
        } else {
            return "";
        }
    }

    self.checkRequired = function() {
        if (this.isRequired() && this.getValue().length == 0) {
            this.setErrorMessage("Field is required!");
        }
    }

    self.validate = function() {
    }

    self.preSubmit = function() {
    }

    self.isValid = function() {
        this.setErrorMessage("");
        this.checkRequired();
        this.validate();
        return (this.getErrorMessage() == "");
    }

    self.ressetValue = function() {
        this.setValue((this.defaultValue ? this.defaultValue : ""));
    }

    return self;

}


/**
 *  Secure Hash Algorithm (SHA1)
 *  http://www.webtoolkit.info/
 */
function SHA1(msg) {

	function rotate_left(n,s) {
		var t4 = ( n<<s ) | (n>>>(32-s));
		return t4;
	}

	function lsb_hex(val) {
		var str="";
		var i;
		var vh;
		var vl;

		for( i=0; i<=6; i+=2 ) {
			vh = (val>>>(i*4+4))&0x0f;
			vl = (val>>>(i*4))&0x0f;
			str += vh.toString(16) + vl.toString(16);
		}
		return str;
	}

	function cvt_hex(val) {
		var str="";
		var i;
		var v;

		for( i=7; i>=0; i-- ) {
			v = (val>>>(i*4))&0x0f;
			str += v.toString(16);
		}
		return str;
	}


	function Utf8Encode(string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";

		for (var n = 0; n < string.length; n++) {

			var c = string.charCodeAt(n);

			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}

		}

		return utftext;
	}

	var blockstart;
	var i, j;
	var W = new Array(80);
	var H0 = 0x67452301;
	var H1 = 0xEFCDAB89;
	var H2 = 0x98BADCFE;
	var H3 = 0x10325476;
	var H4 = 0xC3D2E1F0;
	var A, B, C, D, E;
	var temp;

	msg = Utf8Encode(msg);

	var msg_len = msg.length;

	var word_array = new Array();
	for( i=0; i<msg_len-3; i+=4 ) {
		j = msg.charCodeAt(i)<<24 | msg.charCodeAt(i+1)<<16 |
		msg.charCodeAt(i+2)<<8 | msg.charCodeAt(i+3);
		word_array.push( j );
	}

	switch( msg_len % 4 ) {
		case 0:
			i = 0x080000000;
		break;
		case 1:
			i = msg.charCodeAt(msg_len-1)<<24 | 0x0800000;
		break;

		case 2:
			i = msg.charCodeAt(msg_len-2)<<24 | msg.charCodeAt(msg_len-1)<<16 | 0x08000;
		break;

		case 3:
			i = msg.charCodeAt(msg_len-3)<<24 | msg.charCodeAt(msg_len-2)<<16 | msg.charCodeAt(msg_len-1)<<8	| 0x80;
		break;
	}

	word_array.push( i );

	while( (word_array.length % 16) != 14 ) word_array.push( 0 );

	word_array.push( msg_len>>>29 );
	word_array.push( (msg_len<<3)&0x0ffffffff );


	for ( blockstart=0; blockstart<word_array.length; blockstart+=16 ) {

		for( i=0; i<16; i++ ) W[i] = word_array[blockstart+i];
		for( i=16; i<=79; i++ ) W[i] = rotate_left(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);

		A = H0;
		B = H1;
		C = H2;
		D = H3;
		E = H4;

		for( i= 0; i<=19; i++ ) {
			temp = (rotate_left(A,5) + ((B&C) | (~B&D)) + E + W[i] + 0x5A827999) & 0x0ffffffff;
			E = D;
			D = C;
			C = rotate_left(B,30);
			B = A;
			A = temp;
		}

		for( i=20; i<=39; i++ ) {
			temp = (rotate_left(A,5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) & 0x0ffffffff;
			E = D;
			D = C;
			C = rotate_left(B,30);
			B = A;
			A = temp;
		}

		for( i=40; i<=59; i++ ) {
			temp = (rotate_left(A,5) + ((B&C) | (B&D) | (C&D)) + E + W[i] + 0x8F1BBCDC) & 0x0ffffffff;
			E = D;
			D = C;
			C = rotate_left(B,30);
			B = A;
			A = temp;
		}

		for( i=60; i<=79; i++ ) {
			temp = (rotate_left(A,5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) & 0x0ffffffff;
			E = D;
			D = C;
			C = rotate_left(B,30);
			B = A;
			A = temp;
		}

		H0 = (H0 + A) & 0x0ffffffff;
		H1 = (H1 + B) & 0x0ffffffff;
		H2 = (H2 + C) & 0x0ffffffff;
		H3 = (H3 + D) & 0x0ffffffff;
		H4 = (H4 + E) & 0x0ffffffff;

	}

	return (cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4)).toLowerCase();

}

/**
 * Array com nomes para a qualidade das senhas (0 a 4).
 */
var passwordStrength = ["Very Weak", "Weak", "Mediocre", "Strong", "Very Strong"];

/**
 * Calcula a qualidade da senha.
 * Retorna um inteiro de 0 (pior) a 4 (melhor)
 */
function getPasswordStrength(pwd) {

    var lowerChars = 0;
    var upperChars = 0;
    var digits = 0;
    var otherChars = 0;

    for (var i=0; i<pwd.length; i++) {
        var chr = pwd.charAt(i);
        if (chr >= "a" && chr <= "z") lowerChars++;
        else if (chr >= "A" && chr <= "Z") upperChars++;
        else if (chr >= "0" && chr <= "9") digits++;
        else otherChars++;
    }

    var types = (lowerChars > 0 ? 1 : 0) +
            (upperChars > 0 ? 1 : 0) +
            (digits > 0 ? 1 : 0) +
            (otherChars > 0 ? 1 : 0);

    var score = (pwd.length > 12 ? 12 : pwd.length) +
            (lowerChars > 1 ? 5 : lowerChars > 0 ? 2 : 0) +
            (upperChars > 1 ? 5 : upperChars > 0 ? 2 : 0) +
            (otherChars > 1 ? 5 : otherChars > 0 ? 2 : 0) +
            (    digits > 1 ? 5 :     digits > 0 ? 2 : 0) +
            types * 3;

    return score > 42 ? 4
            : score > 30 ? 3
            : score > 20 ? 2
            : score > 10 ? 1
            : 0;
}

/**
 * Atualiza a qualidade da senha.
 * Estou colocando um texto, mas poderia ser um gif
 * diferente para cada score (0 a 4).
 */
function checkPasswordStrength(elem) {
    var score = getPasswordStrength(elem.value);
    var textDiv = document.getElementById(elem.id + "_strength");
    if (textDiv) textDiv.innerHTML=passwordStrength[score];
    var img = document.getElementById(elem.id + "_img");
    var old = img.src;
    var p = old.lastIndexOf("/");
    var pth = old.substring(0,p);
    if (img) img.src = pth + "/pwd_strength_" + score + ".gif";
}

/**
 * Valida o formulário chamando a validação de todos os campos
 */
function validateForm(name) {
    var fName = name + "-dar-";
    var len = fName.length;
    var elms = document.getElementsByTagName("span");
    var ok = true;
    for (var i=0; i < elms.length; i++) {
        var e = elms[i];
        if (e.id.substr(0, len) == fName) {
            var a = getDomain(e);
            if (a && !a.isValid()) {
                ok = false;
            }
        }
    }
    return ok;
}

/**
 * Resseta os dados do formulário
 */
function ressetForm(name) {
    var fName = name + "-dar-";
    var len = fName.length;
    var elms = document.getElementsByTagName("span");
    var ok = true;
    for (var i=0; i < elms.length; i++) {
        var e = elms[i];
        if (e.id.substr(0, len) == fName) {
            var a = getDomain(e);
            if (a) {
                a.ressetValue();
                a.setErrorMessage("");
            }
        }
    }
    return ok;
}

function validate(ctl) {
    getDomain(ctl).validate();
}


function Form(formName) {

    var self = new Object();

    self.validate = function() {
        var fName = this.formName + "-dar-";
        var len = fName.length;
        var elms = document.getElementsByTagName("span");
        var ok = true;
        for (var i=0; i < elms.length; i++) {
            var e = elms[i];
            if (e.id.substr(0, len) == fName) {
                var a = getDomain(e);
                if (a && !a.isValid()) {
                    ok = false;
                }
            }
        }
        return ok;
    }

    /**
     * Tratamento de evento executado antes de submeter um form.
     * Chama o método preSubmit de cada campo do form.
     */
    self.preSubmit = function() {
        var fName = this.formName + "-dar-";
        var len = fName.length;
        var elms = document.getElementsByTagName("span");
        var ok = true;
        for (var i=0; i < elms.length; i++) {
            var e = elms[i];
            if (e.id.substr(0, len) == fName) {
                var a = getDomain(e);
                if (a) a.preSubmit();
            }
        }
        return ok;
    }

    self.scriptName = function() {
        var script = "";
        var ibe = document.getElementById(this.blockName);
        if (ibe && ibe.className) {
            script = ibe.className + ".do";
        }
        return script;
    }

    /**
     * Executa uma ação de um formulário.
     * actionType - Tipo de ação
     * actionName - Nome da ação
     * id - Opcional - Indica um registro específico
     * element - Elemento a partir do qual a ação foi disparada
     */
    self.executeAction = function(actionType, actionName, id, element) {
        if (actionType == "LIST") this.executeList();
        else if (actionType == "CLEAR_QUERY") this.executeClearQuery();
        else if (actionType == "NEW") this.executeNew(actionName, element);
        else if (actionType == "CLEAR_NEW") this.executeClearNew();
        else if (actionType == "CANCEL_RECORD") this.executeCancelRecord();
        else if (actionType == "INSERT") this.executeInsert(actionName);
        else if (actionType == "VIEW") this.executeView(actionName, id);
        else if (actionType == "UPDATE") this.executeUpdate(actionName, id, element);
        else if (actionType == "SAVE") this.executeSave(actionName, id);
        else if (actionType == "DELETE") this.executeDelete(actionName, id);
        else if (actionType == "CUSTOM") this.executeCustom(actionName, element);
    }
    
    self.executeQuery = function() {
        var id = this.blockName + "_QUERY_AREA";
        var elem = this.getSpanElement(id);
        $.post('?zAction=Query&zTemplate=no', null, function(data) {
            elem.innerHTML = data;
        });
    }

    self.executeClearQuery = function() {
        $("#" + this.blockName + "_LIST_AREA").html("");
        $("#" + this.getRecordAreaId()).html("");
        ressetForm(formName);
    }

    self.executeCancelRecord = function() {
        var rec = document.getElementById(this.getRecordAreaId());
        if (rec) {
            if (rec.tagName == "TD") {
                // Se estiver dentro de uma table LIST, exclui o respectivo TR.
                var trx = rec.parentNode;
                trx.parentNode.removeChild(trx);
            } else {
                // Se n�o estiver dentro de uma table LIST, limpa o conte�do
                rec.innerHTML = "";
            }
        }
    }

    self.executeClearNew = function() {
        ressetForm(formName);
    }

    self.executeList = function() {
        if (this.validate()) {
            var fq = document.getElementById(this.blockName + "_Query");
            var id = this.blockName + "_LIST_AREA";
            var elem = this.getSpanElement(id);
            $.post(this.scriptName() + '?zAction=List&zTemplate=no&zBlock=' + this.blockName,
                    $(fq).serialize(), function(data) {
                var json = getJson(data);
                if (json.error) {
                    alert("ERRO: " + json.error);
                } else {
                    elem.innerHTML = data;
                    if (fq && fq.parentNode) fq.parentNode.removeChild(fq);
                }
            });
        }
    }

    self.executeNew = function(actionName, element) {
        // Remove qualquer área de registro que porventura esteja aberta.
        var elem = document.getElementById(this.getRecordAreaId());
        if (elem) {
            // Se elemento for uma célula, exclui a respectiva TR junto
            if (elem.tagName == "TD") {
                var trx = elem.parentNode;
                trx.parentNode.removeChild(trx);
            } else {
                elem.parentNode.removeChild(elem);
            }
        }
        
        // Cria uma área de registro. Se o bloco tem uma table com a lista de
        // registros, cria dentro dela, senão cria um DIV separado.
        var tbl = document.getElementById(this.blockName + "_listTable");
        if (tbl) {
            id = this.getRecordAreaId();
            var par = tbl.parentNode;
            var td = document.createElement("span");
            td.id = id;
            par.insertBefore(td, tbl);
        } else {
            elem = this.getSpanElement(id);
        }

        $.post(this.scriptName() + '?zAction=Insert&zExec=New&zTemplate=no&zBlock=' + this.blockName,
                $("form:" + id).serialize(), function(data) {
            var json = getJson(data);
            $("#" + id).html(data);
            if (json.js) {
                eval(json.js);
            }
        });
    }

    self.getRecordAreaId = function() {
        return this.blockName + "_RECORD_AREA";
    }

    self.executeInsert = function() {
        if (this.validate()) {
            this.preSubmit();
            var id = this.getRecordAreaId();
            var fName = this.blockName + "_INSERT";
            var fx = this;
            var elem = this.getSpanElement(id);
            var data = $("form#" + fName).serialize();
            //$("#" + id).html("Inserting...");
            $.post(this.scriptName() + '?zAction=Insert&zTemplate=no&zBlock=' + this.blockName, data, function(data) {
                var json = getJson(data);
                if (json.error) {
                    alert("ERRO: " + json.error);
                } else {
                    $("#" + id).html(data);
                    var elem = document.getElementById(fx.blockName + "_LIST_AREA");
                    if (elem && elem.innerHTML.length > 0) {
                        formAction(fx.blockName + "_Query", "LIST");
                    }
                }
            });
        }
    }

    self.executeView = function(actionName, pk) {
        var id = this.getRecordAreaId();
        var fName = this.blockName + "_VIEW";
        var elem = this.getSpanElement(id);
        var data = $("form#" + fName).serialize();
        //$("#" + id).html("Loading...");
        $.post('?zAction=View&zTemplate=no&id='+pk, data, function(data) {
            var json = getJson(data);
            $("#" + id).html(data);
            if (json.error) {
                alert("ERRO: " + json.error);
            }
        });
    }

    self.executeUpdate = function(actionName, pk, element) {
        var id = this.getRecordAreaId();
        var elem = document.getElementById(id);
        if (elem) {
            if (elem.tagName == "TD") {
                var trx = elem.parentNode;
                trx.parentNode.removeChild(trx);
            } else {
                elem.parentNode.removeChild(elem);
            }
        }
        var tr = element.parentNode;
        // Na coluna de Action, tem um SPAN com "editar" dentro do TD
        if (tr.tagName == "TD") tr = tr.parentNode;
        var tbody = tr.parentNode;
        var newtr = document.createElement("tr");
        var td = document.createElement("td");
        td.id = id;
        td.colSpan = tr.childNodes.length;
        newtr.appendChild(td);
        
        var nx = tr.nextSibling;
        if (nx) tbody.insertBefore(newtr, tr.nextSibling);
        else tbody.appendChild(newtr);

        var fName = this.blockName + "_UPDATE";
        var data = $("form#" + fName).serialize();
        //$("#" + id).html("Loading...");
        $.post(this.scriptName() + '?zAction=Update&zTemplate=no&id='+pk+'&zBlock='+this.blockName, data, function(data) {
            var json = getJson(data);
            if (json.error) {
                alert("ERRO: " + json.error);
            } else {
                $("#" + id).html(data);
                if (json.js) {
                    eval(json.js);
                }
            }
        });
    }

    self.executeSave = function() {
        if (this.validate()) {
            this.preSubmit();
            var id = this.getRecordAreaId();
            var fName = this.blockName + "_UPDATE";
            var fx = this;
            var elem = this.getSpanElement(id);
            var data = $("form#" + fName).serialize();
            $.post(this.scriptName() + '?zAction=Update&zExec=Save&zTemplate=no', data, function(data) {
                var json = getJson(data);
                if (json.errors) {
                    alert("ERRO: " + json.errors);
                } else if (json.error) {
                    alert("ERRO: " + json.error);
                } else {
                    $("#" + id).html(data);
                    var elem = document.getElementById(fx.blockName + "_LIST_AREA");
                    if (elem && elem.innerHTML.length > 0) {
                        formAction(fx.blockName + "_Query", "LIST");
                    }
                }
            });
        }
    }

    self.executeDelete = function(actionName, pk) {
        if (!confirm("Tem certeza que deseja excluir este registro?")) return;

        var name = this.blockName + "_Query";
        var id = this.blockName + "_LIST_AREA";
        $.post(this.scriptName() + '?zAction=Delete&zTemplate=no&id='+pk, null, function(data) {
            var json = getJson(data);
            if (json.error) {
                alert("ERRO: " + json.error);
            } else {
                //$("#" + id).html(data);
                formAction(name, "LIST");
            }
        });
    }

    self.executeCustom = function(actionName, element) {
        if (this.validate()) {
            this.preSubmit();
            var fName = this.formName;
            var data = $("form#" + fName).serialize();
            var id = this.blockName;
            $.post(this.scriptName() + '?zAction=' + actionName + '&zExec=Custom&zTemplate=no',
            data, function(data) {
                var json = getJson(data);
                if (json.errors) {
                    alertWithAllMessages(json.errors);
                } else if (json.redirectTo) {
                    document.location.href = json.redirectTo;
                } else {
                    $("#" + id).html(data);
                }
            });
        }
    }

    self.getSpanElement = function(id) {
        var elem = document.getElementById(id);
        if (!elem) {
            var blockElement = document.getElementById(this.blockName);
            elem = document.createElement("span");
            elem.id = id;
            blockElement.appendChild(elem);
        }
        return elem;
    }

    self.formName = formName;
    self.blockName = formName.split("_")[0];

    return self;

}

function getJson(data) {
    var json = "";
    p1 = data.toString().indexOf("<!--");
    if (p1>=0 && p1<3) {
        var p2 = data.toString().indexOf("-->");
        var jsonStr = data.toString().substring(p1+4, p2);
        eval("json = " + jsonStr);
    }
    return json;
}

/**
 * Executa uma ação em um bloco.
 * @param formName - ID do formulário que está sendo submetido
 * @param actionName - Nome da ação a ser executada
 * @param id - Para casos de registros simples, identifica a primary key do mesmo
 * @param actionType - Tipo de ação (executer)
 * @param element - Elemento do DOM que está disparando a ação
 */
function formAction(formName, actionName, id, actionType, element) {
    var form = new Form(formName);
    if (actionType == null) actionType = actionName.toUpperCase();
    form.executeAction(actionType, actionName, id, element);
}

/**
 * Apresenta um bloco dentro de uma tabbed view.
 * @param elem Elemento de TAB clicado
 * @param outer Nome do elemento que contém o corpo da tabbed view
 * @param inner Nome do bloco a ser apresentado
 * @param block Classe que responde ao bloco. Se de outro sistema, deve iniciar
 * com ../sistema/Classe.
 * @param action Ação inicial a ser apresentada na área, caso ela ainda não
 * esteja criada
 * @param urlParams Parâmetros a serem acrescentados na URL do bloco
 */
function showInnerBlock(elem, outer, inner, block, action, urlParams) {
    var e = document.getElementById(inner);
    //e.innerHTML = "Loading...";
    var url = block + ".do?zAction=" + action + "&zTemplate=no&zBlock=" + inner;
    if (action == "View" || action == "Update") {
        // ******************* REVER ISSO **************************
        url += "&id=1";
    }
    $.post(url, null, function(data) {
        var json = getJson(data);
        if (json.error) {
            alert("ERRO: " + json.error);
        } else {
            //elem.innerHTML = data;
            //fq.parentNode.removeChild(fq);
            e.innerHTML = "<div id='" + inner + "_" + action + "_AREA'>" + data + "</div>";
            hideInnerBlocks(outer);
            e.style.display = "block";
            elem.className = "tabSelected";
        }
    });
}

function hideInnerBlocks(outer) {
    var o = document.getElementById(outer + "_INNERBLOCKS");
    var children = o.childNodes;
    for (var i = 0; i < children.length; i++) {
        var child = children[i];
        child.style.display = "none";
    }
    o = document.getElementById(outer + "_INNERTABS");
    children = o.childNodes;
    for (var i = 0; i < children.length; i++) {
        var child = children[i];
        if (child.className == "tabSelected") {
            child.className = "tab";
        }
    }
}

function navigateList(fName, direction) {
    var offsetElem = document.getElementById(fName + "_ZOFFSET");
    var offset = parseInt(offsetElem.value);
    var limitElem = document.getElementById(fName + "_ZLIMIT");
    var limit = limitElem.value;
    offset += parseInt(limit) * direction;
    if (offset < 0) offset = 1;
    offsetElem.value = offset;
    formAction(fName,'LIST',null,'LIST');
}

function changeOrder(fName, column) {
    var orderElem = document.getElementById(fName + "_ZORDER");
    //alert(orderElem.value);
    orderElem.value = column;
    formAction(fName,'LIST',null,'LIST');
}

function selectionCheckClick(ctl,valor,campo) {
    if (ctl.checked) {
        campo.value += (campo.value.length == 0 ? "":",") + valor;
    } else {
        var a1 = campo.value.split(",");
        for (var i=a1.length-1; i>=0; i--) {
            if (a1[i]== valor) a1.splice(i,1);
        }
        campo.value = a1.join(",");
    }
}


//=================================================================
//=====        ATENÇÃO - A LINHA ABAIXO É IMPORTANTE          =====
//=================================================================
$(document).ready(function() {
    $.ajaxSetup({
        cache: false
    });
});

