<?php 
    ##########################################################################
    ##########################################################################
    //VERIFICA SEGURIDAD: Perfil de Administrador requerido antes de continuar
    global $PCOSESS_LoginUsuario,$MULTILANG_ErrorTitAuth,$MULTILANG_WSErr06;
    if (!PCO_EsAdministrador(@$PCOSESS_LoginUsuario))
        {
            PCO_Mensaje("{$MULTILANG_ErrorTitAuth}", "{$MULTILANG_WSErr06}", '', 'fa fa-exclamation-triangle fa-3x texto-rojo texto-blink', 'alert alert-warning alert-dismissible');
            PCO_Auditar("$PCOSESS_LoginUsuario Intenta acceso no autorizado Frm:-35","SECLog:event");
            die();
        }
    ##########################################################################
    ##########################################################################

    /*
    	Function: PCO_CargarObjeto_VisorDeDiferencias
    	Carga el elemento interno (Formulario -35) asociado al visor de diferencias
    	
        Variables de entrada basicas del Framework:
            URL - index.php?PCO_Accion=PCO_CargarObjeto&PCO_Objeto=frm:-35:0&Presentar_FullScreen=1&Precarga_EstilosBS=1
        
        Variables de entrada especificas para el elemento:
            PDIFF_Version1 - Ruta al elemento que representa la version 1 del documento o codigo
            PDIFF_Version2 - Ruta al elemento que representa la version 2 del documento o codigo
            PDIFF_OrigenVersion1 - Tipo de origen (A=Archivo B=BaseDatos)
            PDIFF_OrigenVersion2 - Tipo de origen (A=Archivo B=BaseDatos)
            PDIFF_TablaBDVersion1 - Para Origenes de version tipo B indica ubicacion en el motor
            PDIFF_CampoBDVersion1 - Para Origenes de version tipo B indica ubicacion en el motor
            PDIFF_LlaveBDVersion1 - Para Origenes de version tipo B indica ubicacion en el motor
            PDIFF_TablaBDVersion2 - Para Origenes de version tipo B indica ubicacion en el motor
            PDIFF_CampoBDVersion2 - Para Origenes de version tipo B indica ubicacion en el motor
            PDIFF_LlaveBDVersion2 - Para Origenes de version tipo B indica ubicacion en el motor

    	Salida:
    	    Comparacion de ambas cadenas formateada en HTML
    */

	global $PDIFF_Version1,$PDIFF_Version2,$PDIFF_OrigenVersion1,$PDIFF_OrigenVersion2;
	global $PDIFF_TablaBDVersion1,$PDIFF_CampoBDVersion1,$PDIFF_LlaveBDVersion1,$PDIFF_TablaBDVersion2,$PDIFF_CampoBDVersion2,$PDIFF_LlaveBDVersion2;
	global $Presentar_FullScreen,$Precarga_EstilosBS;

	//PARAMETROS BASICOS DE CONFIGURACION
	$URLRecarga="&PCO_Accion=PCO_CargarObjeto&PCO_Objeto=frm:-35:0&Presentar_FullScreen={$Presentar_FullScreen}&Precarga_EstilosBS={$Precarga_EstilosBS}&PDIFF_Version1={$PDIFF_Version1}&PDIFF_Version2={$PDIFF_Version2}&PDIFF_OrigenVersion1={$PDIFF_OrigenVersion1}&PDIFF_OrigenVersion2={$PDIFF_OrigenVersion2}";

    //VARIABLES DE BANCO DE PRUEBAS - Deberian estar siempre comentadas para produccion
    // ARCHIVOS:
        //$PDIFF_Version1="index.php";
        //$PDIFF_Version2="index.php";
        //$PDIFF_Version2="tmp/index2.php";

    // BASEDATOS:
        //$PDIFF_OrigenVersion2="B";
        //$PDIFF_CampoBDVersion2="contenido";
        //$PDIFF_TablaBDVersion2="core_pcoder_historial";
        //$PDIFF_LlaveBDVersion2="10";
    
        //$PDIFF_OrigenVersion1="B";
        //$PDIFF_CampoBDVersion1="contenido";
        //$PDIFF_TablaBDVersion1="core_pcoder_historial";
        //$PDIFF_LlaveBDVersion1="34";

