<?php

# PLUGIN PREVIEW BY TEXTPATTERN.INFO

if (@txpinterface == 'admin') {
  
add_privs('rvm_plugin_diff''1,2');
  
register_tab('extensions''rvm_plugin_diff''Plugin Diff');
  
register_callback('rvm_plugin_diff''rvm_plugin_diff');
}

/**
  Diff routine uses some parts of the code found at this address:
  http://www.holomind.de/phpnet/diff2.src.php
  Copyright (C) 2003  Daniel Unterberger <diff.phpnet@holomind.de>
  Copyright (C) 2005  Nils Knappmeier (next version)
  License: GNU General Public License version 2 or later
  http://www.gnu.org/licenses/gpl.html
**/

function rvm_plugin_diff($event$step) {
  
pagetop('Plugin Diff');

  
$name gps('name');
  
$nospace gps('nospace') ? 0;
  
$context is_numeric(gps('context')) ? intval(gps('context')) : '5';

  
$plugins = array();
  
$mplugins safe_column('name''txp_plugin''code != code_restore');
  
$oplugins safe_column('name''txp_plugin''code = code_restore');
  
asort($oplugins); asort($mplugins);
  if (
$mplugins) {
    
$plugins[] = ' ';
    if (
$oplugins$plugins[] = ' ----- MODIFIED ----- ';
    foreach(
$mplugins as $plugin$plugins[] = $plugin;
  }
  if (
$oplugins) {
    
$plugins[] = ' ';
    if (
$mplugins$plugins[] = ' ----- ORIGINAL ----- ';
    foreach(
$oplugins as $plugin$plugins[] = $plugin;
  }
  if (isset(
$plugins[$name])) $name $plugins[$name];

  echo 
'<div style="border:1px solid #ccc;background:#f7f7f7;padding:1em;margin-left:2em;float:left;">';
  echo 
form(
    
'<p>Plugin '.selectInput('name'$plugins$name0).'</p>'.
    
'<p>Show <input type="text" name="context" maxlength="4" size="3" value="'.$context.'" class="edit" /> lines around each change</p>'.
    
'<p>'.checkbox('nospace','ignore',$nospace).' Ignore white space changes</p>'.
    
eInput('rvm_plugin_diff').
    
fInput('submit','','Show Changes','publish')
  );
  echo 
'</div>';
  echo 
'<br style="clear:both" />';

  
$rs safe_row('code,code_restore,name,version''txp_plugin'"name='".safe_escape($name)."'");
  if (!
$rs) return;
  
extract($rs);
  unset(
$rs);

  
# force Unix-style line breaks
  
$code_restore str_replace("\r\n"n$code_restore);
  
$code_restore str_replace("\r"n$code_restore);
  
$code str_replace("\r\n"n$code);
  
$code str_replace("\r"n$code);

  
# split the source text into arrays of lines
  
$t1 explode(n,trim($code_restore));
  
$t2 explode(n,trim($code));
  unset(
$code_restore,$code);

  
# build a reverse-index array using the line as key and line number as value
  
foreach($t1 as $i=>$x$r1[$x][] = $i;
  foreach(
$t2 as $i=>$x$r2[$x][] = $i;

  
$a1=0$a2=0;   # start at beginning of each list
  
$actions = array();
  
$is_diff false;

  
# walk this loop until we reach the end of one of the lists
  
while ($a1<count($t1) && $a2<count($t2)) {
    
# if we have a common element, save it and go to the next
    
if ($nospace trim($t1[$a1])==trim($t2[$a2]) : $t1[$a1]==$t2[$a2])
      { 
$actions[]=0$a1++; $a2++; continue; }
    
# otherwise, find the shortest move (Manhattan-distance) from the
    # current location
    
$is_diff true;
    
$best1=count($t1); $best2=count($t2);
    
$s1=$a1$s2=$a2;
    while(
$s1+$s2 $best1+$best2) {
      
$d=-1;
      foreach((array)@
$r1[$t2[$s2]] as $n)
        if (
$n>=$s1) { $d=$n; break; }
      if (
$d>=$s1 and $d+$s2 $best1+$best2)
        { 
$best1=$d$best2=$s2; }
      
$d=-1;
      foreach((array)@
$r2[$t1[$s1]] as $n)
        if (
$n>=$s2) { $d=$n; break; }
      if (
$d>=$s2 and $s1+$d $best1+$best2)
        { 
$best1=$s1$best2=$d; }
      
$s1++; $s2++;
    }
    while (
$a1<$best1) { $actions[]=1$a1++; }  # deleted elements
    
while ($a2<$best2) { $actions[]=2$a2++; }  # added elements
  
}
  unset(
$r1,$r2);

  
# we've reached the end of one list, now walk to the end of the other
  
while($a1<count($t1)) { $actions[]=1$a1++; }  # deleted elements
  
while($a2<count($t2)) { $actions[]=2$a2++; }  # added elements

  # create $lines array with all needed info for further processing
  
$i1=$i2=0;
  
$lines = array();
  foreach(
$actions as $act) {
    
$line = ($act==$t1[$i1] : $t2[$i2]);
    
$line_old = ($act==: ++$i1);
    
$line_new = ($act==: ++$i2);
    
$lines[] = array($line_old$line_new$line2);
  }

  
# remember how much space the line numbers will need
  
$n1 strlen(count($t1)); if ($n1 3$n1 3$n1++;
  
$n2 strlen(count($t2)); if ($n2 3$n2 3$n2++;
  unset(
$t1,$t2,$actions);

  
# mark lines that are needed to provide context
  
if ($is_diff) {
    if (
trim($context) != '') {
      
$count 0;
      foreach(
$lines as $nr => $line) {
        if (
$line[0] and $line[1]) {
          if (
$count$count--;
          else 
$lines[$nr][3]--;
        }
        else 
$count $context;
      }
      
$count 0;
      for(
$nr count($lines)-1$nr >= 0$nr--) {
        if (
$lines[$nr][0] and $lines[$nr][1]) {
          if (
$count$count--;
          else 
$lines[$nr][3]--;
        }
        else 
$count $context;
      }
    }

    
# unified diff
    
if (gps('format')) {
      
$udiff '';
      
$diff = array(0,0,0,0);
      foreach(
$lines as $line) {
        if (!
$line[3]) {
          if (
$out) {
            
$udiff .= $diff[4].$out;
            
$out '';
            
$diff = array(0,0,0,0);
          }
        }
        else {
          if (!
$diff[0]) $diff[0] = $line[0];
          if (!
$diff[1]) $diff[1] = $line[1];
          if (
$line[0]) $diff[2] = $line[0];
          if (
$line[1]) $diff[3] = $line[1];
          
$diff[4] = '@@ -'.$diff[0].','.($diff[2]+1-$diff[0]).' +'.$diff[1].','.($diff[3]+1-$diff[1]).' @@'.n;
          
$out .= (!$line[1] ? '-' : (!$line[0] ? '+' ' ')) . $line[2] . n;
        }
      }
      if (
$out$udiff .= $diff[4].$out;

      
# send unified diff file
      
if ($udiff) {
        
$plugin $name.'-'.$version;
        
$time strftime(' %Y-%m-%d %H:%M:%S.000000000 %z',time());
        
$udiff '--- '.$plugin.'.orig'.$time.n.'+++ '.$plugin.'.new'.$time.n.$udiff;
        
ob_clean();
        
header('Content-Description: Plugin Diff');
        
header('Content-Type: text/plain;charset=utf-8');
        
header('Content-Length: ' strlen($udiff));
        
header('Content-Disposition: attachment; filename="' $plugin '.diff"');
        echo 
$udiff;
        
ob_flush();
        
flush();
        exit;
      }
    }

    
# add inline diff markers
    
$ins $del = array();
    foreach(
$lines as $nr => $line) {
      if (
$line[0] and $line[1]) {
        if (
$del and count($del) == count($ins)) {
          while(
$delnr array_shift($del) and $insnr array_shift($ins)) {
            
$begin 0$end 0;
            
$delstr $lines[$delnr][2];
            
$insstr $lines[$insnr][2];
            
$max min(strlen($insstr),strlen($delstr));
            while(
$begin <= $max and substr($delstr,$begin,1) == substr($insstr,$begin,1)) $begin++;
            while(
$end <= $max and substr($delstr,-$end-1,1) == substr($insstr,-$end-1,1)) $end++;
            if (!
$begin and !$end) continue;
            foreach(array(
$delnr,$insnr) as $linenr) {
              
$str $lines[$linenr][2];
              
$len strlen($str) - $begin $end;
              if (
$len 0) { $end += $len$len 0; }
              
$lines[$linenr][2] = substr($str,0,$begin)."\r".substr($str,$begin,$len)."\r".($end?substr($str,-$end):'');
            }
          }
        }
        
$ins $del = array();
      }
      else {
        if (
$line[0]) $del[] = $nr;
        else 
$ins[] = $nr;
      }
    }
  }

  
# download link
  
if ($is_diff) echo '<p style="margin-left:3em"><a href="?event=rvm_plugin_diff'.a.'format=diff'.a.'name='.urlencode($name).a.'context='.$context.a.'nospace='.$nospace.'">Download in <strong>unified diff</strong> format</a></p>';

  
# color diff
  
$lstyle ' style="color: #999; border-right:1px solid #ccc;padding:0em .5em 0em 0em;"';
  echo 
'<pre>';
  if (
$is_diff) {
    echo 
"<span$lstyle>".str_pad('Old'$n1' 'STR_PAD_LEFT).'</span>';
    echo 
"<span$lstyle>".str_pad('New'$n2' 'STR_PAD_LEFT).'</span>'.n;
  }
  
$skip false;
  foreach(
$lines as $line) {
    if (!
$line[3]) {
      
# empty space between diff parts
      
if (!$skip) echo '<div style="background:#f7f7f7;height:2em;border:1px solid #ccc";border-right:none;>&nbsp;</div>';
      
$skip true;
      continue;
    }
    else 
$skip false;
    if (
$is_diff) echo "<span$lstyle>".str_pad(($line[0] ? $line[0] : ''),$n1,' ',STR_PAD_LEFT).'</span>';
    echo 
"<span$lstyle>".str_pad(($line[1] ? $line[1] : ''),$n2,' ',STR_PAD_LEFT).'</span>';
    if (!
$line[1]) echo '<span style="background: #fdd;">';
    if (!
$line[0]) echo '<span style="background: #dfd;">';
    
$str str_replace("\t",'  ',htmlspecialchars($line[2]));
    if (!
$line[1] or !$line[0]) {
      
# color inline diff
      
$color $line[0] ? '#eaa' '#9e9';
      
$str preg_replace('/\r(.*)\r/','<span style="background:'.$color.'">${1}</span>',$str);
    }
    echo 
' '.$str;
    if (!
$line[0] or !$line[1]) echo '</span>';
    echo 
n;
  }
  echo 
'</pre>';
}