<?php
/**
* Web Application Component Toolkit
*
* @link http://www.phpwact.org/
*
* @author Wact Development Team
* @link http://www.phpwact.org/team
*
* @copyright Copyright 2006, Jeff Moore
* @license http://opensource.org/licenses/mit-license.php MIT
*/

/**
* The source template parser is the core of the WACT template engine
*/
class Wact_Template_Compiler_Parser_Source implements Wact_Html_Sax_Handler {

    /**
    * Source template
    * @var string
    */
    private $source;

    /**
    * Initial instance of Wact_Template_Compiler_Parser_State_Component
    * @var Wact_Template_Compiler_Parser_State_Component
    */
    public $componentParsingState;

    /**
    * Initial instance of Wact_Template_Compiler_Parser_State_Literal
    * @var Wact_Template_Compiler_Parser_State_Literal
    */
    public $literalParsingState;

    /**
    * The current active state
    * @var Wact_Template_Compiler_Parser_State subclass
    */
    public $state;

    /**
    * @var Wact_Template_Compiler_Parser_TreeBuilder
    */
    public $treeBuilder;

    /**
    * Constructs SourceFileParser.
    * @param string Template source
    * @param Wact_Template_Compiler_Parser_TreeBuilder $treeBuilder
    */
    function __construct($source, $treeBuilder) {
        $this->source = $source;
        $this->treeBuilder = $treeBuilder;
    }

    /**
    * Creates Build a filter chain for pre-processing source code
    * @return HTMLParser
    */
    function buildFilterChain() {
        return $this;
    }

    /**
    * Used to parse the source template.
    * Initially invoked by the CompileTemplate function,
    * the first component argument being a Wact_Template_Compiler_Node_Root.
    * Uses the TagDictionary to spot compiler components
    * @see CompileTemplate
    * @see Wact_Template_Compiler_Node_Root
    * @param object compile time component
    * @return void
    */
    function parse($componentRoot, $publicId) {
        $context = $this->treeBuilder->getCompilingContext();

        $this->componentParsingState = new Wact_Template_Compiler_Parser_State_Component($this, $this->treeBuilder, $context);
        $this->literalParsingState = new Wact_Template_Compiler_Parser_State_Literal($this, $this->treeBuilder);
        $this->changeToComponentParsingState();

        $parser = new Wact_Html_Sax_Parser();
        $parser->setHandler($this->buildFilterChain());
        $parser->parse($this->stripPhp($this->source), $publicId);
    }

    /**
    * Remove php tokens for safety
    */
    function stripPhp($source) {
        $tokens = token_get_all($source);
        $result = '';
        foreach ($tokens as $key => $token) {
            if (is_array($token)) {
                list($t, $text, $line) = $token;
            } else {
                $t = T_CHARACTER;
                $text = $token;
                // $line same as last!  Clever huh?
            }
            if ($t == T_INLINE_HTML) {
                // pass through unmodified
                $result .= $text;
            } else {
                // Only pass the newlines so line numbers in errors are correct
                $result .= str_repeat("\n", substr_count($text, "\n"));
            }
        }
        return $result;    
    }

    /**
    * Switch to component parsing state
    * @return void
    */
    function changeToComponentParsingState() {
        $this->state = $this->componentParsingState;
    }

    /**
    * Switch to literal parsing state
    * @param string tag name marking the literal component
    * @return void
    */
    function changeToLiteralParsingState($tag) {
        $this->state = $this->literalParsingState;
        $this->state->activate($tag);
    }

    /**
    * Sax Open Handler
    */
    function startDocument(Wact_Html_Sax_Locator $locator, $encoding) {
        $this->literalParsingState->setDocumentLocator($locator);
        $this->componentParsingState->setDocumentLocator($locator);
    }

    /**
    * Sax Close Handler
    */
    function endDocument() {

    }

    /**
    * Sax Open Handler
    * @param string tag name
    * @param array attributes
    * @return void
    */
    function startElement($tag, $attrs) {
        $this->state->startElement($tag, $attrs);
    }

    /**
    * Sax Close Handler
    * @param string tag name
    * @return void
    */
    function endElement($tag) {
        $this->state->endElement($tag);
    }

    /**
    * Sax Open Handler
    * @param string tag name
    * @param array attributes
    * @return void
    */
    function emptyElement($tag, $attrs) {
        $this->state->emptyElement($tag, $attrs);
    }

    /**
    * Sax Data Handler
    * @param string text content in tag
    * @return void
    */
    function characters($text) {
        $this->state->characters($text);
    }

    /**
    * Sax XML Comment Handler
    * @param string text content in comment
    * @return void
    */
    function comment($text) {
        $this->state->comment($text);
    }

    /**
    * Sax Data Handler
    * @param string text content in tag
    * @return void
    */
    function cdata($text) {
        $this->state->cdata($text);
    }

}

?>
