<?php
/**
 * ###############################################
 *
 * SWIFT Framework
 * _______________________________________________
 *
 * @author		Varun Shoor
 *
 * @package		SWIFT
 * @copyright	Copyright (c) 2001-2012, Kayako
 * @license		http://www.kayako.com/license
 * @link		http://www.kayako.com
 *
 * ###############################################
 */

/**
 * The Diff Render Handling Class
 *
 * @author Varun Shoor
 */
class SWIFT_DiffRenderer extends SWIFT_Library
{
	/**
	 * Constructor
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 */
	public function __construct()
	{
		parent::__construct();

		require_once ('./' . SWIFT_BASEDIRECTORY . '/' . SWIFT_THIRDPARTYDIRECTORY . '/Text_Diff/Diff.php');
		require_once ('./' . SWIFT_BASEDIRECTORY . '/' . SWIFT_THIRDPARTYDIRECTORY . '/Text_Diff/Diff/Renderer.php');
		require_once ('./' . SWIFT_BASEDIRECTORY . '/' . SWIFT_THIRDPARTYDIRECTORY . '/Text_Diff/Diff/Renderer/inline.php');
		require_once ('./' . SWIFT_BASEDIRECTORY . '/' . SWIFT_THIRDPARTYDIRECTORY . '/Text_Diff/Diff/Renderer/context.php');
		require_once ('./' . SWIFT_BASEDIRECTORY . '/' . SWIFT_THIRDPARTYDIRECTORY . '/Text_Diff/Diff/Renderer/unified.php');

		return true;
	}

	/**
	 * Destructor
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 */
	public function __destruct()
	{
		parent::__destruct();

		return true;
	}

	/**
	 * Export Unified Diff
	 *
	 * @author Varun Shoor
	 * @param string $_fileName The File Name to Export as
	 * @param string $_oldText The Old Text
	 * @param string $_newText The New Text
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function Export($_fileName, $_oldText, $_newText)
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_oldText = preg_replace("#(\r\n|\r|\n)#s", SWIFT_CRLF, $_oldText);
		$_newText = preg_replace("#(\r\n|\r|\n)#s", SWIFT_CRLF, $_newText);

		$_oldTextList = explode(SWIFT_CRLF, $_oldText);
		$_newTextList = explode(SWIFT_CRLF, $_newText);

		$_DiffObject = new Text_Diff($_oldTextList, $_newTextList);

		$_UnifiedRendererObject = new Text_Diff_Renderer_unified();

		$_unifiedText = trim($_UnifiedRendererObject->render($_DiffObject));

		$_fileName = Clean($_fileName).'.patch';

		if(isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/MSIE/', $_SERVER['HTTP_USER_AGENT'])) {
			// IE Bug in download name workaround
			ini_set( 'zlib.output_compression','Off' );
		}

		header('Content-Type: application/force-download');
		header('Content-Disposition: attachment; filename="' . $_fileName . '"');
		header('Content-Transfer-Encoding: binary');

		echo $_unifiedText;

		return true;
	}

	/**
	 * Render the Inline HTML
	 *
	 * @author Varun Shoor
	 * @param string $_oldText The Old Text
	 * @param string $_newText The New Text
	 * @return mixed "_finalText" (STRING) on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function InlineHTML($_oldText, $_newText)
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_oldText = preg_replace("#(\r\n|\r|\n)#s", SWIFT_CRLF, $_oldText);
		$_newText = preg_replace("#(\r\n|\r|\n)#s", SWIFT_CRLF, $_newText);

		$_oldTextList = explode(SWIFT_CRLF, $_oldText);
		$_newTextList = explode(SWIFT_CRLF, $_newText);

		$_DiffObject = new Text_Diff($_oldTextList, $_newTextList);

		$_InlineRendererObject = new Text_Diff_Renderer_inline();
		$_ContextRendererObject = new Text_Diff_Renderer_context();

		$_inlineText = $_InlineRendererObject->render($_DiffObject);
		$_inlineList = explode(SWIFT_CRLF, $_inlineText);

		$_contextText = $_ContextRendererObject->render($_DiffObject);
		$_contextList = explode(SWIFT_CRLF, $_contextText);
		//print_r($_ContextRendererObject);
		//	echo $_contextText;
		//	exit;

		$_finalText = '';

/*		$_finalText = '<table width="100%"  border="0" cellpadding="1" cellspacing="0" class="gridcontentborder"><tr><td><table width="100%"  border="0" cellspacing="0" cellpadding="0"><tr><td width="50%" align="left" valign="top" class="gridrow1">';
		$_finalText .= nl2br(htmlspecialchars($_oldText));
		$_finalText .= '</td><td width="50% align="left" valign="top" class="gridrow1">';
		$_finalText .= nl2br(htmlspecialchars($_newText));
		$_finalText .= '</td></tr></table></td></tr></table>';
*/

