<?php
/**
 * Classe para montar o arquivo XML com as revendas e veiculos
 * Mais informacoes no site http://www.guiarevendas.com.br/xml/
 *
 * @author Leandro Pierin
 * @created 2010-11-13 19:00
 * @modified 2011-12-21 16:45
 * @version 1.7
  */
class GuiaRevendas {

    /**
     * Versao da classe
     * @var string
     */
    private $Version = '1.7';
    /**
     * Habilita/Desabilita o debug da classe
     * @var bool
     */
    private $Debug = false;
    /**
     * Lista as extensoes necessarios pela classe
     * @var array Nomes das classes
     */
    private $ExtReq = array("dom", "libxml");
    /**
     * Variavel de checagem se as extensoes necessarias estao carregadas
     * @var bool
     */
    private $CheckExt;
    /**
     * Mensagens de erro caso alguma variavel requerida nao seja informada
     * @var array
     */
    private $ERRO = array();
    /**
     * Chave privada informada ao carregar a classe
     * @var <type>
     */
    private $CHAVE_PRI;
    /**
     * Variavel com Id da revenda
     * @var integer
     */
    private $RevID;
    /**
     * Variavel com a chave publica informada para checagem
     * @var string
     */
    private $CHAVE_PUB;
    /**
     * Variavel com o objeto do documento XML
     * @var object
     */
    private $XML;
    /**
     * Elementos do objeto XML ******
     * @var object
     */
    private $ElemtRaiz;
    /**
     * Elementos do objeto XML *******
     * @var object
     */
    private $ElemtReg;
    /**
     * Quantia de registros do elemento ******
     * @var integer
     */
    private $NumRegistros;
    /**
     * Tipo de arquivo XML (Carros | Revendas | Veiculos)
     * @var <type>
     */
    private $TipoXML;
    /**
     * Tipo de charset do XML 
     * @var string ISO-8859-1 ou UTF-8
     */
    private $Charset = 'UTF-8';


     /**
     * Carrega informacoes basicas e verifica valores requeridos.
     *
     * @author Leandro Pierin (GuiaRevendas.com.br)
     * @version 1.0
     * @param string $ChavePrivada Chave privada para validar acesso
     * @param string $ChavePublica Chave publica para acesso as informacoes
     */
    function __construct($ChavePrivada, $ChavePublica, $Charset='UTF-8'){
        $this->CheckExt = $this->CheckExtensions();
        if($Charset <> "") $this->Charset = strtoupper($Charset);
        if($this->CheckExt){
            if($this->Debug) echo 'Recebendo ChavePrivada: <b>'.$ChavePrivada.'</b><br />';
            $this->CHAVE_PRI = $ChavePrivada;
            if($this->Debug) echo 'Recebendo ChavePublica: <b>'.$ChavePublica.'</b><br />';
            $this->CHAVE_PUB = $ChavePublica;
        } else {
            $this->PrintErro();
            return false;
        }
    }

    /**
     * Monta o XML dos carros e imprime
     *
     * @author Leandro Pierin
     * @version 1.0
     * @param array $Carros Informacoes dos carros como Id, Marca, Modelo, Ano, Valor e Link
     * @param integer $RevID Id da revenda na base de dados
     * @return xml
     */
    public function MakeXML_Carro($Carros, $RevID){
        $this->SetTipoXML("Carros");
        //
        if($this->Debug) echo 'Recebendo RevID: <b>'.$RevID.'</b><br />';
        $this->RevID = $RevID;
        //
        if($this->CheckExt and $this->CheckVariables()){
            if($this->Debug) echo 'Criando XML...<br />';
            $this->NumRegistros = count($Carros);
            //
            $this->CreateHeaderXML();
            //
            $this->CreateElemRaiz();
            foreach($Carros as $Row){
                $this->CreateCarro($Row);
            }
            //
            // Imprime os dados do XML criado...
            echo $this->XML->saveXML();
            //
        } else {
            $this->PrintErro();
        }
    }

