<?php
// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
/**
 * Default: Parses for smileys / emoticons tags
 *
 * This class implements a Text_Wiki_Rule to find source text marked as
 * smileys defined by symbols as ':)' , ':-)' or ':smile:'
 * The symbol is replaced with a token.
 *
 * PHP versions 4 and 5
 *
 * @category   Text
 * @package    Text_Wiki
 * @author     Bertrand Gugger <bertrand@toggg.com>
 * @copyright  2005 bertrand Gugger
 * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
 * @version    CVS: $Id$
 * @link       http://pear.php.net/package/Text_Wiki
 */

/**
 * Smiley rule parser class for Default.
 *
 * @category   Text
 * @package    Text_Wiki
 * @author     Bertrand Gugger <bertrand@toggg.com>
 * @copyright  2005 bertrand Gugger
 * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
 * @version    Release: @package_version@
 * @link       http://pear.php.net/package/Text_Wiki
 * @see        Text_Wiki_Parse_Default::Text_Wiki_Parse_Default()
 */
class Text_Wiki_Parse_Default_Smiley extends Text_Wiki_Parse {

    /**
     * Configuration keys for this rule
     * 'smileys' => array Smileys recognized by this rule, symbols key definitions:
     *              'symbol' => array ( 'name', 'description' [, 'variante', ...] ) as
     *                  ':)'  => array('smile', 'Smile'),
     *                  ':D'  => array('biggrin', 'Very Happy',':grin:'),
     *              the eventual elements after symbol and description are variantes
     *
     * 'auto_nose' => boolean enabling the auto nose feature:
     *                auto build a variante for 2 chars symbols by inserting a '-' as ':)' <=> ':-)'
     *
     * @access public
     * @var array 'config-key' => mixed config-value
     */
    var $conf = array(
        "smileys" => array(
            ":D"        => array("biggrin", "Very Happy", ":grin:"),
            ":)"        => array("smile", "Smile", "(:"),
            ":("        => array("sad", "Sad", "):"),
            ":o"        => array("surprised", "Surprised", ":eek:", "o:"),
            ":shock:"   => array("eek", "Shocked"),
            ":?"        => array("confused", "Confused", ":???:"),
            "8)"        => array("cool", "Cool", "(8"),
            ":lol:"     => array("lol", "Laughing"),
            ":x"        => array("mad", "Mad"),
            ":P"        => array("razz", "Razz"),
            ":oops:"    => array("redface", "Embarassed"),
            ":cry:"     => array("cry", "Crying or Very sad"),
            ":evil:"    => array("evil", "Evil or Very Mad"),
            ":twisted:" => array("twisted", "Twisted Evil"),
            ":roll:"    => array("rolleyes", "Rolling Eyes"),
            ";)"        => array("wink", "Wink", "(;"),
            ":!:"       => array("exclaim", "Exclamation"),
            ":?:"       => array("question", "Question"),
            ":idea:"    => array("idea", "Idea"),
            ":arrow:"   => array("arrow", "Arrow"),
            ":|"        => array("neutral", "Neutral", "|:"),
            ":mrgreen:" => array("mrgreen", "Mr. Green"),
        ),
        "auto_nose" => true
    );

    /**
     * Definition array of smileys, variantes references their model
     * 'symbol' => array ( 'name', 'description')
     *
     * @access private
     * @var array 'config-key' => mixed config-value
     */
    var $_smileys = array();

     /**
     * Constructor.
     * We override the constructor to build up the regex from config
     *
     * @param object &$obj the base conversion handler
     * @return object The parser object
     * @access public
     */
    function __construct(&$obj)
    {
        $default = $this->conf;
        parent::__construct($obj);

        // read the list of smileys to sort out variantes and :xxx: while building the regexp
        $this->_smileys = $this->getConf("smileys", $default["smileys"]);
        $autoNose = $this->getConf("auto_nose", $default["auto_nose"]);
        $reg1 = $reg2 = "";
        $sep1 = ":(?:";
        $sep2 = "";
        foreach ($this->_smileys as $smiley => $def) {
            for ($i = 1; $i < count($def); $i++) {
                if ($i > 1) {
                    $cur = $def[$i];
                    $this->_smileys[$cur] = &$this->_smileys[$smiley];
                } else {
                    $cur = $smiley;
                }
                $len = strlen($cur);
                if (($cur[0] == ":") && ($len > 2) && ($cur[$len - 1] == ":")) {
                    $reg1 .= $sep1 . preg_quote(substr($cur, 1, -1), "#");
                    $sep1 = "|";
                    continue;
                }
                if ($autoNose && ($len === 2)) {
                    $variante = $cur[0] . "-" . $cur[1];
                    $this->_smileys[$variante] = &$this->_smileys[$smiley];
                    $cur = preg_quote($cur[0], "#") . "-?" . preg_quote($cur[1], "#");
                } else {
                    $cur = preg_quote($cur, "#");
                }
                $reg2 .= $sep2 . $cur;
                $sep2 = "|";
            }
        }
        $delim = '[\n\r\s' . $this->wiki->delim . "$^]";
        $this->regex = "#(?<=" . $delim .
             ")(" . ($reg1 ? $reg1 . "):" . ($reg2 ? "|" : "") : "") . $reg2 .
             ")(?=" . $delim . ")#i";
    }

    /**
     * Constructor.
     * We override the constructor to build up the regex from config
     *
     * @param object &$obj the base conversion handler
     * @return object The parser object
     * @access public
     */
    function Text_Wiki_Parse_Default_Smiley(&$obj)
    {
        return self::__construct($obj);
    }

    /**
     * Generates a replacement token for the matched text.  Token options are:
     *     'symbol' => the original marker
     *     'name' => the name of the smiley
     *     'desc' => the description of the smiley
     *
     * @param array &$matches The array of matches from parse().
     * @return string Delimited token representing the smiley
     * @access public
     */
    function process(&$matches)
    {
        // tokenize
        return $this->wiki->addToken($this->rule,
            array(
                "symbol" => $matches[1],
                "name"   => $this->_smileys[$matches[1]][0],
                "desc"   => $this->_smileys[$matches[1]][1]
            ));
    }
}