		$_finalText .= '<table width="100%"  border="0" cellpadding="1" cellspacing="0" class="gridcontentborder"><tr><td><table width="100%"  border="0" cellspacing="0" cellpadding="0"><tr><td width="50%" align="left" valign="top" class="diffcontainer">';

//		echo 'OLD TEXT: ' .count($_oldTextList) . '<br />';
//		echo 'NEW TEXT: ' . count($_newTextList) . '<br />';

		$_totalLength = count($_oldTextList) + count($_newTextList);
		$_firstBlockStore = $_secondBlockStore = array();


		foreach ($_ContextRendererObject->_first_block as $_key => $_val)
		{
			foreach ($_val as $_subKey => $_subVal)
			{
				$_firstBlockStore[$_key][$_subKey] = substr($_subVal, 0, 1);
			}
		}

		foreach ($_ContextRendererObject->_second_block as $_key => $_val)
		{
			foreach ($_val as $_subKey => $_subVal)
			{
				$_secondBlockStore[$_key][$_subKey] = substr($_subVal, 0, 1);
			}
		}

//		echo nl2br(print_r($_ContextRendererObject, true));
//		echo nl2br(print_r($_firstBlockStore, true));
//		echo nl2br(print_r($_secondBlockStore, true));

		$_finalText .= '<ol style="padding-left: 40px; margin: 0px; background: #FFFFFF;">';

		$_firstLineNumber = $_secondLineNumber = $_secondLineTrue = $_firstLineTrue = 0;

		$_shiftPoint = -1;
		if (count($_ContextRendererObject->xblocks))
		{
			$_shiftPoint = 0;
		}
		$_shiftLength = $_shiftLineNumber = 0;