    /**
     * Monta o XML dos veiculos e imprime
     *
     * @author Leandro Pierin
     * @version 1.0
     * @param array $Veiculos Informacoes dos veiculos como Id, Marca, Modelo, Ano, Valor e Link
     * @param integer $RevID Id da revenda na base de dados
     * @return xml
     */
    public function MakeXML_Veiculo($Veiculos, $RevID){
        $this->SetTipoXML("Veiculos");
        //
        if($this->Debug) echo 'Recebendo RevID: <b>'.$RevID.'</b><br />';
        $this->RevID = $RevID;
        //
        if($this->CheckExt and $this->CheckVariables()){
            if($this->Debug) echo 'Criando XML...<br />';
            $this->NumRegistros = count($Veiculos);
            //
            $this->CreateHeaderXML();
            //
            $this->CreateElemRaiz();
            foreach($Veiculos as $Row){
                $this->CreateVeiculo($Row);
            }
            //
            // Imprime os dados do XML criado...
            echo $this->XML->saveXML();
            //
        } else {
            $this->PrintErro();
        }
    }

    /**
     * Monta o XML das revendas e imprime
     *
     * @author Leandro Pierin
     * @version 1.0
     * @param array $Revendas Informacoes das revendas como Id, Nome, Logradouro, Numero, Complemento, Bairro, Cidade, Estado, Fone e Link
     * @return xml
     */
    public function MakeXML_Revenda($Revendas){
        $this->SetTipoXML("Revendas");
        //
        if($this->CheckExt and $this->CheckVariables()){
            if($this->Debug) echo 'Criando XML...<br />';
            $this->NumRegistros = count($Revendas);
            //
            $this->CreateHeaderXML();
            //
            $this->CreateElemRaiz();
            foreach($Revendas as $Row){
                $this->CreateRevenda($Row);
            }
            //
            // Imprime os dados do XML criado...
            echo $this->XML->saveXML();
            //
        } else {
            $this->PrintErro();
        }
    }

    private function PrintErro(){
        //
        $this->CreateHeaderXML();
        //
        // Cria elemento raiz "Revenda"...
        $this->ElemtRaiz = $this->XML->createElement("Erros");
        //
        $this->SetAttrRaiz("Data", date("Y-m-d"));
        $this->SetAttrRaiz("Hora", date("H:i:s"));
        //
        // Aplica os atributos ao elemento criado...
        $this->XML->appendChild($this->ElemtRaiz);
        //
        // Cria elemento "Erro"...
        $this->ElemtReg = $this->XML->createElement("Erro");
        //
        // Cria os elementos com seus valores...
        $Elem = $this->XML->createElement("Codigo");
        $Elem->appendChild($this->XML->createTextNode($this->ERRO['Codigo']));
        $this->ElemtReg->appendChild($Elem);
        //
        $Elem = $this->XML->createElement("Mensagem");
        $Elem->appendChild($this->XML->createCDATASection($this->ERRO['Mensagem']));
        $this->ElemtReg->appendChild($Elem);
        //
	// Junta os registros dos Carros ao elemento raiz Revenda...
	$this->ElemtRaiz->appendChild($this->ElemtReg);
        //
        // Imprime os dados do XML criado...
        die($this->XML->saveXML());
        //
    }

    /**
     * Cria o cabecalho do XML com header do PHP informando o tipo de arquivo de saida como a tag <xml ...>
     */
    private function CreateHeaderXML(){
        //
        // Determina o tipo de conteudo para XML para que o browser entenda como XML...
        if(!$this->Debug) header('Content-Type:text/xml; charset="utf-8"', true);
        //
        // Cria o documento XML...
        $this->XML = new DOMDocument('1.0', 'utf-8');
        $this->XML->formatOutput = true;
        $this->XML->appendChild($this->XML->createComment(" XML gerado pela classe GuiaRevendas - Versao: ".$this->Version." "));
        //- Charset IN: ".$this->Charset." - Charset OUT: UTF-8
    }

    /**
     * Seta o tipo de XML
     * @param string $Tipo Tipo de XML (Carros | Revendas | Veiculos)
     */
    private function SetTipoXML($Tipo){
        $this->TipoXML = $Tipo;
    }

    /**
     * Pega o valor do tipo de XML
     * @return string
     */
    private function GetTipoXML(){
        return $this->TipoXML;
    }

