<?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
*/

/**
*/
class Wact_Template_Compiler implements Wact_Template_Compiler_Context {

    protected $loader;
    protected $reader;

    /**
    * @var Wact_Plugin_Loader
    */
    protected $tagLoader;

    /**
    * @var array
    */
    protected $tagInfo = array();

    /**
    * @var Wact_Plugin_Loader
    */
    protected $formatterLoader;

    /**
    * @var array
    */
    protected $formatterInfo = array();

    /**
    */
    public function __construct($loader, $reader) {
        $this->loader = $loader;
        $this->reader = $reader;
        $this->tagLoader = new Wact_Plugin_Loader('.tag.php');
        $this->tagLoader->addPath('Wact/Template/tag', 'Wact_Template_Tag');
        $this->formatterLoader = new Wact_Plugin_Loader('.formatter.php');
        $this->formatterLoader->addPath('Wact/Template/formatter', 'Wact_Template_Formatter');
    }

    /**
    */
    protected function generateTemplate($resourceId, $class, $source, $baseClass = null) {
        $code = new Wact_Php_Writer();

        $tree = new Wact_Template_Compiler_Node_Root(NULL, NULL, new Wact_Template_Compiler_Location($resourceId, 0), $class);
        if (!is_null($baseClass)) {
            $tree->parentViewClass = $baseClass;
        }

        $treeBuilder = new Wact_Template_Compiler_Parser_TreeBuilder($this);
        $treeBuilder->parseSource($source, $tree, $resourceId);

//        $debugger = new Wact_Template_Compiler_Node_Debug($tree);
//        $debugger->dump();
        
        $tree->prepare();

        $tree->generateConstructMethod($code);

        $tree->generatePaintMethod($code);

        return $code->getCode();
    }

    /**
    * Compile a resource and store it into our cache
    */
    public function compile($resourceId, $cache, $cacheId, $class, $baseClass) {
        $data = $this->readSource($resourceId);
        if (!$data) {
            throw new Wact_Template_Compiler_Exception('Cannot read resource "{ResourceId}"', $resourceId);
        }

        $code = $this->generateTemplate($resourceId, $class, $data, $baseClass);
//        highlight_string($code);
        $cache->store($cacheId, $code);
    }

    /**
    * @return WactSourceReader
    */
    public function getSourceReader() {
        return $this->reader;
    }


    /**
    */
    public function getTagPluginName($tag) {
        return str_replace(':', DIRECTORY_SEPARATOR, strtolower($tag));
    }

    /**
    */
    public function getTagInfo($tag) {
        $name = $this->getTagPluginName($tag);
        if (!isset($this->tagInfo[$name])) {
            $pluginclass = $this->tagLoader->load($name);
            if ($pluginclass) {
                $this->tagInfo[$name] = new Wact_Template_Compiler_Tag_Info($pluginclass);
            } else {
                $this->tagInfo[$name] = FALSE;
            }
        }
        return $this->tagInfo[$name];
    }


    /**
    */
    public function getFormatterPluginName($name) {
        return str_replace(':', DIRECTORY_SEPARATOR, strtolower($name));
    }
    
    /**
    */
    public function getFormatterInfo($formatter) {
        $name = $this->getFormatterPluginName($formatter);
        if (!isset($this->formatterInfo[$name])) {
            $pluginclass = $this->formatterLoader->load($name);
            if ($pluginclass) {
                $this->formatterInfo[$name] = new Wact_Template_Compiler_Formatter_Info($pluginclass);
            } else {
                $this->formatterInfo[$name] = FALSE;
            }
        }
        return $this->formatterInfo[$name];
    }

    /**
    * @param string $resourceId Resource ID
    */
    public function readSource($resourceId) {
        $source = $this->reader->readSource($resourceId);
        if (is_null($source)) {
            throw new Wact_Template_Exception_NotFound($resourceId);
        } else {
            return $source;
        }
    }
}

?>