<?
//i have tried to make private functions begin with an underscore
//i have tried to keep the functions in the order they are generally called
class quickietemplate
{
    var 
$version "20050423";
    var 
$begintag "<!--";
    var 
$endtag  "-->";
    var 
$beginblock "BEGIN BLOCK:";
    var 
$endblock  "END BLOCK:";

    
//debug can be set 2, 1, 0 (Warnings, Errors, Nothing)
    
var $debug 2;

    
//these are set during the initiater function to the tags above
    
var $patternstart;
    var 
$patternfinish;

    var 
$currentworkdirectory;

    
//these keep the three states of the template
    
var $tploriginal;
    var 
$tplchanged;
    var 
$tplprintout;

    
//this is just a more efficient way of keeping track of which subblocks
    //are below a given block without iterating through the array and finding
    //the begin and end block, but it is not used at the moment except for debug
    
var $subblock;

    
//this array just stores the begin and end block line number for each sublcok
    //it is only used for debug information
    
var $alphaomega;


    
//we que up all the assign patterns and do then in one go
    
var $replacelocalqueue;
    var 
$replaceallqueue;

    function 
quickietemplate($filelocation)
    {
        
$this->_initiater($filelocation);
    }

    function 
_initiater($filelocation)
    {
        if(!
file_exists($filelocation))
        {
            
//echo "ERROR: " . $filelocation . " does not exist.";
            
$this->_debugmessage($filelocation " does not exist.""ERROR");
            return;
        }

        
$this->currentworkdirectory dirname($filelocation);

        
$this->patternstart "/" $this->begintag "\s*" $this->beginblock "\s*(.+)\s*" $this->endtag "/";
        
$this->patternfinish "/" $this->begintag "\s*" $this->endblock "\s*(.+)\s*" $this->endtag "/";

        
$alltext file($filelocation);
        if((
count($alltext) == "1") && !ini_get(auto_detect_line_endings))
        {
            
//echo "ERROR: " . $filelocation . " appears to be a MAC text file.";
            
$this->_debugmessage($filelocation " appears to be a MAC text file.""ERROR");
        }
        
//this adds a blank line to the beginning
        //which helps when using blank master notation
        
array_unshift($alltext"");

        
$holder $this->_slicer($alltext0"master"0);
        
//listvar($holder);
        //$this->listvar($holder);

        
$this->tploriginal $holder;
        
$this->tplchanged $holder;
        
//$this->assign('(.*)', '');
    
}