    /**
     * Verifica se as extensoes necessarias estao carregadas no servidor conforme variavel $ExtReq
     * @return bool
     */
    private function CheckExtensions(){
        if($this->Debug) echo 'Verificando extensoes... <br />';
        $ExtLoad = get_loaded_extensions();
        $nExtReq = count($this->ExtReq);
        $nExtOK = 0;
        $msgExtERRO = '';
        for($i=0; $i<$nExtReq; $i++){
            if($this->Debug) echo 'Verificando extensao <b>'.$this->ExtReq[$i].'</b>...';
            if(in_array($this->ExtReq[$i], $ExtLoad)){
                if($this->Debug) echo '... encontrada! <br />';
                $nExtOK++;
            } else {
                if($this->Debug) echo '... NAO encontrada! <br />';
                $msgExtERRO .= 'GuiaRevendas necessita da extensao PHP <b>'.$this->ExtReq[$i].'</b>. <br />';
            }// Fecha in_array
        }// Fecha for
        if($nExtReq <> $nExtOK){
            if($this->Debug) echo 'Ops! Extensao PHP requerida nao encontrada! <br />';
            #echo $msgExtERRO;
            $this->ERRO['Codigo'] = 1;
            $this->ERRO['Mensagem'] = $msgExtERRO;
            return false;
        } else {
            return true;
        }
    }// Fecha function

    /**
     * Verifica se as variaveis requeridas foram informadas ($ChavePrivada, $RevID, $ChavePublica)
     * @return bool
     */
    private function CheckVariables(){
        if($this->Debug) echo 'Verificando variaveis... <br />';
        # Tornando o uso de chave privada, opcional...
        #if($this->CHAVE_PRI == ""){
        #    $Erro = 'Variavel <b>CHAVE_PRIVADA</b>... NAO informada!<br />';
        #    if($this->Debug) echo $Erro;
        #    $this->ERRO['Codigo'] = 2;
        #    $this->ERRO['Mensagem'] = $Erro;
        #    return false;
        #}
        if($this->RevID == "" and $this->GetTipoXML() == "Carros"){
            $Erro = 'Variavel <b>RevID</b>... NAO informada!<br />';
            if($this->Debug) echo $Erro;
            $this->ERRO['Codigo'] = 3;
            $this->ERRO['Mensagem'] = $Erro;
            return false;
        }
        if($this->RevID == "" and $this->GetTipoXML() == "Veiculos"){
            $Erro = 'Variavel <b>RevID</b>... NAO informada!<br />';
            if($this->Debug) echo $Erro;
            $this->ERRO['Codigo'] = 3;
            $this->ERRO['Mensagem'] = $Erro;
            return false;
        }
        if($this->CHAVE_PUB == ""){
            $Erro = 'Variavel <b>CHAVE_PUBLICA</b>... NAO informada!<br />';
            if($this->Debug) echo $Erro;
            $this->ERRO['Codigo'] = 4;
            $this->ERRO['Mensagem'] = $Erro;
            return false;
        }
        # Ajuste feito depois de tornar a chave privada opcional...
        if($this->CHAVE_PRI <> "" and ($this->CHAVE_PUB <> $this->MakeChavePub())){
            $Erro = 'Variavel <b>CHAVE_PUBLICA</b>... INVALIDA!<br />';
            if($this->Debug) echo $Erro;
            $this->ERRO['Codigo'] = 5;
            $this->ERRO['Mensagem'] = $Erro;
            return false;
        }
        return true;
    }

    /**
     * Cria a chave publica com base da chave privada, data e Id da revenda
     * @return string Chave publica para verificacao com a chave informada
     */
    private function MakeChavePub(){
        if($this->GetTipoXML() == "Carros"){
            $CHAVE = strtoupper(md5(date("Ymd").$this->RevID.$this->CHAVE_PRI));
        } elseif($this->GetTipoXML() == "Veiculos"){
            $CHAVE = strtoupper(md5(date("Ymd").$this->RevID.$this->CHAVE_PRI));
        } elseif($this->GetTipoXML() == "Revendas"){
            $CHAVE = strtoupper(md5(date("Ymd").$this->CHAVE_PRI));
        }
        if($this->Debug) echo 'CHAVE_PUBLICA: <b>'.$CHAVE.'</b><br />';
        return $CHAVE;
    }

