/**
  * Process the template modifier tags
  * Convert {parse ...} tags
  *
  * @param	string		Content
  * @return	@e string
  */
 protected function _processPluginTags($text)
 {
     $text = IPSText::replaceRecursively($text, '{parse', '\\"}', array('classTemplate', '_processPluginTagsCallback'));
     //print "\n\n========\n\n".$text."\n\n========\n\n";
     return $text;
 }
 /**
  * Replace Recursively
  *
  * @access	public
  * @param	string		Text to search in
  * @param	string		Opening text to search for. (Example: <a href=)
  * @param	string		Closing text to search for. (Example: >)
  * @param	mixed		Call back function that handles the replacement. If using a class, pass array( $classname, $function ) THIS MUST BE A STATIC FUNCTION
  * @return	string		Replaced text
  * <code>
  * # We want to replace all instances of <a href="http://www.domain.com"> with <a href="javascript:goLoad('domain.com')">
  * $text = IPSText::replaceRecursively( $text, "<a href=", ">", array( 'myClass', 'replaceIt' ) );
  * class myClass {
  *	static function replaceIt( $text, $openText, $closeText )
  *	{
  *		# $text contains the matched text between the tags, eg: "http://www.domain.com"
  *		# $openText contains the searched for opening, eg: <a href
  *		# $closeText contains the searched for closing, eg: >
  *		# Remove http...
  *		$text = str_replace( 'http://', '', $text )
  *		# Remove quotes
  * 		$text = str_replace( array( '"', "'" ), '', $text );
  *		return '"javascript:goLoad(\'' . $text . '\')"';
  *	}
  * }
  * </code>
  */
 public static function replaceRecursively($text, $textOpen, $textClose, $callBackFunction)
 {
     //----------------------------------------
     // INIT
     //----------------------------------------
     # Tag specifics
     $foundOpenText_pointer = 0;
     $foundCloseText_pointer = 0;
     $foundOpenTextRecurse_pointer = 0;
     //----------------------------------------
     // Keep the server busy for a while
     //----------------------------------------
     while (1 == 1) {
         # Reset pointer
         $startOfTextAfterOpenText_pointer = 0;
         # See if we have any 'textOpen' at all
         $foundOpenText_pointer = strpos($text, $textOpen, $foundCloseText_pointer);
         # No?
         if ($foundOpenText_pointer === FALSE) {
             break;
         }
         # Do we have any close text?
         $foundCloseText_pointer = strpos($text, $textClose, $foundOpenText_pointer);
         # No?
         if ($foundCloseText_pointer === FALSE) {
             return $text;
         }
         # Reset pointer for text between the open and close text
         $startOfTextAfterOpenText_pointer = $foundOpenText_pointer + strlen($textOpen);
         # Check recursively
         $foundOpenTextRecurse_pointer = $startOfTextAfterOpenText_pointer;
         while (1 == 1) {
             # Got any open text again?
             $foundOpenTextRecurse_pointer = strpos($text, $textOpen, $foundOpenTextRecurse_pointer);
             # No?
             if ($foundOpenTextRecurse_pointer === FALSE or $foundOpenTextRecurse_pointer >= $foundCloseText_pointer) {
                 break;
             }
             # Yes! Reset recursive pointer
             $foundCloseTextRecurse_pointer = $foundCloseText_pointer + strlen($textClose);
             # Yes! Reset close normal pointer to next close tag FROM the last found close point
             $foundCloseText_pointer = strpos($text, $textClose, $foundCloseTextRecurse_pointer);
             # Make sure we have a closing text
             if ($foundCloseText_pointer === FALSE) {
                 return $text;
             }
             $foundOpenTextRecurse_pointer += strlen($textOpen);
         }
         # This is the text between the open text and close text
         $foundText = substr($text, $startOfTextAfterOpenText_pointer, $foundCloseText_pointer - $startOfTextAfterOpenText_pointer);
         # Recurse
         if (strpos($foundText, $textOpen) !== FALSE) {
             $foundText = IPSText::replaceRecursively($foundText, $textOpen, $textClose, $callBackFunction);
         }
         # Run the call back...
         $_newText = call_user_func($callBackFunction, $foundText, $textOpen, $textClose);
         # Run the replacement
         $text = substr_replace($text, $_newText, $foundOpenText_pointer, $foundCloseText_pointer - $foundOpenText_pointer + strlen($textClose));
         # Reset pointer
         $foundCloseText_pointer = $foundOpenText_pointer + strlen($_newText);
     }
     return $text;
 }