    function 
_slicer($blob$linenumber$blockname$depth)
    {
        
$tploriginal = array();
        
//start initial depth, reference, and blocklongnotation
        
$depth 0;
        
$reference[$depth] = $blockname;
        
$blocklongnotation implode("."$reference);

        for(
$x $linenumber$x sizeof($blob); $x++)
        {
            
//uncomment this if you want to see how tploriginal is built
            //echo $linenumber . "-" . $x . "-" . $blocklongnotation . " - " . htmlentities($blob[$linenumber]) . "<br>\n";

            
if(preg_match($this->patternstart$blob[$linenumber], $match))
            {
                
$tploriginal[$blocklongnotation][$linenumber] = $blob[$linenumber];

                
//we increase depth and set the reference array to the current block name
                
$depth++;
                
$blockname trim($match[1]);
                
$reference[$depth] = $blockname;

                
//before we set the blocklongnoation to its new value
                //we want to assign the new blocklongnotation to the sublock array
                //with the key being the old blocklongnotation
                
$this->subblock[$blocklongnotation][] = implode("."$reference);

                
$blocklongnotation implode("."$reference);
                
//echo "BEGIN:" . $depth . " - " . $blockname . " - " . $blocklongnotation . "<br>\n";

                //set alphaomega array with beginning linenumber
                
$this->alphaomega[$blocklongnotation]["begin"] = $linenumber;

                
$tploriginal[$blocklongnotation][$linenumber] = $blob[$linenumber];
            }
            else if(
preg_match($this->patternfinish$blob[$linenumber], $match))
            {
                
$tploriginal[$blocklongnotation][$linenumber] = $blob[$linenumber];

                
//set alphaomega array with ending linenumber
                
$this->alphaomega[$blocklongnotation]["end"] = $linenumber;

                
//we really do not need to set the end block name as we have the name
                //from the begin block and so the very next end block we come up against
                //should be the appropriate end block, but i am adding this in here for
                //error checking purposes
                
$blockname trim($match[1]);
                if(
$blockname != $reference[$depth])
                {
                    
//echo "ERROR: end block (" . $blockname . ") does not match begin block (" . $reference[$depth] . ")";
                    
$this->_debugmessage("end block (" $blockname ") does not match begin block (" $reference[$depth] . ")""WARNING");
                }
                
//we unset the last reference block name and decrease the depth
                
unset($reference[$depth]);
                
$depth--;

                
$blocklongnotation implode("."$reference);
                
//echo "END:" . $depth . " - " . $blockname . " - " . $blocklongnotation . "<br>\n";

                
$tploriginal[$blocklongnotation][$linenumber] = $blob[$linenumber];
            }
            else if(
preg_match("/\{TPL_SOURCE:(.+)\}/U"$blob[$linenumber], $match))
            {
                
//what to do if we find a TPL_SOURCE
                //basically we read in the file and insert it into the file array
                //it needs a little tightening up and better error handling
                
$filelocation["tplsource"] = $this->currentworkdirectory '/' trim($match[1]);

                if(!
file_exists($filelocation["tplsource"]))
                {
                    
//echo "ERROR: " . $filelocation["tplsource"] . " does not exist.";
                    
$this->_debugmessage($filelocation["tplsource"] . " does not exist.""WARNING");
                }

                
$matched '{TPL_SOURCE:' $match[1] . '}';

                
$strpos[0] = strpos($blob[$linenumber], $matched);
                
$strpos[1] = $strpos[0] + strlen($matched);
                
//listvar($strpos);
                
$splitline[0] = substr($blob[$linenumber], 0$strpos[0]);
                
$splitline[1] = substr($blob[$linenumber], $strpos[1]);
                
//listvar($splitline);

                
$pasttext array_slice($blob0$x);
                
$pasttext[] = $splitline[0];

                
$subsourcetext file($filelocation["tplsource"]);
                
$futuretext array_slice($blob, ($x 1));

                
$newtext array_merge($pasttext$subsourcetext);
                
$newtext[] = $splitline[1];
                
$newtext array_merge($newtext$futuretext);

                
//listvar($pasttext);
                //listvar($splitline[1]);
                //listvar($futuretext);

                
$blob $newtext;
                
//listvar($newtext);

                
$tploriginal[$blocklongnotation][$linenumber] = $blob[$linenumber];
            }
            else
            {
                
$tploriginal[$blocklongnotation][$linenumber] = $blob[$linenumber];
            }

            
$linenumber++;
        }
        
//listvar($reference);
        //listvar($this->subblock);
        //listvar($this->alphaomega);
        //listvar($tploriginal);
        
return $tploriginal;
    }

    
//the assign function just adds the keyword and the replacement text to a
    //replaceallqueue, the actual replacement happens when parse is called
    //this allows us to pass all the patterns to the php preg_replace function
    //which is probably faster then iterating over the blocks for every assign
    
function assign($pattern$replacement)
    {
        
//if it is an array we write it out in long noation using periods
        
if(is_array($replacement))
        {
            while(list(
$key$val) = each($replacement))
            {
                
//$pattern2 = "/{" . $pattern . "." . $key . "}/";
                
$pattern2 "{" $pattern "." $key "}";
                
$replacement2 $val;
                
$this->replaceallqueue["everything"]["pattern"][] = $pattern2;
                
$this->replaceallqueue["everything"]["replacement"][] = $replacement2;
            }
        }
        else
        {
                
//$pattern = "/{" . $pattern . "}/";
                
$pattern "{" $pattern "}";
                
$this->replaceallqueue["everything"]["pattern"][] = $pattern;
                
$this->replaceallqueue["everything"]["replacement"][] = $replacement;
        }
    }

