<?php
/**
 * An implementation of the article text renderer.
 *
 * @package koubel homepage
 * @author Miroslav Kubelik (koubel@volny.cz)
 * @copyright Copyright (c) 2007-2009 Miroslav Kubelik
 * @license http://opensource.org/licenses/gpl-license.php GNU GPL
 */

/**
 * Article text renderer helper. 
 * 
 * Produces the XHTML markup for the article text. A text in the database can 
 *  be in wiki markup or in XHTML. Caching support included.   
 * 
 * @package koubel homepage
 * @author Miroslav Kubelik (koubel@volny.cz)
 * @copyright Copyright (c) 2007-2009 Miroslav Kubelik
 * @license http://opensource.org/licenses/gpl-license.php GNU GPL
 */ 
class HomeWebApp_View_Helper_TextRenderer
{
    /** wiki parser is lazy initialized
     * @var WikiText_Parser
     */
    private $_wikiParser;

    /** 
     * cache object
     * @var Zend_Cache_Core
     * @see HomeWebApp::$_cache      
     */ 
    private $_cache;

    public function __construct()
    {
        $this->_cache = Zend_Controller_Front::getInstance()
            ->getParam('bootstrap')
            ->getResource('cache');
    }

    /**
     * Main helper function
     *
     * @param Blog_Model_Article $article article with the text
     * @param bool $firstParaGraph if we want only first html paragraph (for list pages)
     * @param bool $useCache use article html caching
     * 
     * @return string xhtml for the article or the first paragraph
     */      
    public function textRenderer(Blog_Model_Article $article, $firstParaGraph = false,
        $useCache = true)
    {
        //id for the cache entry, can be null if the $article hasn't article id
        //e.g. when we call this helper via ajax for article text preview 
        $htmlCacheId = $article->getHTMLCacheId();

        if ($useCache && $htmlCacheId) {
            if ($htmlText = $this->_cache->load($htmlCacheId)) {
                //cache catched
            } else {
                //cache miss, so me make html output for the article text
                $htmlText=$this->_getHTMLText($article);
                //save into the cache, one week lifetime  
                $this->_cache->save($htmlText,null,array(),3600*60*7);
            }
        } else {
            //caching is not possible
            $htmlText=$this->_getHTMLText($article);
        }

        return $firstParaGraph ? Blog_Model_Article::getFirstParagraph($htmlText) : $htmlText;
    }

    private function _getHTMLText(Blog_Model_Article $article)
    {
        if ($article->getFormat() == Blog_Model_Dao_Article::FORMAT_WIKI) {
            return $this->_renderWikitoHTML($article->getText());
        } else {
            return Blog_Model_Article::escapeCode($article->getText());
        }
    } 

    private function _getWikiParser()
    {
        if (!isset($this->_wikiParser)) {
            $this->_initParser();
        }

        return $this->_wikiParser;
    }

    /**
     * Initializes wiki parser
     * @see Article::$_wikiParser 
     */
    private function _initParser()
    {
        //Create the parser
        $parser = new WikiText_Parser();

        // Add the Handler
        $parser->setHandler(new WikiText_Handler());

        //add modes to parser

        //add default modes
        $parser->addMode('listblock',new WikiText_Parser_Mode_ListBlock());
        $parser->addMode('preformatted',new WikiText_Parser_Mode_PreFormatted());
        $parser->addMode('unformatted',new WikiText_Parser_Mode_UnFormatted());
        $parser->addMode('header',new WikiText_Parser_Mode_Header());
        $parser->addMode('table',new WikiText_Parser_Mode_Table());
        $parser->addMode('linebreak',new WikiText_Parser_Mode_LineBreak());
        $parser->addMode('footnote',new WikiText_Parser_Mode_FootNote());
        $parser->addMode('externallink',new WikiText_Parser_Mode_ExternalLink());
        $parser->addMode('html',new WikiText_Parser_Mode_Html());
        $parser->addMode('quote',new WikiText_Parser_Mode_Quote());
        $parser->addMode('code',new WikiText_Parser_Mode_Code());
        $parser->addMode('internallink',new WikiText_Parser_Mode_InternalLink());
        $parser->addMode('emaillink',new WikiText_Parser_Mode_EmailLink());
        $parser->addMode('media',new WikiText_Parser_Mode_Media());
        $parser->addMode('eol',new WikiText_Parser_Mode_Eol());

        //add formatting modes
        $parser->addMode('strong',new WikiText_Parser_Mode_Formatting('strong'));
        $parser->addMode('emphasis',new WikiText_Parser_Mode_Formatting('emphasis'));
        $parser->addMode('underline',new WikiText_Parser_Mode_Formatting('underline'));
        $parser->addMode('monospace',new WikiText_Parser_Mode_Formatting('monospace'));
        $parser->addMode('subscript',new WikiText_Parser_Mode_Formatting('subscript'));
        $parser->addMode('superscript',new WikiText_Parser_Mode_Formatting('superscript'));
        $parser->addMode('deleted',new WikiText_Parser_Mode_Formatting('deleted'));

        //add modes which need files
        $parser->addMode('smiley',new WikiText_Parser_Mode_Smiley());
        $parser->addMode('acronym',new WikiText_Parser_Mode_Acronym());
        $parser->addMode('entity',new WikiText_Parser_Mode_Entity());

        //print_r($parser->modes);
        $this->_wikiParser=$parser;
    } 

    /**
     * Renders wiki text as the Xhtml markup.
     * Uses dokuwiki based parser, lexer, handler and renderer.
     * @see http://wiki.splitbrain.org/wiki:parser for nice documentation
     * @param string $wikiText the text with a wiki markup, that will be translated
     * to the xhtml, must be in the utf-8
     * @return string xhtml that is corresponded with $wikiText
     */
    private function _renderWikitoHTML($wikiText)
    {
        //clear handler calls. necessary, because parser is persistent
        $this->_getWikiParser()->getHandler()->reset();

        $instructions = $this->_getWikiParser()->parse($wikiText);

        $renderer = new WikiText_Renderer_Xhtml();
        $renderer->setBaseUrl(MKLib_AppBaseUrl::getBaseUrl());

        // Loop through the instructions
        foreach ( $instructions as $instruction ) {
            // Execute the callback against the Renderer
            call_user_func_array(array($renderer, $instruction[0]),$instruction[1]);
        }

        //return the output, no iconv needed, because our output encoding is utf-8
        return $renderer->getOutput();
    }
}