################################################################################
################################################################################
    class BuscadorDiferencias
        {
        	var $error = '';
            ////////////////////////////////////////////////////////////////////
            ////////////////////////////////////////////////////////////////////
        	function SepararCadena($Cadena, $Separador, $Fin, &$positions)
            	{
            		$l = strlen($Cadena);
            		$split = array();
            		for($p = 0; $p < $l;)
            		{
            			$e = strcspn($Cadena, $Separador.$Fin, $p);
            			$e += strspn($Cadena, $Separador, $p + $e);
            			$split[] = substr($Cadena, $p, $e);
            			$positions[] = $p;
            			$p += $e;
            			if(strlen($Fin)
            			&& ($e = strspn($Cadena, $Fin, $p)))
            			{
            				$split[] = substr($Cadena, $p, $e);
            				$positions[] = $p;
            				$p += $e;
            			}
            		}
            		$positions[] = $p;
            		return $split;
            	}
        

            ////////////////////////////////////////////////////////////////////
            ////////////////////////////////////////////////////////////////////
        	function Diff($before, $after, &$difference)
            	{
            		$for_patch = (IsSet($difference->patch) && $difference->patch);

    				$before = $this->SepararCadena($before, "\r\n", '', $posb);
    				$lb = count($before);
    				$after = $this->SepararCadena($after, "\r\n", '', $posa);
    				$la = count($after);

            		$diff = array();
            		for($b = $a = 0; $b < $lb && $a < $la;)
            		{
            			for($pb = $b; $a < $la && $pb < $lb && $after[$a] === $before[$pb]; ++$a, ++$pb);
            			if($pb !== $b)
            			{
            				$diff[] = array(
            					'change'=>'=',
            					'position'=>$posb[$b],
            					'length'=>$posb[$pb] - $posb[$b]
            				);
            				$b = $pb;
            			}
            			if($b === $lb)
            				break;
            			for($pb = $b; $pb < $lb; ++$pb)
            			{
            				for($pa = $a ; $pa < $la && $after[$pa] !== $before[$pb]; ++$pa);
            				if($pa !== $la)
            					break;
            			}
            			if($pb !== $b)
            			{
            				$diff[] = array(
            					'change'=>'-',
            					'position'=>$posb[$b],
            					'length'=>$posb[$pb] - $posb[$b]
            				);
            				$b = $pb;
            			}
            			if($pa !== $a)
            			{
            				$position = $posa[$a];
            				$length = $posa[$pa] - $posa[$a];
            				$change = array(
            					'change'=>'+',
            					'position'=>$position,
            					'length'=>$length
            				);
            				if($for_patch)
            				{
        						$patch = $after[$a];
        						for(++$a; $a < $pa; ++$a)
        							$patch .= $after[$a];
            							
            					$change['patch'] = $patch;
            				}
            				$diff[] = $change;
            				$a = $pa;
            			}
            		}
            		if($a < $la)
            		{
            			$position = $posa[$a];
            			$length = $posa[$la] - $posa[$a];
            			$change = array(
            				'change'=>'+',
            				'position'=>$position,
            				'length'=>$length
            			);
            			if($for_patch)
            			{
            					$patch = $after[$a];
            					for(++$a; $a < $la; ++$a)
            						$patch .= $after[$a];

            				$change['patch'] = $patch;
            			}
            			$diff[] = $change;
            		}
            		$difference->difference = $diff;
            		return true;
            	}


            ////////////////////////////////////////////////////////////////////
            ////////////////////////////////////////////////////////////////////
        	function FormatearEnHTML($before, $after, &$difference)
            	{
            		if(!$this->diff($before, $after, $difference))
            		{
            			return false;
            		}
            		$html = '';
            		$td = count($difference->difference);
            		for($d = 0; $d < $td; ++$d)
            		{
            			$diff = $difference->difference[$d];
            			
            			//Define los elementos indicadores que van al lado izquierdo solo despues de la primera interaccion
            			//if ($d>=1)
            			    {
                    			$IndicadorNormal ="<div class='btn btn-xs btn-default' data-toggle='tooltip' data-placement='bottom' data-html='true' title='Interacción <font color=yellow><b>#{$d}</b></font><br>Conservar' style='margin-left:-30px !important;text-decoration:none;' ><i class='fa fa-arrow-right'></i></div>";
                    			$IndicadorAgregar="<div class='btn btn-xs btn-success' data-toggle='tooltip' data-placement='bottom' data-html='true' title='Interacción <font color=yellow><b>#{$d}</b></font><br>Insertar'  style='margin-left:-30px !important; text-decoration:none;'><i class='fa fa-plus'></i></div>";
                    			$IndicadorBorrar ="<div class='btn btn-xs btn-warning' data-toggle='tooltip' data-placement='bottom' data-html='true' title='Interacción <font color=yellow><b>#{$d}</b></font><br>Eliminar'  style='margin-left:-30px !important;text-decoration:none;' ><i class='fa fa-minus'></i></div>";
            			    }
            			
            			switch($diff['change'])
            			{
            				case '=':
            					$html .= '<div class="conservado">'.$IndicadorNormal.nl2br(HtmlSpecialChars(substr($before, $diff['position'], $diff['length']))).'</div>';
            					break;
            				case '-':
            					$html .= '<div class="borrado" style="background-color:orange;">'.$IndicadorBorrar.nl2br(HtmlSpecialChars(substr($before, $diff['position'], $diff['length']))).'</div>';
            					break;
            				case '+':
            					$html .= '<div class="insertado" style="background-color:lightgreen;">'.$IndicadorAgregar.nl2br(HtmlSpecialChars(substr($after, $diff['position'], $diff['length']))).'</div>';
            					break;
            				default:
            					$this->error = $diff['change'].' : Este no es un tipo de cambio esperado';
            					return false;
            			}
            		}
            		$difference->html = $html;
            		return true;
            	}

            ////////////////////////////////////////////////////////////////////
            ////////////////////////////////////////////////////////////////////
            function GenerarParche($before, $difference, &$after_patch)
            	{
            		$after = '';
            		$b = 0;
            		foreach($difference as $segment)
            		{
            			switch($segment['change'])
            			{
            				case '-':
            					if($segment['position'] !== $b)
            					{
            						$this->error = 'la posicion de segmento removida es '.$segment->position.' y no '.$b.' como se esperaba';
            						return false;
            					}
            					$b += $segment['length'];
            					break;
            
            				case '+':
            					$after .= $segment['patch'];
            					break;
            
            				case '=':
            					if($segment['position'] !== $b)
            					{
            						$this->error = 'la posicion de segmento removida es '.$segment->position.' y no '.$b.' como se esperaba';
            						return false;
            					}
            					$b += $segment['length'];
            					$after .= substr($before, $segment['position'], $segment['length']);
            					break;
            
            				default:
            					$this->error = $segment['change'].' tipo de cambio no soportado (no es +, - o =)';
            					return false;
            			}
            		}
            		$after_patch->after = $after;
            		return true;
            	}
        };