		//	echo "\n###################\nOLDTEXTLIST\n####################\n";
		//	print_r($_oldTextList);
		for ($_ii=0; $_ii < $_totalLength; $_ii++)
		{
			$_display =  false;

			$_valPrefix = '<img src="' . SWIFT::Get('themepath') . 'space.gif" align="absmiddle" width="16" height="16" border="0" />';

			if ($_shiftPoint != -1 && isset($_ContextRendererObject->xblocks[$_shiftPoint]) && $_firstLineNumber < ($_ContextRendererObject->xblocks[$_shiftPoint][0]-1))
			{
	//			echo "=1)".$_firstLineNumber."\n";
	//			echo "=2)".$_shiftPoint."\n";
	//			echo "=3)".$_ii."\n";
				$_lineClass = 'diffline';
				$_display = true;

				$_val = '  '.$_oldTextList[$_firstLineNumber];

				$_firstLineNumber++;
			} else if ($_shiftPoint == -1 && $_firstLineNumber < (count($_oldTextList))) {
				$_lineClass = 'diffline';
				$_display = true;

				$_val = '  '.$_oldTextList[$_firstLineNumber];
				$_firstLineNumber++;
	//			echo "=1)".$_firstLineNumber."\n";
	//			echo "=2)".$_shiftPoint."\n";
	//			echo "=3)".$_ii."\n";
	//			echo "=4)".count($_oldTextList)."\n";
			} else if ($_firstLineNumber == (count($_oldTextList))) {
				$_display = false;

			} else {
				if (!isset($_ContextRendererObject->xblocks[$_shiftPoint]))
				{
//					echo "A1)".$_shiftLength."\n";
//					echo "A2)".$_shiftPoint."\n";
//					echo "A3)".$_firstLineNumber."\n";

					continue;
				}

				if ($_shiftLength >= $_ContextRendererObject->xblocks[$_shiftPoint][1])
				{
					if ($_shiftPoint >= (count($_ContextRendererObject->xblocks)-1))
					{
//						echo "X1)".$_ContextRendererObject->xblocks[$_shiftPoint][1]."\n";
//						echo "X2)".$_shiftLength."\n";
//						echo "X3)".$_shiftPoint."\n";
//						echo "X4)".(count($_ContextRendererObject->xblocks)-1)."\n";

						$_shiftPoint = -1;
					} else {
	//					echo "X*1)".$_ContextRendererObject->xblocks[$_shiftPoint][1]."\n";
	//					echo "X*2)".$_shiftLength."\n";
	//					echo "X*3)".$_shiftPoint."\n";
	//					echo "X*4)".(count($_ContextRendererObject->xblocks)-1)."\n";
						$_shiftPoint++;
					}

					$_shiftLength = $_secondLineTrue = $_shiftLineNumber = 0;
					continue;
				}

				$_val = $_ContextRendererObject->_first_block[$_shiftPoint][$_shiftLineNumber];
				$_decider = substr($_val, 0, 1);

	//			echo "========================================\n".$_val."(". $_shiftPoint .")(". $_firstLineNumber .")(". $_secondLineTrue .")\n=======================================\n";

				$_display = false;

				$_lineClass = 'diffline';

				// There is a change in this line
				if ($_decider == '!' && $_secondBlockStore[$_shiftPoint][$_secondLineTrue] == '!')
				{
					$_valPrefix = '<img src="' . SWIFT::Get('themepath') . 'images/icon_diffchange.gif" align="absmiddle" width="16" height="16" border="0" />';
					$_lineClass = 'difflinechange';
					$_display = true;
					$_secondLineTrue++;
				// Line was probably added in the 2nd block
				} else if ($_decider == ' ' && $_secondBlockStore[$_shiftPoint][$_secondLineTrue] == '!') {
					$_finalText .= '<li class="difflineempty"><div>'. $_valPrefix .'&nbsp;</div></li>';
					$_secondLineTrue++;
				} else if ($_decider == '+') {
					$_valPrefix = '<img src="' . SWIFT::Get('themepath') . 'images/icon_diffadd.gif" align="absmiddle" width="16" height="16" border="0" />';
					$_lineClass = 'difflineadded';
					$_display = true;
					$_secondLineTrue++;
				} else if ($_decider == '-') {
					$_valPrefix = '<img src="' . SWIFT::Get('themepath') . 'images/icon_diffdelete.gif" align="absmiddle" width="16" height="16" border="0" />';
					$_lineClass = 'difflinedeleted';
					$_display = true;

				// No change for both the lines
				} else if ($_decider == ' ' && $_secondBlockStore[$_shiftPoint][$_secondLineTrue] == ' ') {
					$_lineClass = 'diffline';
					$_display = true;
					$_secondLineTrue++;

				// Line was probably added
				} else if ($_decider == '!' && $_secondBlockStore[$_shiftPoint][$_secondLineTrue] != '!') {
					$_valPrefix = '<img src="' . SWIFT::Get('themepath') . 'images/icon_diffadd.gif" align="absmiddle" width="16" height="16" border="0" />';
					$_lineClass = 'difflineadded';
					$_display = true;

				} else if ($_secondBlockStore[$_shiftPoint][$_secondLineTrue] == '+' && $_decider != '+') {
					$_finalText .= '<li class="difflineempty"><div>' . $_valPrefix . '&nbsp;</div></li>';
					$_secondLineTrue++;

				} else {
					$_finalText .= $_secondLineTrue . ':' . $_ii . ':' . $_decider . '-' . $_secondBlockStore[$_shiftPoint][$_secondLineTrue] . '-' . $_secondLineTrue . '<br />';
				}

				if ($_display)
				{
					$_firstLineNumber++;
					$_shiftLength++;
					$_shiftLineNumber++;
				}
			}


			if ($_display)
			{
				$_finalText .= '<li class="' . $_lineClass . '">' . $_valPrefix . '&nbsp;' . htmlspecialchars(trim(substr($_val, 2))) . '</li>';
			}
		}