    /**
     * Cria o elemento raiz Revenda e aplica os atributos com seus valores
     */
    private function CreateElemRaiz(){
        $Tipo = $this->GetTipoXML();
        //
        // Cria elemento raiz "Revenda"...
        $this->ElemtRaiz = $this->XML->createElement($Tipo);
        //
        // Aplica os atributos ao elemento raiz "Revenda"...
        if($Tipo == "Carros"){
            $this->SetAttrRaiz("RevendaID", $this->RevID);
        }
        $this->SetAttrRaiz("Registros", $this->NumRegistros);
        $this->SetAttrRaiz("Data", date("Y-m-d"));
        $this->SetAttrRaiz("Hora", date("H:i:s"));
        //
        // Atributos de validacao do XML ( XSD )...
        $this->SetAttrRaiz("xmlns:gr", "http://www.w3.org/2001/XMLSchema-instance");
        if($Tipo == "Carros"){
            $this->SetAttrRaiz("gr:noNamespaceSchemaLocation", "http://www.guiarevendas.com.br/xml/carros.xsd");
        } elseif($Tipo == "Veiculos"){
            $this->SetAttrRaiz("gr:noNamespaceSchemaLocation", "http://www.guiarevendas.com.br/xml/veiculos.xsd");
        } elseif($Tipo == "Revendas"){
            $this->SetAttrRaiz("gr:noNamespaceSchemaLocation", "http://www.guiarevendas.com.br/xml/revendas.xsd");
        }
        //
        // Aplica os atributos ao elemento criado...
        $this->XML->appendChild($this->ElemtRaiz);
    }

    /**
     * Seta atributos ao elemento Revenda
     * @param string $Atributo Nome do atributo
     * @param string $Valor Valor do atributo
     */
    private function SetAttrRaiz($Atributo, $Valor){
        $this->ElemtRaiz->appendChild($this->XML->createAttribute($Atributo));
        $this->ElemtRaiz->setAttribute($Atributo, $Valor);
    }

    /**
     * Cria o elemento Carro com suas informacoes
     * @param array $Carro Informacoes do carro como Id, Marca, Modelo, Ano, Valor e Link
     */
    private function CreateCarro($Carro){
        //
        // Cria elemento "Carro"...
        $this->ElemtReg = $this->XML->createElement("Carro");
        //
        // Aplica os atributos ao elemento raiz "Revenda"...
        $this->SetAttrReg("Id", $Carro['Id']);
        //
        // Se os dados estiverem no Charset ISO-8859-1, converte para UTF-8...
        $Marca   = $this->TrataCharset($Carro['Marca']);
        $Modelo  = $this->TrataCharset($Carro['Modelo']);
        $Ano     = $this->TrataCharset($Carro['Ano']);
        $Valor   = $this->TrataCharset($Carro['Valor']);
        $Link    = $this->TrataCharset($Carro['Link']);
        //
        // Cria os elementos com seus valores...
        $this->SetElemReg("Marca",  $Marca);
        $this->SetElemReg("Modelo", $Modelo);
        $this->SetElemReg("Ano",    $Ano);
        $this->SetElemReg("Valor",  $Valor);
        $this->SetElemReg("Link",   $Link);
        //
	// Junta os registros dos Carros ao elemento raiz Revenda...
	$this->ElemtRaiz->appendChild($this->ElemtReg);
	//
    }

    /**
     * Cria o elemento Veiculo com suas informacoes
     * @param array $Veiculo Informacoes do veiculo como Id, Marca, Modelo, Ano, Valor e Link
     */
    private function CreateVeiculo($Veiculo){
        //
        // Cria elemento "Veiculo"...
        $this->ElemtReg = $this->XML->createElement("Veiculo");
        //
        // Aplica os atributos ao elemento raiz "Revenda"...
        $this->SetAttrReg("Id", $Veiculo['Id']);
        //
        // Se os dados estiverem no Charset ISO-8859-1, converte para UTF-8...
        $Marca   = $this->TrataCharset($Veiculo['Marca']);
        $Modelo  = $this->TrataCharset($Veiculo['Modelo']);
        $Ano     = $this->TrataCharset($Veiculo['Ano']);
        $Valor   = $this->TrataCharset($Veiculo['Valor']);
        $Link    = $this->TrataCharset($Veiculo['Link']);
        //
        // Cria os elementos com seus valores...
        $this->SetElemReg("Marca",  $Marca);
        $this->SetElemReg("Modelo", $Modelo);
        $this->SetElemReg("Ano",    $Ano);
        $this->SetElemReg("Valor",  $Valor);
        $this->SetElemReg("Link",   $Link);
        //
	// Junta os registros dos Veiculos ao elemento raiz Revenda...
	$this->ElemtRaiz->appendChild($this->ElemtReg);
	//
    }