################################################################################
################################################################################
    //Carga la version 1 segun su origen
    if ($PDIFF_OrigenVersion1=="A")
        $before=file_get_contents($PDIFF_Version1);
    if ($PDIFF_OrigenVersion1=="B")
        $before=PCO_EjecutarSQL("SELECT {$PDIFF_CampoBDVersion1} FROM {$PDIFF_TablaBDVersion1} WHERE id='{$PDIFF_LlaveBDVersion1} '")->fetchColumn();

    //Carga la version 2 segun su origen
    if ($PDIFF_OrigenVersion2=="A")
        $after=file_get_contents($PDIFF_Version2);
    if ($PDIFF_OrigenVersion2=="B")
        $after=PCO_EjecutarSQL("SELECT {$PDIFF_CampoBDVersion2} FROM {$PDIFF_TablaBDVersion2} WHERE id='{$PDIFF_LlaveBDVersion2} '")->fetchColumn();

    //Ejecuta la comparacion si se reciben al menos dos versiones
	if($before!="" || $after!="")
    	{
    	    echo '<div style="font-family: sans-serif,arial,helvetica;">';
    		$diff = new BuscadorDiferencias;
    		$difference = new stdClass;
    		$difference->patch = true;
    		$after_patch = new stdClass;
    		if($diff->FormatearEnHTML($before, $after, $difference)
    		&& $diff->GenerarParche($before, $difference->difference, $after_patch))
        		{
        			echo '<div class="well well-sm">
    			            Comparando: 
    			                <div class="btn btn-xs btn-default">['.$PDIFF_OrigenVersion1.']->'.$PDIFF_Version1.$PDIFF_TablaBDVersion1.'.'.$PDIFF_CampoBDVersion2.'['.$PDIFF_LlaveBDVersion1.']</div> 
    			                <b>VS</b> 
    			                <div class="btn btn-xs btn-default">['.$PDIFF_OrigenVersion2.']->'.$PDIFF_Version2.$PDIFF_TablaBDVersion2.'.'.$PDIFF_CampoBDVersion2.'['.$PDIFF_LlaveBDVersion2.']</div>
    			            <div>
            			    <pre id="MarcoResultado" style="margin-top:10px; background-color:lightgray; padding-left:40px; font-family: mono,monospace,terminal; font-size:11px;">
            			        ', $difference->html, '
            			    </pre>
            			  ';
        			
        			echo '<div class="">
        			        <div class="btn btn-xs btn-default">Chequeo de integridad</div>
        			        ', ($after === $after_patch->after ? ' <b>OK</b>' : 'Se ha encontrado un bug. Texto parcheado (<b>'.HtmlSpecialChars($after_patch->after).'</b>) no coincide con el texto posterior (<b>'.HtmlSpecialChars($after).'</b>).');
        			echo '</div>';
        		}
    		else
    			echo '<div>Error: ', HtmlSpecialChars($diff->error), '</div>';
    	    echo '</div>';
    	}