    function 
assignlocal($blocknotation$pattern$replacement)
    {
        if(!empty(
$blocknotation))
            
$masterblocknotation "master." $blocknotation;
        else
            
$masterblocknotation "master";

        if(!isset(
$this->tploriginal[$masterblocknotation]))
        {
            
//echo "ERROR: " . $blocknotation . " does not exist.";
            
$this->_debugmessage($blocknotation " does not exist.""WARNING");
        }

        
//if it is an array we write it out in long noation using periods
        
if(is_array($replacement))
        {
            while(list(
$key$val) = each($replacement))
            {
                
//$pattern2 = "/{" . $pattern . "." . $key . "}/";
                
$pattern2 "{" $pattern "." $key "}";
                
$replacement2 $val;
                
$this->replacelocalqueue[$masterblocknotation]["pattern"][$pattern2] = $pattern2;
                
$this->replacelocalqueue[$masterblocknotation]["replacement"][$pattern2] = $replacement2;
            }
        }
        else if(
is_scalar($replacement))
        {
                
//$pattern = "/{" . $pattern . "}/";
                
$pattern "{" $pattern "}";
                
$this->replacelocalqueue[$masterblocknotation]["pattern"][$pattern] = $pattern;
                
$this->replacelocalqueue[$masterblocknotation]["replacement"][$pattern] = $replacement;
        }
    }

    function 
_replacer($masterblocknotation)
    {
        
$pattern = array();
        
$replacement = array();

        if(!isset(
$this->tploriginal[$masterblocknotation]))
            return;

        if(isset(
$this->replacelocalqueue[$masterblocknotation]["pattern"]))
            
$pattern $this->replacelocalqueue[$masterblocknotation]["pattern"];

        if(isset(
$this->replacelocalqueue[$masterblocknotation]["replacement"]))
            
$replacement $this->replacelocalqueue[$masterblocknotation]["replacement"];

        if(isset(
$this->replaceallqueue["everything"]["pattern"]))
            
$pattern array_merge($pattern$this->replaceallqueue["everything"]["pattern"]);

        if(isset(
$this->replaceallqueue["everything"]["replacement"]))
            
$replacement array_merge($replacement$this->replaceallqueue["everything"]["replacement"]);

        
$pattern array_reverse($pattern);
        
$replacement array_reverse($replacement);

        
//this blanks out any un modified { }
        //$pattern2 = "/\{" . "(.*)" . "\}/";

        
$pattern2 '/\{([^\}]*)\}/sm';
        
$replacement2 "";
        
//echo $pattern2;
        
$pattern[$pattern2] = $pattern2;
        
$replacement[$pattern2] = $replacement2;

        
reset($this->tploriginal[$masterblocknotation]);
        while(list(
$key$val) = each($this->tploriginal[$masterblocknotation]))
        {
            
//$this->tplchanged[$masterblocknotation][$key] = preg_replace($pattern, $replacement, $val);
            
$val str_replace($pattern$replacement$val);
            
$val eregi_replace("[\{]([A-Z,0-9,\.,\_]+)[\}]"""$val);
            
$this->tplchanged[$masterblocknotation][$key] = $val;
        }

        
//we need to blank out the replacement que when we are done parsing the local block
        
unset($this->replacelocalqueue[$masterblocknotation]["pattern"]);
        unset(
$this->replacelocalqueue[$masterblocknotation]["replacement"]);
    }

