/*

OBJETO CHAT 
	
este objeto controla envio, recebimento e exibição de mensagens,
inclusive conexão e desconexão da interface gráfica.
	
Obs: Não criamos a classe pois durante toda a execução do visualizador
existe uma única instância ("singleton") do objeto chat.
	
Não utilizamos a palavra chave "this" pois quando adicionamos um método 
em um evento (addEvent), o javascript não adiciona a referência ao método
do objeto instanciado, mas adiciona a referância ao método da classe 
(método estático).


*/



var chat = {


    CLASSE_CSS_MENSAGEM: "WebCastersChatMensagem", // estilo para o DIV da mensagem

    CLASSE_CSS_MENSAGEM_AUTOR: "WebCastersChatMensagemAutor", // estilo para mensagens do próprio autor
    CLASSE_CSS_MENSAGEM_MODERADOR: "WebCastersChatMensagemModerador", // estilo para mensagens do próprio autor


    CLASSE_CSS_MENSAGEM_NOME: "WebCastersChatMensagemNome", // estilo do texto do nome do autor da mensagem
    CLASSE_CSS_MENSAGEM_DATA: "WebCastersChatMensagemData", // estilo do texto do nome da data da mensagem
    CLASSE_CSS_MENSAGEM_HORA: "WebCastersChatMensagemHora", // estilo do texto do nome da hora da mensagem


    // definição de propriedades

    codTransmissao: 0,
    codUsuario: 0,


    // define se o usuário foi banido ou não
    _banido: false,
    // define se a interface está ativa ou não
    _interfaceAtiva: false,


    // referências dos objetos html
    _listaMensagens: {},
    _entradaMensagem: {},
    _botaoEnviar: {},

    OnDemandAtivado: false,

    // mensagens antigas
    mensagens: "",

    rolagemAutomatica: true,
    atualizando: true,


    // dados da ultima mensagem recebida
    _ultimaMensagem: {
        data: new Date(),
        id: 0
    },


    // atrasa o próximo pedido de atualização (reduzir a quantidade de requisições)
    _updateDelayer: {
        LATE_RESPONSE: 1200, // tempo em ms que indica demora de resposta

        BASE_TIME: 2000, // o tempo mínimo entre requisições
        STEP_TIME: 3000, // quanto o tempo pode aumentar ou reduzir de cada vez
        MAX_TIME: 20000, // o tempo máximo entre requisições

        currentTime: 2000, // o tempo de espera atual
        serverIsSlow: false, // o servidor está lento / ou não

        reset: function () {
            chat._updateDelayer.currentTime = chat._updateDelayer.BASE_TIME;
            trace("chatDelayer: reset to " + chat._updateDelayer.currentTime);
        },

        increase: function () {
            if (chat._updateDelayer.currentTime < chat._updateDelayer.MAX_TIME) {
                chat._updateDelayer.currentTime += chat._updateDelayer.STEP_TIME;
            } else {
                chat._updateDelayer.currentTime = chat._updateDelayer.MAX_TIME;
            }
            trace("chatDelayer: increased to " + chat._updateDelayer.currentTime);

        },
        decrease: function () {
            if (chat._updateDelayer.currentTime > chat._updateDelayer.BASE_TIME) {
                chat._updateDelayer.currentTime -= chat._updateDelayer.STEP_TIME;
            } else {
                chat._updateDelayer.currentTime = chat._updateDelayer.BASE_TIME;
            }
            trace("chatDelayer: decreased to " + chat._updateDelayer.currentTime);
        },
        setToMax: function () {
            if (chat._updateDelayer.currentTime < chat._updateDelayer.MAX_TIME) {
                chat._updateDelayer.currentTime = chat._updateDelayer.MAX_TIME;
            }
            trace("chatDelayer: maxed to " + chat._updateDelayer.currentTime);
        },

        checkDelay: function (t1, t2, newMessage) {
            var dl = t2.getTime() - t1.getTime();

            trace("chatDelayer: response delay " + dl + "ms");

            if (dl > chat._updateDelayer.LATE_RESPONSE || chat._updateDelayer.serverIsSlow) {
                // se deu sinal de lentidão no servidor, ou já se sabe que o servidor está lento
                trace("chatDelayer: slow mode.");
                chat._updateDelayer._checkForSlowResponse(dl, newMessage);
                return;

            }

            // sem sinal de lentidão

            if (newMessage) {
                // se tiver novas mensagens, reseta o tempo entre requisições
                chat._updateDelayer.reset();
            } else {
                // sem novas mensagens, aumenta o tempo
                chat._updateDelayer.increase();
            }



        }, // end check delay

        _checkForSlowResponse: function (dl, newMessage) {

            // controle do tempo de delay /// /// ///
            if (dl > (chat._updateDelayer.LATE_RESPONSE * 2)) {
                // se levou mais que o dobro do indicador de lentidão, vai pro máximo
                chat._updateDelayer.setToMax();

            } else if (dl > chat._updateDelayer.LATE_RESPONSE) {
                // se está acima do limite de lentidão, aumenta
                chat._updateDelayer.increase();

            } else if (!newMessage) {
                // se não veio novas mensagens
                chat._updateDelayer.increase();

            } else {
                // se está abaixo da demora limite e veio mensagens
                chat._updateDelayer.decrease();

            }

            // controle do modo de lentidão /// /// ///
            if (chat._updateDelayer.currentTime <= chat._updateDelayer.BASE_TIME) {
                // se o tempo de espera retornou ao tempo de base, reseta o tempo de espera
                // e sai do modo de lentidão
                chat._updateDelayer.serverIsSlow = false;
                chat._updateDelayer.reset();
                dl = 0;

            } else {
                // o tempo de espera não retornou ao mínimo, o servidor ainda está lento
                // entra ou mantém no modo de lentidão
                chat._updateDelayer.serverIsSlow = true;

            }


            chat._updateDelayer.currentTime = Math.floor(chat._updateDelayer.currentTime);

        }

    },



    iniciarChat: function (CodTransmissao, CodUsuario) {
        chat.codTransmissao = CodTransmissao;
        chat.codUsuario = CodUsuario;

        chat._ultimaMensagem.data.setFullYear(2000, 0, 1);

        chat.atualizarMensagens();

        chat._confereOnDemand();
    },







    ativarInterface: function (lista, entrada, botaoEnviar) {
        // define as referências
        chat._listaMensagens = lista;
        if (chat._listaMensagens) {
            chat._listaMensagens.innerHTML = chat.mensagens;
        }
        chat._entradaMensagem = entrada;
        chat._botaoEnviar = botaoEnviar;



        // adiciona eventos
        if (chat._botaoEnviar) {
            simpleAddEvent(chat._botaoEnviar, 'click', chat.enviarMensagem);
        }

        chat.confereOnDemand();

        chat._interfaceAtiva = true;

        indirectRun(chat._rolarAutomatico);
    },



    desativarInterface: function () {
        chat._interfaceAtiva = false;


        if (chat._botaoEnviar) {
            simpleRemoveEvent(chat._botaoEnviar, 'click', chat.enviarMensagem);
        }

        chat._listaMensagens = {};
        chat._botaoEnviar = {};
        chat._entradaMensagem = {};


    },

    adicionarEntrada: function (msg) {
        // concatena no histórico de mensagens
        chat.mensagens += msg;

        if (!chat._interfaceAtiva || !chat._listaMensagens) {
            return;
        }

        chat.rolagemAutomatica = (chat._listaMensagens.scrollTop == chat._listaMensagens.scrollHeight - chat._listaMensagens.clientHeight);

        if (chat._listaMensagens.clientHeight < chat._listaMensagens.height) {
            chat.rolagemAutomatica = true;
        }

        // adiciona mensagem na interface
        chat._listaMensagens.innerHTML += msg;

        chat._rolarAutomatico();

    },


    _rolarAutomatico: function () {


        // rola para a ultima mensagem
        if (chat.rolagemAutomatica) {
            chat._listaMensagens.scrollTop = chat._listaMensagens.scrollHeight;
        }

    },


    atualizarMensagens: function () {
        // t1 e t2 são para testar a demora da resposta do servidor
        var t1 = new Date();

        var ret = WCAjax.Chat_GetMensagens(visualizador.Usuario.Codigo
		    , chat.codTransmissao
			, chat._ultimaMensagem.id
			, chat._ultimaMensagem.data);

        var t2 = new Date();

        if (visualizador.ajaxErrorCheck(ret) < 1) {
            trace('chat.atualizarMensagens : return ERROR!');

            chat._updateDelayer.setToMax();
            setTimeout(chat.atualizarMensagens, chat._updateDelayer.currentTime);

            return;

        }

        trace('chat.atualizarMensagens : ok');

        var res = verificaSessao(ret);

        if (res == null) {
            trace('erro na requisição de mensagens do chat!');
            // se não veio nada, vai embora
            chat._updateDelayer.setToMax();
            setTimeout(chat.atualizarMensagens, chat._updateDelayer.currentTime);
            return;
        }


        if (chat._listaMensagens) {
            // pass;
        } else {
            // se a área não existir
            chat._updateDelayer.setToMax();
            chat.rolagemAutomatica = false;

        }


        // pega o código da mensagem mais atual
        var i;
        for (i = 0; i < res.rows.length; i++) {
            var men = res.rows[i];

            // atualizar o código e a data da mensagem mais recente
            if (chat._ultimaMensagem.id < men.Codigo) {
                chat._ultimaMensagem.id = men.Codigo;
            }

            if (chat._ultimaMensagem.data.getTime() < men.Data.getTime()) {
                chat._ultimaMensagem.data = men.Data;
            }

            var sb = new StringBuilder();
            sb.append("<div class='" + chat.CLASSE_CSS_MENSAGEM);

            // adiciona a mensagem na lista
            if (men.CodUsuario == chat.codUsuario) {
                sb.append(" " + chat.CLASSE_CSS_MENSAGEM_AUTOR);

            }
            else if (men.CodUsuarioDestino == chat.codUsuario) {
                sb.append(" " + chat.CLASSE_CSS_MENSAGEM_MODERADOR);
            }

            sb.append("'>");

            sb.append("<span class=" + chat.CLASSE_CSS_MENSAGEM_DATA + ">" + chat._dateToString(men.Data) + "</span>");
            sb.append("<span class=" + chat.CLASSE_CSS_MENSAGEM_HORA + ">" + chat._hourToString(men.Data) + "</span> ");
            sb.append("<span class=" + chat.CLASSE_CSS_MENSAGEM_NOME + ">" + men.NomeOrigem + ":</span> ");
            sb.append(men.Mensagem.stripTags());


            sb.append("</div>");

            chat.adicionarEntrada(sb.toString());

        } // end for


        chat._updateDelayer.checkDelay(t1, t2, i > 0);

        // para atualizar novamente
        if (visualizador.Transmissao.AoVivo || chat.OnDemandAtivado) {
            setTimeout(chat.atualizarMensagens, chat._updateDelayer.currentTime);
            atualizando = true;
        }

        atualizando = false;

    }, // end method




    enviarMensagem: function () {
        if (!chat._interfaceAtiva || !chat._entradaMensagem) {
            trace('chat.enviarMensagem : no interface!');
            return;
        }

        if (chat._entradaMensagem.value.trim() == "") {
            return;
        }

        var res = WCAjax.Chat_AddMensagem(visualizador.Usuario.Codigo
		    , chat.codTransmissao
			, chat._entradaMensagem.value.htmlEncode());

        if (visualizador.ajaxErrorCheck(res) < 1) {
            trace('chat.enviarMensagem : return ERROR!');
            return;

        }

        var enviado = verificaSessao(res);

        chat.eco(chat._entradaMensagem.value.htmlEncode());

        chat._entradaMensagem.value = '';



        if (!enviado) {
            var d = new Date();
            chat.adicionarEntrada("<div class=" + chat.CLASSE_CSS_MENSAGEM + "><span class=" + chat.CLASSE_CSS_MENSAGEM_MODERADOR + ">"
					+ chat._dateToString(d)
					+ " <span class=" + chat.CLASSE_CSS_MENSAGEM_NOME + ">Moderador:</span> Voc&ecirc; foi banido do chat por enviar mensagens impr&oacute;prias.</span></div>");
        }

    },



    // só ecoa a mensagem quando for moderado
    eco: function (mensagem) {
        if (visualizador.Transmissao.TipoChat != 2) {
            // não é moderado
            return;

        }

        var sb = new StringBuilder();
        sb.append("<div class='" + chat.CLASSE_CSS_MENSAGEM + " " + chat.CLASSE_CSS_MENSAGEM_AUTOR + "'>");

        var d = new Date();

        sb.append("<span class=" + chat.CLASSE_CSS_MENSAGEM_DATA + ">" + chat._dateToString(d) + "</span>");
        sb.append("<span class=" + chat.CLASSE_CSS_MENSAGEM_HORA + ">" + chat._hourToString(d) + "</span> ");
        sb.append("Mensagem enviada ao moderador: ");
        sb.append(mensagem);
        sb.append("</div>");

        chat.adicionarEntrada(sb.toString());
    },




    // confere local
    confereOnDemand: function () {
        var desativado = (chat.OnDemandAtivado == false);

        if (template.ChatOdDisponivel == false) {
            trace("chat.confereOnDemand - template.chatod indisponivel.");
            return;
        }

        // está altornando o modo?
        if (desativado == chat._botaoEnviar.disabled) {
            return; // não
        }

        trace("chat.confereOnDemand - alternando modo.");


        if (desativado) {
            // está desativando
            chat._entradaMensagem.value = 'O envio de mensagens está desabilitado.';
        } else {
            // está ativando
            chat._entradaMensagem.value = '';

            // se parou de atualizar, volta
            if (atualizando == false) {
                chat.atualizarMensagens();
            }

        }

        chat._botaoEnviar.disabled = desativado;
        chat._entradaMensagem.disabled = desativado;

        chat._botaoEnviar.style.display = desativado ? 'none' : '';

    },

    // confere no servidor
    _confereOnDemand: function () {
        if (visualizador.Transmissao.AoVivo) {
            trace("chat._confereOnDemand - a transmissão é ao vivo.");
            return;
        }

        WCAjax.Transmissao_VerificaChatOnDemand(chat.codTransmissao,
            chat._confereOnDemand_Callback);

    },

    _confereOnDemand_Callback: function (res) {

        if (visualizador.ajaxErrorCheck(res) < 1) {
            trace('chat._confereOnDemand_Callback : return ERROR!');

        } else if (res.value != chat.OnDemandAtivado) {
            chat.OnDemandAtivado = res.value;
            chat.confereOnDemand(res.value);

        }

        setTimeout(chat._confereOnDemand, 7000);

    },




    _hourToString: function (d) {
        var sb = new StringBuilder();

        sb.append("(");
        sb.append(d.getHours() > 9 ? d.getHours() : '0' + d.getHours());
        sb.append(":");
        sb.append(d.getMinutes() > 9 ? d.getMinutes() : '0' + d.getMinutes());
        sb.append(":");
        sb.append(d.getSeconds() > 9 ? d.getSeconds() : '0' + d.getSeconds());
        sb.append(")");

        return sb.toString();
    },

    _dateToString: function (d) {
        var sb = new StringBuilder();

        sb.append("(");
        sb.append(d.getDate() > 9 ? d.getDate() : '0' + d.getDate());
        sb.append("/");
        var m = d.getMonth() + 1;
        sb.append(m > 9 ? m : '0' + m);
        sb.append("/");
        sb.append(d.getFullYear());
        sb.append(")");

        return sb.toString();
    }



};                 // end chat






