var MyWidget = SuperWidget.extend({
    instanceId: null,

    init: function() {
        this.clearMessage();
        $("#detalheSolicitacao_" + this.instanceId).hide();
    },

    bindings: {
        local: {
            "pesquisar": ["click_consultarSolicitacoes"],
            "acompanhar": ["click_acompanharSolicitacao"],
            "limpar": ["click_limparConsulta"]
        },
        global: {}
    },

    consultarSolicitacoes: function(htmlElement, event) {
        if (event) event.preventDefault();

        var numero = this.normalizarTexto($("#filtroNumero_" + this.instanceId).val());
        var solicitante = this.normalizarTexto($("#filtroSolicitante_" + this.instanceId).val());
        var status = this.normalizarTexto($("#filtroStatus_" + this.instanceId).val());

        this.clearMessage();
        $("#detalheSolicitacao_" + this.instanceId).hide().empty();

        if (numero) {
            this.renderizarConsultaPorNumero(numero);
            return;
        }

        this.renderizarListaGenerica(solicitante, status);
    },

    acompanharSolicitacao: function(htmlElement, event) {
        if (event) event.preventDefault();

        var numero = $(htmlElement).attr("data-numero-sc");
        if (!numero) return;

        $("#filtroNumero_" + this.instanceId).val(numero);
        this.renderizarTracker(numero);
    },

    limparConsulta: function(htmlElement, event) {
        if (event) event.preventDefault();

        $("#filtroNumero_" + this.instanceId).val("");
        $("#filtroSolicitante_" + this.instanceId).val("");
        $("#filtroStatus_" + this.instanceId).val("");
        $("#listaSolicitacoes_" + this.instanceId).empty();
        $("#detalheSolicitacao_" + this.instanceId).hide().empty();
        this.clearMessage();
    },

    bindDynamicActions: function() {
        var self = this;
        $("#listaSolicitacoes_" + this.instanceId)
            .find("[data-acompanhar]")
            .off("click.tracker")
            .on("click.tracker", function(event) {
                self.acompanharSolicitacao(this, event);
            });
    },

    renderizarConsultaPorNumero: function(numero) {
        var dados = this.consultarSC(numero);

        if (!dados || !dados.rows.length || !this.temSCValida(dados.rows[0])) {
            $("#listaSolicitacoes_" + this.instanceId).html(this.emptyState("Nenhuma solicitacao encontrada para a SC informada."));
            return;
        }

        $("#listaSolicitacoes_" + this.instanceId).html(this.montarTabelaSolicitacoes(dados.rows));
        this.bindDynamicActions();
        this.renderizarTracker(numero, dados);
    },

    renderizarListaGenerica: function(solicitante, status) {
        var ds = null;
        var constraints = [];

        try {
            if (solicitante) constraints.push(this.criarConstraint("C1_SOLICIT", solicitante, solicitante));
            if (status) constraints.push(this.criarConstraint("STATUS", status, status));
            ds = this.buscarDataset("dsSolicitacoesCompra", null, constraints, null);
        } catch (e) {
            ds = null;
        }

        if (!ds || !ds.values || !ds.values.length) {
            this.showMessage("Informe o numero da SC para abrir o tracker. A listagem geral depende de um dataset de consulta de solicitacoes no ambiente Fluig.", "info");
            $("#listaSolicitacoes_" + this.instanceId).html(this.emptyState("Digite uma SC e clique em Pesquisar."));
            return;
        }

        $("#listaSolicitacoes_" + this.instanceId).html(this.montarTabelaSolicitacoes(ds.values));
        this.bindDynamicActions();
    },

    consultarSC: function(numero) {
        var constraints = [
            this.criarConstraint("numeroSCProtheus", numero, numero)
        ];
        var ds = this.buscarDataset("ds_consultaSC", null, constraints, null);

        return {
            dataset: ds,
            rows: ds && ds.values ? ds.values : []
        };
    },

    criarConstraint: function(campo, valorInicial, valorFinal) {
        if (typeof DatasetFactory !== "undefined" && typeof ConstraintType !== "undefined") {
            return DatasetFactory.createConstraint(campo, valorInicial, valorFinal, ConstraintType.MUST);
        }

        return {
            _field: campo,
            _initialValue: valorInicial,
            _finalValue: valorFinal,
            _type: 1,
            fieldName: campo,
            initialValue: valorInicial,
            finalValue: valorFinal,
            constraintType: 1
        };
    },

    buscarDataset: function(nome, fields, constraints, sortFields) {
        if (typeof DatasetFactory !== "undefined") {
            return DatasetFactory.getDataset(nome, fields, constraints, sortFields);
        }

        var retorno = { values: [] };

        $.ajax({
            url: "/api/public/ecm/dataset/datasets",
            type: "POST",
            async: false,
            contentType: "application/json",
            dataType: "json",
            data: JSON.stringify({
                name: nome,
                fields: fields || null,
                constraints: constraints || [],
                order: sortFields || null
            }),
            success: function(response) {
                var content = response && response.content ? response.content : response;
                retorno = {
                    values: content && content.values ? content.values : []
                };
            },
            error: function(xhr) {
                var mensagem = xhr && xhr.responseText ? xhr.responseText : "Falha ao consultar dataset " + nome;
                throw new Error(mensagem);
            }
        });

        return retorno;
    },

    renderizarTracker: function(numero, dadosConsulta) {
        var detalhe = $("#detalheSolicitacao_" + this.instanceId);
        detalhe.show().html(this.loadingState("Consultando dados da SC " + this.escapeHTML(numero) + "..."));

        try {
            var dados = dadosConsulta || this.consultarSC(numero);
            if (!dados || !dados.rows.length || !this.temSCValida(dados.rows[0])) {
                detalhe.html(this.emptyState("Nao foi possivel carregar o tracker desta SC."));
                return;
            }

            var resumo = this.montarResumoSC(dados.rows);
            detalhe.html(this.montarTracker(resumo));
        } catch (e) {
            detalhe.html(this.emptyState("Erro ao carregar o tracker: " + this.escapeHTML(String(e))));
        }
    },

    montarTabelaSolicitacoes: function(rows) {
        var exibidos = {};
        var html = [
            '<div class="tracker-table-wrap">',
            '<table class="table tracker-table">',
            '<thead><tr>',
            '<th>Solicitacao</th>',
            '<th>Solicitante</th>',
            '<th>Data</th>',
            '<th>Status</th>',
            '<th>Pedido</th>',
            '<th class="text-right">Acao</th>',
            '</tr></thead><tbody>'
        ];

        for (var i = 0; i < rows.length; i++) {
            var row = rows[i] || {};
            var numero = this.primeiroValor(row.C1_NUM, row.numero, row.NUMERO);
            if (!numero) continue;
            if (exibidos[numero]) continue;
            exibidos[numero] = true;

            html.push(
                '<tr>',
                '<td><strong>SC ' + this.escapeHTML(numero) + '</strong></td>',
                '<td>' + this.escapeHTML(this.primeiroValor(row.C1_SOLICIT, row.solicitante, "-")) + '</td>',
                '<td>' + this.escapeHTML(this.formatarData(this.primeiroValor(row.C1_EMISSAO, row.data, ""))) + '</td>',
                '<td>' + this.montarBadge(this.primeiroValor(row.STATUS, row.status, "-")) + '</td>',
                '<td>' + this.escapeHTML(this.formatarDocumento(this.primeiroValor(row.C1_PEDIDO, row.pedido, "-"))) + '</td>',
                '<td class="text-right">',
                '<button type="button" class="btn btn-default btn-sm" data-acompanhar data-numero-sc="' + this.escapeHTML(numero) + '">',
                '<span class="fluigicon fluigicon-eye-open"></span> Acompanhar',
                '</button>',
                '</td>',
                '</tr>'
            );
        }

        html.push('</tbody></table></div>');
        return html.join("");
    },

    montarResumoSC: function(rows) {
        var base = rows[0] || {};
        var cotacoes = this.parseJsonArray(base.COTACOES_JSON);
        var pedidos = this.parseJsonArray(base.PEDIDO_JSON);
        var totalSC = this.somarCampo(rows, "C1_TOTAL");
        var menorCotacao = this.encontrarMenorCotacao(cotacoes);
        var pedido = this.formatarDocumento(this.primeiroValor(base.C1_PEDIDO, menorCotacao ? menorCotacao.C8_NUMPED : ""));
        var cotacao = this.formatarDocumento(this.primeiroValor(base.C1_COTACAO, menorCotacao ? menorCotacao.C8_NUM : ""));
        var status = this.definirStatus(base, cotacao, pedido);
        var assinaturas = this.extrairAssinaturasPedido(pedidos);

        return {
            numero: this.primeiroValor(base.C1_NUM, ""),
            solicitante: this.primeiroValor(base.C1_SOLICIT, "-"),
            data: this.formatarData(base.C1_EMISSAO),
            valor: totalSC > 0 ? this.formatarMoeda(totalSC) : this.formatarMoeda(this.numeroBR(base.C1_TOTAL)),
            status: status,
            cotacao: cotacao,
            pedido: pedido,
            fornecedor: menorCotacao ? this.primeiroValor(menorCotacao.A2_NOME, menorCotacao.C8_FORNOME, menorCotacao.C8_FORNECE, "-") : "-",
            menorValor: menorCotacao ? this.formatarMoeda(this.numeroBR(menorCotacao.C8_TOTAL)) : "-",
            itens: rows,
            cotacoes: cotacoes,
            pedidos: pedidos,
            assinaturas: assinaturas,
            cotacaoErro: base.COTACAO_ERRO || "",
            pedidoErro: base.PEDIDO_ERRO || "",
            atualizadoEm: this.montarDataHora(base.data_consulta, base.hora_consulta)
        };
    },

    montarTracker: function(resumo) {
        var etapas = this.montarEtapas(resumo);

        return [
            '<article class="tracker-card tracker-card-main">',
            '<div class="tracker-title-row">',
            '<div>',
            '<h3>SC ' + this.escapeHTML(resumo.numero || "-") + '</h3>',
            '<span>Acompanhamento completo da solicitacao</span>',
            '</div>',
            this.montarBadge(resumo.status),
            '</div>',
            '<div class="tracker-summary-grid">',
            this.montarInfo("Solicitante", resumo.solicitante),
            this.montarInfo("Data da solicitacao", resumo.data || "-"),
            this.montarInfo("Valor estimado", resumo.valor || "-"),
            this.montarInfo("Cotacao", resumo.cotacao || "-"),
            this.montarInfo("Pedido", resumo.pedido || "-"),
            this.montarInfo("Fornecedor sugerido", resumo.fornecedor || "-"),
            '</div>',
            '</article>',
            '<article class="tracker-card">',
            '<div class="tracker-steps">' + etapas.join("") + '</div>',
            '</article>',
            '<div class="tracker-grid">',
            '<div>',
            this.montarCotacoes(resumo),
            this.montarPedidos(resumo),
            this.montarItens(resumo),
            '</div>',
            '<div>',
            this.montarAprovacoes(resumo),
            this.montarResumoFinal(resumo),
            '</div>',
            '</div>'
        ].join("");
    },

    montarEtapas: function(resumo) {
        var temCotacao = this.documentoValido(resumo.cotacao);
        var temPedido = this.documentoValido(resumo.pedido);
        var aprovado = resumo.assinaturas.length > 0 && this.todasAssinaturasAprovadas(resumo.assinaturas);

        return [
            this.montarEtapa("Solicitacao", "Criada", true, "fluigicon-shopping-cart"),
            this.montarEtapa("Cotacao", temCotacao ? resumo.cotacao : "Pendente", temCotacao, "fluigicon-link"),
            this.montarEtapa("Pedido", temPedido ? resumo.pedido : "Aguardando", temPedido, "fluigicon-file"),
            this.montarEtapa("Aprovacao", aprovado ? "Aprovado" : "Pendente", aprovado, "fluigicon-ok-circle"),
            this.montarEtapa("Entrega", "Aguardando", false, "fluigicon-truck")
        ];
    },

    montarEtapa: function(titulo, detalhe, concluida, icone) {
        return [
            '<div class="tracker-step ' + (concluida ? "is-done" : "is-pending") + '">',
            '<div class="tracker-step-icon"><span class="fluigicon ' + icone + '"></span></div>',
            '<strong>' + this.escapeHTML(titulo) + '</strong>',
            '<span>' + this.escapeHTML(detalhe || "-") + '</span>',
            '</div>'
        ].join("");
    },

    montarCotacoes: function(resumo) {
        var cotacoes = resumo.cotacoes || [];
        var html = [
            '<section class="tracker-card">',
            '<div class="tracker-section-head"><h4>Cotacoes</h4><span>' + cotacoes.length + '</span></div>'
        ];

        if (!cotacoes.length) {
            html.push(this.emptyInline(resumo.cotacaoErro || "Nenhuma cotacao vinculada ate o momento."));
        } else {
            html.push('<div class="tracker-mini-table"><table class="table"><thead><tr><th>Fornecedor</th><th>Item</th><th>Valor</th><th>Pedido</th></tr></thead><tbody>');
            for (var i = 0; i < Math.min(cotacoes.length, 5); i++) {
                var c = cotacoes[i] || {};
                html.push(
                    '<tr>',
                    '<td>' + this.escapeHTML(this.primeiroValor(c.A2_NOME, c.C8_FORNOME, c.C8_FORNECE, "-")) + '</td>',
                    '<td>' + this.escapeHTML(this.primeiroValor(c.C8_ITEM, c.C8_ITEMSC, "-")) + '</td>',
                    '<td><strong>' + this.escapeHTML(this.formatarMoeda(this.numeroBR(c.C8_TOTAL))) + '</strong></td>',
                    '<td>' + this.escapeHTML(this.formatarDocumento(c.C8_NUMPED || "-")) + '</td>',
                    '</tr>'
                );
            }
            html.push('</tbody></table></div>');
        }

        html.push('</section>');
        return html.join("");
    },

    montarPedidos: function(resumo) {
        var pedidos = resumo.pedidos || [];
        var html = [
            '<section class="tracker-card">',
            '<div class="tracker-section-head"><h4>Pedidos</h4><span>' + (this.documentoValido(resumo.pedido) ? "1" : "0") + '</span></div>'
        ];

        if (!this.documentoValido(resumo.pedido)) {
            html.push(this.emptyInline(resumo.pedidoErro || "Pedido ainda nao gerado."));
        } else {
            html.push('<div class="tracker-order-line"><strong>PED ' + this.escapeHTML(resumo.pedido) + '</strong><span>' + this.escapeHTML(resumo.fornecedor) + '</span><em>' + this.escapeHTML(resumo.menorValor) + '</em></div>');
            if (pedidos.length) {
                html.push('<div class="tracker-muted">' + this.escapeHTML(pedidos.length + " registro(s) retornado(s) pela consulta do pedido.") + '</div>');
            }
        }

        html.push('</section>');
        return html.join("");
    },

    montarAprovacoes: function(resumo) {
        var assinaturas = resumo.assinaturas || [];
        var html = [
            '<section class="tracker-card tracker-approval-card">',
            '<div class="tracker-section-head"><h4>Aprovacoes</h4><span>' + assinaturas.length + '</span></div>'
        ];

        if (!assinaturas.length) {
            html.push(this.emptyInline("Sem alcadas retornadas para o pedido."));
        } else {
            html.push('<ol class="tracker-approval-list">');
            for (var i = 0; i < assinaturas.length; i++) {
                var a = assinaturas[i] || {};
                var aprovado = this.statusAprovado(a.status);
                html.push(
                    '<li class="' + (aprovado ? "is-approved" : "is-waiting") + '">',
                    '<span class="tracker-approval-dot">' + (aprovado ? "&#10003;" : "!") + '</span>',
                    '<div><strong>' + this.escapeHTML(this.primeiroValor(a.nivel, "Nivel " + (i + 1))) + ' - ' + this.escapeHTML(this.primeiroValor(a.usuario, a.nome, "-")) + '</strong>',
                    '<small>' + this.escapeHTML(this.primeiroValor(a.status, a.descricao, "Pendente")) + '</small></div>',
                    '</li>'
                );
            }
            html.push('</ol>');
        }

        html.push('</section>');
        return html.join("");
    },

    montarItens: function(resumo) {
        var itens = resumo.itens || [];
        var html = [
            '<section class="tracker-card">',
            '<div class="tracker-section-head"><h4>Itens da solicitacao</h4><span>' + itens.length + '</span></div>',
            '<div class="tracker-mini-table"><table class="table"><thead><tr><th>Item</th><th>Descricao</th><th>Qtd.</th><th>Total</th></tr></thead><tbody>'
        ];

        for (var i = 0; i < itens.length; i++) {
            var item = itens[i] || {};
            html.push(
                '<tr>',
                '<td>' + this.escapeHTML(this.primeiroValor(item.C1_ITEM, "-")) + '</td>',
                '<td>' + this.escapeHTML(this.primeiroValor(item.C1_DESCRI, item.C1_PRODUTO, "-")) + '</td>',
                '<td>' + this.escapeHTML(this.primeiroValor(item.C1_QUANT, "-")) + '</td>',
                '<td><strong>' + this.escapeHTML(this.formatarMoeda(this.numeroBR(item.C1_TOTAL))) + '</strong></td>',
                '</tr>'
            );
        }

        html.push('</tbody></table></div></section>');
        return html.join("");
    },

    montarResumoFinal: function(resumo) {
        return [
            '<section class="tracker-card">',
            '<div class="tracker-section-head"><h4>Resumo</h4></div>',
            '<dl class="tracker-resume">',
            '<dt>Status da SC</dt><dd>' + this.montarBadge(resumo.status) + '</dd>',
            '<dt>Menor valor encontrado</dt><dd>' + this.escapeHTML(resumo.menorValor || "-") + '</dd>',
            '<dt>Fornecedor sugerido</dt><dd>' + this.escapeHTML(resumo.fornecedor || "-") + '</dd>',
            '<dt>Pedido gerado</dt><dd>' + this.escapeHTML(resumo.pedido || "-") + '</dd>',
            '<dt>Previsao de entrega</dt><dd>A definir</dd>',
            '</dl>',
            resumo.atualizadoEm ? '<div class="tracker-updated">Ultima atualizacao: ' + this.escapeHTML(resumo.atualizadoEm) + '</div>' : '',
            '</section>'
        ].join("");
    },

    montarInfo: function(label, valor) {
        return '<div class="tracker-info"><span>' + this.escapeHTML(label) + '</span><strong>' + this.escapeHTML(valor || "-") + '</strong></div>';
    },

    montarBadge: function(texto) {
        var t = this.primeiroValor(texto, "-");
        var c = "tracker-badge";
        var s = String(t).toLowerCase();

        if (s.indexOf("aprov") >= 0 || s.indexOf("gerad") >= 0 || s.indexOf("liberad") >= 0 || s.indexOf("sucesso") >= 0) c += " is-success";
        else if (s.indexOf("aguard") >= 0 || s.indexOf("pend") >= 0 || s.indexOf("cotacao") >= 0) c += " is-warning";
        else if (s.indexOf("reprov") >= 0 || s.indexOf("erro") >= 0) c += " is-danger";
        else c += " is-info";

        return '<span class="' + c + '">' + this.escapeHTML(t) + '</span>';
    },

    definirStatus: function(row, cotacao, pedido) {
        if (this.documentoValido(pedido)) return "Pedido gerado";
        if (this.documentoValido(cotacao)) return "Cotacao gerada";

        var aprov = String(row.C1_APROV || "").toUpperCase();
        if (aprov === "L") return "Liberada";
        if (aprov === "R") return "Reprovada";
        if (aprov === "B") return "Aguardando cotacao";

        return this.primeiroValor(row.STATUS, "Aguardando acompanhamento");
    },

    encontrarMenorCotacao: function(cotacoes) {
        var menor = null;
        var menorValor = null;

        for (var i = 0; i < cotacoes.length; i++) {
            var atual = cotacoes[i] || {};
            var valor = this.numeroBR(atual.C8_TOTAL);
            if (!valor && valor !== 0) continue;

            if (menor === null || valor < menorValor) {
                menor = atual;
                menorValor = valor;
            }
        }

        return menor;
    },

    extrairAssinaturasPedido: function(pedidos) {
        var assinaturas = [];

        for (var i = 0; i < pedidos.length; i++) {
            var p = pedidos[i] || {};
            var candidatos = [p.ALCADAS, p.alcadas, p.aprovacoes, p.APROVACOES, p.assinaturas, p.ASSINATURAS];

            for (var j = 0; j < candidatos.length; j++) {
                var lista = candidatos[j];
                if (typeof lista === "string") lista = this.parseJsonArray(lista);
                if (lista && lista.length) {
                    for (var k = 0; k < lista.length; k++) {
                        var a = lista[k] || {};
                        assinaturas.push({
                            nivel: this.primeiroValor(a.NIVEL, a.nivel, a.SEQUENCIA, a.sequencia),
                            usuario: this.primeiroValor(a.USUARIO, a.usuario, a.NOME, a.nome, a.APROVADOR, a.aprovador),
                            status: this.primeiroValor(a.STATUS, a.status, a.SITUACAO, a.situacao, a.DESCRICAO, a.descricao)
                        });
                    }
                }
            }
        }

        return assinaturas;
    },

    todasAssinaturasAprovadas: function(assinaturas) {
        for (var i = 0; i < assinaturas.length; i++) {
            if (!this.statusAprovado(assinaturas[i].status)) return false;
        }
        return assinaturas.length > 0;
    },

    statusAprovado: function(status) {
        var s = String(status || "").toLowerCase();
        return s.indexOf("aprov") >= 0 || s === "03" || s.indexOf("liberad") >= 0;
    },

    temSCValida: function(row) {
        return !!(row && this.primeiroValor(row.C1_NUM, row.numero, row.NUMERO));
    },

    documentoValido: function(valor) {
        var v = String(valor || "").replace(/\s/g, "");
        if (!v || v === "-") return false;
        if (/^0+$/.test(v)) return false;
        if (/^x+$/i.test(v)) return false;
        return true;
    },

    parseJsonArray: function(valor) {
        if (!valor) return [];
        if (Object.prototype.toString.call(valor) === "[object Array]") return valor;

        try {
            var parsed = JSON.parse(valor);
            if (Object.prototype.toString.call(parsed) === "[object Array]") return parsed;
            if (parsed && parsed.pedidos) return parsed.pedidos;
            if (parsed && parsed.cotacoes) return parsed.cotacoes;
            if (parsed && parsed.values) return parsed.values;
        } catch (e) {
            return [];
        }

        return [];
    },

    somarCampo: function(rows, campo) {
        var total = 0;
        for (var i = 0; i < rows.length; i++) {
            total += this.numeroBR((rows[i] || {})[campo]);
        }
        return total;
    },

    numeroBR: function(valor) {
        if (typeof valor === "number") return valor;
        var v = String(valor || "").trim();
        if (!v) return 0;

        v = v.replace(/[R$\s]/g, "");
        if (v.indexOf(",") >= 0) v = v.replace(/\./g, "").replace(",", ".");
        var n = parseFloat(v);
        return isNaN(n) ? 0 : n;
    },

    formatarMoeda: function(valor) {
        var n = typeof valor === "number" ? valor : this.numeroBR(valor);
        if (!n && n !== 0) return "-";
        return "R$ " + n.toLocaleString("pt-BR", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
    },

    formatarData: function(valor) {
        var v = String(valor || "").trim();
        if (!v) return "-";
        if (/^\d{8}$/.test(v)) return v.substr(6, 2) + "/" + v.substr(4, 2) + "/" + v.substr(0, 4);
        return v;
    },

    formatarDocumento: function(valor) {
        var v = String(valor || "").trim();
        if (!this.documentoValido(v)) return "-";
        return v;
    },

    montarDataHora: function(data, hora) {
        var d = this.formatarData(data);
        var h = String(hora || "").trim();
        if (d === "-" && !h) return "";
        return h ? d + " " + h : d;
    },

    primeiroValor: function() {
        for (var i = 0; i < arguments.length; i++) {
            var v = arguments[i];
            if (v !== null && v !== undefined && String(v).trim() !== "") return String(v).trim();
        }
        return "";
    },

    normalizarTexto: function(valor) {
        return String(valor || "").trim();
    },

    showMessage: function(texto, tipo) {
        var classe = tipo === "danger" ? "alert-danger" : tipo === "success" ? "alert-success" : "alert-info";
        $("#mensagemSolicitacoes_" + this.instanceId).html('<div class="alert ' + classe + '">' + this.escapeHTML(texto) + '</div>');
    },

    clearMessage: function() {
        $("#mensagemSolicitacoes_" + this.instanceId).empty();
    },

    loadingState: function(texto) {
        return '<div class="tracker-state"><span class="fluigicon fluigicon-refresh"></span>' + this.escapeHTML(texto) + '</div>';
    },

    emptyState: function(texto) {
        return '<div class="tracker-state">' + this.escapeHTML(texto) + '</div>';
    },

    emptyInline: function(texto) {
        return '<div class="tracker-empty-inline">' + this.escapeHTML(texto) + '</div>';
    },

    escapeHTML: function(valor) {
        return String(valor === null || valor === undefined ? "" : valor)
            .replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;")
            .replace(/"/g, "&quot;")
            .replace(/'/g, "&#039;");
    }
});