    function 
parse($blocknotation)
    {
        if(!empty(
$blocknotation))
            
$masterblocknotation "master." $blocknotation;
        else
            
$masterblocknotation "master";
        
//listvar($this->replaceallqueue["everything"]);
        //listvar($this->replacelocalqueue[$masterblocknotation]);

        
if(!isset($this->tploriginal[$masterblocknotation]))
        {
            echo 
"ERROR: " $blocknotation " does not exist.";
            
$this->_debugmessage($blocknotation " does not exist.""WARNING");
        }

        
$this->_replacer($masterblocknotation);

        
$this->_resolver($blocknotation);

        
//listvar($this->tplchanged[$masterblocknotation]);
    
}

    
//resolver takes the tplchanged array and puts it into the tplprintout array
    //we do things here line by line which probably messes up multi line regexp
    //if a begin block is found, tplprintout is checked to see if we have content
    //there to append into this block for its tplprintout
    
function _resolver($blocknotation)
    {
        if(!empty(
$blocknotation))
            
$masterblocknotation "master." $blocknotation;
        else
            
$masterblocknotation "master";
        
$x 0;

        
//we should have a changed even if we have not done an assign or assignlocal
        //it is set to the original during the iniater function
        
if(!isset($this->tplchanged[$masterblocknotation]))
            return;


        
reset($this->tplchanged[$masterblocknotation]);
        while(list(
$key$val) = each($this->tplchanged[$masterblocknotation]))
        {
            if(
preg_match($this->patternstart$val$match))
            {
                
//uncomment this if you wish to keep block notation in the outgoing html
                //$this->tplprintout[$masterblocknotation][] = $val;

                
if($x >= 1)
                {
                    
//we should compare these two to make sure they are the same
                    //but we just check that the matchmaster matches what we have parsed
                    
$matchoriginal $blocknotation "." trim($match[1]);
                    
$matchmaster $masterblocknotation '.' trim($match[1]);

                    
//we do not need to do a recursive look up
                    //only need to get the sublocks that have been parsed right below this block
                    //because those sublocks should have already been passed through this function
                    //and hence should already have grabbed the sublocks below them
                    
if(isset($this->tplprintout[$matchmaster]))
                    {
                        while(list(
$key2$val2) = each($this->tplprintout[$matchmaster]))
                        {
                            
$this->tplprintout[$masterblocknotation][] = $val2;
                        }
                        
//we should probably clear out the printout array
                        //as we have pushed it up into a higher block
                        //actually this is a very convoluted problem
                        //we want to save up parses when they are sublocks
                        //but what do we want to do when we want to start over
                        //and parse main again in a prisitine state
                        //unset($this->tplprintout[$matchmaster]);
                    
}
                }

            }
            else if(
preg_match($this->patternfinish$val$match))
            {
                
//uncomment this if you wish to keep block notation in the outgoing html
                //$this->tplprintout[$masterblocknotation][] = $val;
            
}
            else
            {
                
$this->tplprintout[$masterblocknotation][] = $val;
            }
            
$x++;
        }
    }

    function 
quickprint($blocknotation)
    {
        
//listvar($this->tplprintout);
        
if(!empty($blocknotation))
            
$masterblocknotation "master." $blocknotation;
        else
            
$masterblocknotation "master";
        
//echo $masterblocknotation . "<br>\n";

        
if(!isset($this->tploriginal[$masterblocknotation]))
        {
            
//echo "ERROR: " . $blocknotation . " does not exist.";
            
$this->_debugmessage($blocknotation " does not exist.""WARNING");
        }

        if(isset(
$this->tplprintout[$masterblocknotation]))
        {
            
//if you uncomment this, you will quickprint every parse ever done
            
reset($this->tplprintout[$masterblocknotation]);
            while(list(
$key$val) = each($this->tplprintout[$masterblocknotation]))
            {
                echo 
$val;
            }
        }
    }

    function 
quicktext($blocknotation)
    {
        if(!empty(
$blocknotation))
            
$masterblocknotation "master." $blocknotation;
        else
            
$masterblocknotation "master";
        
//echo $masterblocknotation . "<br>\n";

        
if(!isset($this->tploriginal[$masterblocknotation]))
        {
            
//echo "ERROR: " . $blocknotation . " does not exist.";
            
$this->_debugmessage($blocknotation " does not exist.""WARNING");
        }

        
$quicktext "";

        if(isset(
$this->tplprintout[$masterblocknotation]))
        {
            
//if you uncomment this, you will quickprint every parse ever done
            
reset($this->tplprintout[$masterblocknotation]);
            while(list(
$key$val) = each($this->tplprintout[$masterblocknotation]))
            {
                
$quicktext .= $val;
            }
        }

        return 
$quicktext;
    }

    function 
reset($blocknotation)
    {
        if(!empty(
$blocknotation))
            
$masterblocknotation "master." $blocknotation;
        else
            
$masterblocknotation "master";
        
//echo $masterblocknotation . "<br>\n";

        
if(isset($this->tplprintout[$masterblocknotation]))
            unset(
$this->tplprintout[$masterblocknotation]);

    }

    
//additinoal debug information thanks to heather cash
    
function _debugmessage($message$level)
    {
        if(
$level == "ERROR")
            
$level 1;
        if(
$level == "WARNING")
            
$level 2;

        if(
$level $this->debug)
            return;

        switch (
$level)
        {
            case 
1:
                echo 
"ERROR: " $message "<br>\n";
                break;
            case 
2:
                echo 
"WARNING:" $message "<br>\n";
                break;
        }
    }
}

if(!
function_exists('listvar'))
{
    function 
listvar($arg)
    {
        echo 
"<pre>";
        
print_r($arg);
        echo 
"</pre>";
    }
}
?>