<?php

	/*
		-------------------------------------------------------------------------
		PhpTemplate Copyright © 2002 Jeremy Locke - gravical@hotmail.com
		January 1, 2002
		-------------------------------------------------------------------------
	*/

	function NewTemplateFromFile($filename)
	{
		$tp = new PhpTemplate();
		$tp->StartFromFile($filename);
		return $tp;
	}

	function NewTemplateFromEscape($content)
	{
		$tp = new PhpTemplate();
		$tp->Start($content);
		return $tp;
	}
	
	class PhpTemplate {

		// ---------------------------------------
		// Member variables

		var $m_Stream;
		var $m_Output;
		var $m_Escape;
		var $m_Argument;
		var $m_bIsEscapeSet;
		var $m_Parameter;

		function PhpTemplate()
		{
			 // Clear
			 $this->m_Stream = "";
			 $this->m_Output = "";
			 $this->m_Escape = "";
			 $this->m_Argument = "";
			 $this->m_bIsEscapeSet = 0;
			 $this->m_Parameter = "";
		}

		// ---------------------------------------
		// Control functions

		function StartFromFile($sFilename)
		{
			// Read it
			$fTemplate = fopen($sFilename, "r");

			// Load the entire contents into this file
			$sContent = fread($fTemplate, filesize($sFilename));

			// Close it
			fclose($fTemplate);

			// Start the template
			$this->Start($sContent);
		}

		function Start($sContent)
		{
			// Set the stream
			$this->m_Stream = $sContent;
			$this->m_Output = "";
			$this->m_Escape = "";
			$this->m_Argument = "";
			$this->m_Parameter = "";

			// Defaul to no
			$this->m_bIsEscapeSet = 0;
		}

		function Next()
		{
			// Loop the nexts
			for(; $this->InternalNext();) {
			
				// Check for internally handled escapes
				if($this->m_Escape == "OPENBRACE" || $this->m_Escape == "OB") {
					$this->m_Output .= "{";
				}
				else if($this->m_Escape == "CLOSEBRACE" || $this->m_Escape == "CB") {
					$this->m_Output .= "}";
				}
				else			
					return true;
			}
			
			// Done
			return false;
		}

		function InternalNext()
		{
			// If we have no data
			if($this->m_Stream == "") {

				// No data
				$this->m_Escape = "";
				$this->m_Argument = "";
				$this->m_bIsEscapeSet = 0;

				// Set the return
				return false;
			}

			// Find an open brace
			$iOpenBrace = strpos($this->m_Stream, "{");

			// If we happen to have none left
			if($iOpenBrace >= strlen($this->m_Stream) || $iOpenBrace < 0) {
				$this->SendFullStream();
				return true;
			}

			// Find the closing
			$iCloseBrace = $this->AdvanceToEndOfEscape($this->m_Stream, $iOpenBrace + 1);

			// If there is no acceptable closing brace
			if($iCloseBrace <= 0) {
				$this->SendFullStream();
				return true;
			}

			// Set the full escape
			$sFullEscape = substr($this->m_Stream, $iOpenBrace + 1, ($iCloseBrace - 1) - $iOpenBrace);

			// Set the escape name
			$this->BreakUpEscape($sFullEscape);

			// This escape is present
			$this->m_bIsEscapeSet = 1;

			// Set the output stream
			if($iOpenBrace == 0)
				$this->m_Output .= "";
			else
				$this->m_Output .= substr($this->m_Stream, 0, $iOpenBrace);

			// Set the remainder stream
			if($iCloseBrace >= (strlen($this->m_Stream) - 1))
				$this->m_Stream = "";
			else
				$this->m_Stream = substr($this->m_Stream, -(strlen($this->m_Stream) - $iCloseBrace - 1));

			// Set the return
			return true;
		}

		function NextAndEchoOutput()
		{
			// Load the next
			if(!$this->Next()) return false;

			// Send out the output
			echo $this->GetOutput();

			// Clear
			$this->ClearOutput();
			
			// More to go
			return true;		
		}

		function End()
		{
			 // Clear
			 $this->m_Stream = "";
			 $this->m_Escape = "";
			 $this->m_Argument = "";
			 $this->m_bIsEscapeSet = 0;
		}

		function PushArgumentToStream()
		{
			$this->m_Stream = $this->m_Argument . $this->m_Stream;		
		}

		function PushToStream( $sContent )
		{
			$this->m_Stream = $sContent . $this->m_Stream;		
		}

		// ---------------------------------------
		// Escape property returns	

		function GetEscapeName()
		{
			return $this->m_Escape;
		}

		function GetEscapeArgument()
		{
			return $this->m_Argument;
		}

		function IsEscape($sEscape)
		{
			return ($this->m_bIsEscapeSet && (Strcasecmp($sEscape, $this->m_Escape) == 0));
		}

		function IsEscapeSet()
		{
			return $this->m_bIsEscapeSet;
		}
		
		function GetParameter()
		{
			return $this->m_Parameter;
		}

		// ---------------------------------------
		// Stream property returns

		function AppendToOutput($content)
		{
			$this->m_Output .= $content;
		}
		
		function ClearOutput()
		{
			$this->m_Output = "";
		}
		
		function GetOutput()
		{
			return $this->m_Output;
		}

		function GetStream()
		{
			return $this->m_Stream;
		}

		// ---------------------------------------
		// Internal functions

		function AdvanceToEndOfEscape($sStream, $iStart)
		{
			// Init
			$iBraceDepth = 0;

			// Loop until we find the right closing brace
			for($iCurrent = $iStart; $iCurrent < strlen($sStream); $iCurrent++) {

				// Get the current charachter
				$sMidStream = substr($sStream, $iCurrent, 1);

				// If we have a closing escape
				if($sMidStream == "}") {

					// If we have no depth
					if($iBraceDepth <= 0)
						return $iCurrent;
					else
						$iBraceDepth--;
				}

				// If we have an open escape
				else if($sMidStream == "{") {

					// We have a new depth
					$iBraceDepth++;
				}
			}

			// Failure, unable to find escape closing
			return 0;
		}

		function BreakUpEscape($sEscape)
		{
								
			$bIsParameter = false;
			$bParameterComplete = false;
			$iParameterBeginIndex = -1;
			$iParameterEndIndex = -1;
			
			// Clear parameter
			$this->m_Parameter = "";
		
			// Seek past all of the valid escape name charachters
			for($iCurrent = 0; $iCurrent < strlen($sEscape); $iCurrent++) 
			{

				// Get the current charachter
				if( $iCurrent > 0 ) $sMidStreamPrevious = substr($sEscape, $iCurrent - 1, 1);
				$sMidStream = substr($sEscape, $iCurrent, 1);
								
				// Check for beginning of parameter
				if( $sMidStream == "(" && !$bIsParameter && !$bParameterComplete )
				{
					$bIsParameter = true;
					$iParameterBeginIndex = $iCurrent;
				}				
				else if( $sMidStream == ")" && $bIsParameter && !$bParameterComplete && $sMidStreamPrevious != "\\" )
				{
					// Set the end of the parameter
					$bParameterComplete = true;
					$iParameterEndIndex = $iCurrent;
				}
				else
				{						
					// If there isn't a parameter found, or if the parameter found has been closed, then valid character
					if( !$bIsParameter || $bParameterComplete )
						if( $this->IsValidEscapeNameChar(ord($sMidStream)) == 0 ) break;
				}				

			}
			
			// Set the argument (remove escape name and parameter)
			if($iCurrent < strlen($sEscape))
				$this->m_Argument = substr($sEscape, -(strlen($sEscape) - $iCurrent));
			else
				$this->m_Argument = "";

			// Take the first char if it is a space
			if(substr($this->m_Argument, 0, 1) == " " && strlen($this->m_Argument) > 1)
				$this->m_Argument = substr($this->m_Argument, -(strlen($this->m_Argument) - 1));
				
			// Set the parameter
			if( $bParameterComplete )
				$this->m_Parameter = UnEscape(substr($sEscape, $iParameterBeginIndex + 1, $iParameterEndIndex - $iParameterBeginIndex - 1));
				
			// Set the escape name
			if( $iCurrent == strlen($sEscape) )
			{
				// If there is a parameter, then make sure escape name doesn't include it
				if( $bParameterComplete )
					$this->m_Escape = substr($sEscape, 0, $iParameterBeginIndex);
				else
					$this->m_Escape = $sEscape;
			}
			else if($iCurrent > 0)
			{
				// If there is a parameter, then make sure escape name doesn't include it
				if( $bParameterComplete )
					$this->m_Escape = strtoupper(substr(substr($sEscape, 0, -(strlen($sEscape) - $iCurrent)), 0, $iParameterBeginIndex));
				else
					$this->m_Escape = strtoupper(substr($sEscape, 0, -(strlen($sEscape) - $iCurrent)));
			}
			else
				$this->m_Escape = "";
							
		 }

		function IsValidEscapeNameChar($iEscapeChar)
		{
			if($iEscapeChar >= ord("A") && $iEscapeChar <= ord("Z"))
				return 1;
			else if($iEscapeChar >= ord("a") && $iEscapeChar <= ord("z"))
				return 1;
			else if($iEscapeChar >= ord("0") && $iEscapeChar <= ord("9"))
				return 1;
			else if($iEscapeChar == ord("-") || $iEscapeChar == ord("_") || $iEscapeChar == ord("."))
				return 1;
			else
				return 0;
		}

		function SendFullStream()
		{
			// No escape
			$this->m_bIsEscapeSet = 0;
			$this->m_Escape = "";
			$this->m_Argument = "";

			// Set the output
			$this->m_Output .= $this->m_Stream;

			// Clear the stream
			$this->m_Stream = "";
		}

		function HTMLEncode($text)
		{
			return str_replace("\"", "&quot;", str_replace(">", "&gt;", str_replace("<", "&lt;", $text)));
		}
				
	};
	
	function UnEscape($text)
	{
		return str_replace("\\)", ")", $text);
	}	

?>