    /**
     * Cria o elemento Revenda com suas informacoes
     * @param array $Revenda Informacoes da Revenda como Id, Nome, Logradouro, Numero, Complemento, Bairro, Cidade, Estado, Fone e Link
     */
    private function CreateRevenda($Revenda){
        //
        // Cria elemento "Revenda"...
        $this->ElemtReg = $this->XML->createElement("Revenda");
        //
        // Verifica o charset do nome...
        #$CharsetDetect = '';
        #if(mb_check_encoding($Revenda['Nome'], 'ISO-8859-1')) $CharsetDetect .= 'ISO-8859-1 ';
        #if(mb_check_encoding($Revenda['Nome'], 'UTF-8')) $CharsetDetect .= 'UTF-8 ';
        #$this->ElemtReg->appendChild($this->XML->createComment(" CharsetDetect: ".$CharsetDetect." "));
        //
        // Aplica os atributos ao elemento raiz "Revenda"...
        $this->SetAttrReg("Id", $Revenda['Id']);
        //
        // Se os dados estiverem no Charset ISO-8859-1, converte para UTF-8...
        /* if($this->Charset == 'ISO-8859-1'){
            $Nome           = utf8_encode($Revenda['Nome']);
            $Logradouro     = utf8_encode($Revenda['Logradouro']);
            $Numero         = utf8_encode($Revenda['Numero']);
            $Complemento    = utf8_encode($Revenda['Complemento']);
            $Bairro         = utf8_encode($Revenda['Bairro']);
            $Cidade         = utf8_encode($Revenda['Cidade']);
            $Estado         = utf8_encode($Revenda['Estado']);
            $Fone           = utf8_encode($Revenda['Fone']);
            $Email          = utf8_encode($Revenda['Email']);
            $Site           = utf8_encode($Revenda['Site']);
        } else {//*/
            $Nome           = $this->TrataCharset($Revenda['Nome']);
            $Logradouro     = $this->TrataCharset($Revenda['Logradouro']);
            $Numero         = $this->TrataCharset($Revenda['Numero']);
            $Complemento    = $this->TrataCharset($Revenda['Complemento']);
            $Bairro         = $this->TrataCharset($Revenda['Bairro']);
            $Cidade         = $this->TrataCharset($Revenda['Cidade']);
            $Estado         = $this->TrataCharset($Revenda['Estado']);
            $Fone           = $this->TrataCharset($Revenda['Fone']);
            $Email          = $this->TrataCharset($Revenda['Email']);
            $Site           = $this->TrataCharset($Revenda['Site']);
        //}
        //
        // Cria os elementos com seus valores...
        $this->SetElemReg("Nome",           $Nome);
        $this->SetElemReg("Logradouro",     $Logradouro);
        $this->SetElemReg("Numero",         $Numero);
        $this->SetElemReg("Complemento",    $Complemento);
        $this->SetElemReg("Bairro",         $Bairro);
        $this->SetElemReg("Cidade",         $Cidade);
        $this->SetElemReg("Estado",         $Estado);
        $this->SetElemReg("Fone",           $Fone);
        $this->SetElemReg("Email",          $Email);
        $this->SetElemReg("Site",           $Site);
        //
	// Junta os registros das Revendas ao elemento raiz Revenda...
	$this->ElemtRaiz->appendChild($this->ElemtReg);
	//
    }

    
    /**
     * Verifica e trata valor para UTF-8
     * @param string $Valor Valor a ser tratado
     */
    private function TrataCharset($Valor){
        #return mb_convert_encoding($Valor, "UTF-8", mb_detect_encoding($Valor, "UTF-8, ISO-8859-1, ISO-8859-15", true));
        
        if(!mb_check_encoding($Valor, 'UTF-8')){
            if(mb_check_encoding($Valor, 'ISO-8859-1')){
                return utf8_encode($Valor);
            } else {
                return iconv("CP850", "UTF-8//TRANSLIT", $Valor);//mb_convert_encoding($Valor, 'UTF-8', 'ISO-8859-15');
            }
        } else {
            return $Valor;
        }//*/
    }
    
    /**
     * Seta atributos ao elemento
     * @param string $Atributo Nome do atributo
     * @param string $Valor Valor do atributo
     */
    private function SetAttrReg($Atributo, $Valor){
        $this->ElemtReg->appendChild($this->XML->createAttribute($Atributo));
        $this->ElemtReg->setAttribute($Atributo, $Valor);
    }

    /**
     * Cria o elemento com seu valor 
     * @param string $Elemento Nome do elemento
     * @param string $Valor Valor do elemento
     */
    private function SetElemReg($Elemento, $Valor){
        $E = $this->XML->createElement($Elemento);
        //$E->appendChild($this->XML->createTextNode($Valor));
        $E->appendChild($this->XML->createCDATASection($Valor));
        $this->ElemtReg->appendChild($E);
    }

}// Fecha classe
?>