		$_finalText .= '</ol>';
		$_finalText .= '</td><td width="50% align="left" valign="top">';
		$_finalText .= '<ol style="padding-left: 40px; margin: 0px; background: #FFFFFF;">';


//	echo "\n###################\nFIRSTBLOCKSTORE\n####################\n";
//	print_r($_firstBlockStore);
//	echo "\n###################\nSECONDBLOCKSTORE\n####################\n";
//	print_r($_secondBlockStore);

	$_shiftPoint = -1;
	if (count($_ContextRendererObject->yblocks))
	{
		$_shiftPoint = 0;
	}

	$_shiftLength = $_shiftLineNumber = 0;

//	echo nl2br(print_r($_ContextRendererObject, true));

	$_secLineNumber = 0;
//	echo '--'.strlen($_newText).'--'.strlen($_oldText).'--';
//	echo '--'.count($_newTextList).'--'.count($_oldTextList).'--'.count($_ContextRendererObject->yblocks);
	for ($_ii=0; $_ii < $_totalLength; $_ii++)
	{
		$_display = false;

		$_valPrefix = '<img src="' . SWIFT::Get('themepath') . 'space.gif" align="absmiddle" width="16" height="16" border="0" />';

		if (!count($_ContextRendererObject->yblocks) && isset($_newTextList[$_secondLineNumber]) && $_secondLineNumber < (count($_newTextList)-1)) {
//			echo $_ii.': 1<br />';
			$_lineClass = 'diffline';
			$_finalText .= '<li class="' . $_lineClass . '">' . $_valPrefix . '&nbsp;' . trim(htmlspecialchars($_newTextList[$_secondLineNumber])) . '</li>';

			$_display = false;
			$_secondLineNumber++;
		} else if ($_shiftPoint != -1 && isset($_ContextRendererObject->yblocks[$_shiftPoint]) && $_secondLineNumber < ($_ContextRendererObject->yblocks[$_shiftPoint][0]-1)) {
//			echo $_ii.': 2<br />';
			$_lineClass = 'diffline';
			$_display = true;

			$_val = $_newTextList[$_secondLineNumber];

			$_secondLineNumber++;
		} else if ($_shiftPoint == -1 && $_secondLineNumber < (count($_newTextList))) {
//			echo $_ii.': 3<br />';
			$_lineClass = 'diffline';
			$_display = true;

			$_val = $_newTextList[$_secondLineNumber];
			$_secondLineNumber++;
		} else if ($_secondLineNumber == (count($_newTextList)) && count($_newTextList)) {
//			echo $_ii.': 4<br />';
			$_display = false;
		} else {
//			echo $_ii.': 5<br />';
			if ($_shiftLength >= $_ContextRendererObject->yblocks[$_shiftPoint][1])
			{
				if ($_shiftPoint >= (count($_ContextRendererObject->yblocks)-1))
				{
//					echo "Y1)".$_ContextRendererObject->yblocks[$_shiftPoint][1]."\n";
//					echo "Y2)".$_shiftLength."\n";
//					echo "Y3)".$_shiftPoint."\n";
//					echo "Y4)".(count($_ContextRendererObject->yblocks)-1)."\n";
					$_shiftPoint = -1;
				} else {
//					echo "Y*1)".$_ContextRendererObject->yblocks[$_shiftPoint][1]."\n";
//					echo "Y*2)".$_shiftLength."\n";
///					echo "Y*3)".$_shiftPoint."\n";
//					echo "Y*4)".(count($_ContextRendererObject->yblocks)-1)."\n";
					$_shiftPoint++;
				}
//			echo $_ii.': 6<br />';

				$_shiftLength = $_shiftLineNumber = $_firstLineTrue = 0;
				continue;
			}

			$_decider = substr($_ContextRendererObject->_second_block[$_shiftPoint][$_shiftLineNumber], 0, 1);
//			echo "========================================\n".$_val."(". $_shiftPoint .")(". $_shiftLineNumber .")(". $_firstLineTrue .")(". $_decider .")\n=======================================\n";
			$_display = false;

			// No change in both lines?
			if ($_decider == ' ' && $_firstBlockStore[$_shiftPoint][$_firstLineTrue] == ' ')
			{
//			echo $_ii.': 7<br />';
				$_lineClass = 'diffline';
				$_display = true;
				$_firstLineTrue++;

			// Lines have changed
			} else if ($_decider == '!' && $_firstBlockStore[$_shiftPoint][$_firstLineTrue] == '!') {
//			echo $_ii.': 8<br />';
				$_lineClass = 'difflinechange';
				$_valPrefix = '<img src="' . SWIFT::Get('themepath') . 'images/icon_diffchange.gif" align="absmiddle" width="16" height="16" border="0" />';
				$_display = true;
				$_firstLineTrue++;

			// New lines added (though marked as changed)
			} else if ($_decider == '!' && $_firstBlockStore[$_shiftPoint][$_firstLineTrue] == ' ') {
//			echo $_ii.': 9<br />';
				$_lineClass = 'difflineadded';
				$_valPrefix = '<img src="' . SWIFT::Get('themepath') . 'images/icon_diffadd.gif" align="absmiddle" width="16" height="16" border="0" />';
				$_display = true;

			// Line was probably changed or deleted add an empty block
			} else if ($_decider == ' ' && (isset($_firstBlockStore[$_shiftPoint][$_ii]) && $_firstBlockStore[$_shiftPoint][$_ii] == '!')) {
//			echo $_ii.': 10<br />';
				$_valPrefix = '<img src="' . SWIFT::Get('themepath') . 'images/icon_diffdelete.gif" align="absmiddle" width="16" height="16" border="0" />';
				$_finalText .= '<li class="difflineempty"><div>' . $_valPrefix . '&nbsp;</div></li>';
				$_firstLineTrue++;

			// Line added?
			} else if ($_decider == '+' && (!isset($_firstBlockStore[$_shiftPoint][$_firstLineTrue]) || $_firstBlockStore[$_shiftPoint][$_firstLineTrue] == ' ')) {
//			echo $_ii.': 11<br />';
				$_lineClass = 'difflineadded';
				$_valPrefix = '<img src="' . SWIFT::Get('themepath') . 'images/icon_diffadd.gif" align="absmiddle" width="16" height="16" border="0" />';
				$_display = true;

			// Line deleted?
			} else if ($_firstBlockStore[$_shiftPoint][$_firstLineTrue] == '-') {
//			echo $_ii.': 12<br />';
				$_valPrefix = '<img src="' . SWIFT::Get('themepath') . 'images/icon_diffdelete.gif" align="absmiddle" width="16" height="16" border="0" />';
				$_finalText .= '<li class="difflineempty"><div>' . $_valPrefix . '&nbsp;</div></li>';
				$_firstLineTrue++;
//				$_secLineNumber++;

			} else {
//			echo $_ii.': 13<br />';
				$_finalText .= $_secLineNumber . ':' . $_ii . ':' . $_decider . '-' . $_firstBlockStore[$_shiftPoint][$_firstLineTrue] . '-' . $_firstLineTrue . '<br/>';
			}

			if ($_display)
			{
				$_secondLineNumber++;
				$_shiftLength++;
				$_shiftLineNumber++;
			}
		}

		if ($_display)
		{
			$_finalText .= '<li class="' . $_lineClass . '">' . $_valPrefix . '&nbsp;' . trim($_inlineList[$_secLineNumber]) . '</li>';

			$_secLineNumber++;
		}
	}
	$_finalText .= '</ol>';

//	print_r($_firstBlockStore);
//	print_r($_secondBlockStore);
//	print_r($_ContextRendererObject->_first_block);
//	print_r($_ContextRendererObject->_second_block);
	$_finalText .= '</td></tr></table></td></tr></table>';
//	print_r($_inlineList);
	return $_finalText;

	}
}
?>