<?php
/*
+-----------------------------------------------------------------------------+
| $Id: bwbbcode.class.php 2009-08-18 08:02:23Z Bleakwind $
| Parse BBCODE
| Copyright (c) 2003-2010 Bleakwind (www.weaverdream.com)
| http://www.weaverdream.com/
| Release under the GNU Lesser General Public License Version 3 (LGPLv3):
|   http://www.gnu.org/licenses/lgpl.html
+-----------------------------------------------------------------------------+
*/

class bwbbcode{

    var $bw_tag             = array();
    var $bw_js_han          = "";
    var $bw_js_fun          = "";
    var $bw_serial          = 0;

    // "yes" = halt with message, "no" = ignore errors quietly, "report" = ignore errror, but spit a warning
    var $halt_on_error      = "yes";

    var $adminemail         = "Administrator";

    var $setting;

    function bwbbcode()
    {
        $this->setting = array(
            'entities_p'    => false,
            'entities_v'    => false,

            'color_bg'      => "#FFFFFF",
            'color_comment' => "#BBBBBB",
            'color_default' => "#0000BB",
            'color_html'    => "#000000",
            'color_keyword' => "#007700",
            'color_string'  => "#DD0000",
        );
        $this->set_color();
        return;
    }

    function set_color()
    {
        @ini_set("highlight.bg",        $this->setting['color_bg']);
        @ini_set("highlight.comment",   $this->setting['color_comment']);
        @ini_set("highlight.default",   $this->setting['color_default']);
        @ini_set("highlight.html",      $this->setting['color_html']);
        @ini_set("highlight.keyword",   $this->setting['color_keyword']);
        @ini_set("highlight.string",    $this->setting['color_string']);
        return;
    }

    function add_code_copyfun($str)
    {
        $this->bw_js_fun = $str;
        return;
    }

    function add_tag($pattern)
    {
        if(!preg_match("/^[a-z]{1,30}$/i", $pattern['bw_bb_name'])) {
            $this->halt("bw_bb_name error...");
        }
        if(array_key_exists($pattern['bw_bb_name'], $this->bw_tag)) {
            $this->halt("bw_bb_name[".$pattern['bw_bb_name']."] is already in use...");
        }
        if ($pattern['bw_if_value'] != "no") {
            $pattern['bw_if_value'] = "yes";
            if(!preg_match("/^[a-z<>\/]{1,255}$/i", $pattern['bw_html_end'])) {
                $this->halt("bw_html_end error...");
            }
        }
        if( $pattern['bw_if_param'] == "yes" || $pattern['bw_if_param'] == "both" ) {
            if(empty($pattern['bw_param_regex'])) {
                $pattern['bw_param_regex'] = '[^\\]]+';
            }
        } else {
            $pattern['bw_if_param'] = "no";
        }
        if(empty($pattern['bw_param_replace'])) {
            $pattern['bw_param_replace'] = array();
        }
        $this->bw_tag[$pattern['bw_bb_name']] = $pattern;
        return true;
    }

    function add_alias($name, $aliasof)
    {
        if(!array_key_exists($aliasof, $this->bw_tag) || array_key_exists($name, $this->bw_tag)) {
            return false;
        }else{
            $this->bw_tag[$name] = array('alias' => $aliasof);
            return true;
        }
    }

    function get_data($name, $alias = "")
    {
        if(!array_key_exists($name, $this->bw_tag)){
            return "";
        } else {
            $data           = $this->bw_tag[$name];
            $this_name      = $alias == "" ? $name : $alias;
            $data['bw_bb_name']   = $this_name;
            return $data;
        }
    }

    function clear_param($param, $array)
    {
        if (!empty($array)) {
            $pattern    = array_keys($array);
            $replace    = array_values($array);
            $param      = preg_replace($pattern, $replace, $param);
        }
        if($this->setting['entities_p']){
            $param = htmlentities($param);
        }
        return $param;
    }

    function clear_value($value)
    {
        if($this->setting['entities_v']){
            $value = htmlentities($value);
        }
        return $value;
    }

    function make_value($bw_html_begin, $value, $bw_html_end, $func)
    {
        $this->bw_serial++;
        $value  = str_replace("\\\"", "\"", $value);
        list($bw_html_begin, $bw_html_end)  = str_ireplace('#s#', $this->bw_serial, array($bw_html_begin, $bw_html_end));
        if (!empty($func)) {
            $value = $this->$func($value, $this->bw_serial);
        }
        return $bw_html_begin.$value.$bw_html_end;
    }

    function parse_bwbbcode($content)
    {
        $this->bw_js_han = "";
        foreach($this->bw_tag as $tag_name => $tag_data){
            if (array_key_exists('alias', $tag_data)) {
                $tag_data = $this->get_data($tag_data['alias'], $tag_name);
            }
            if( $tag_data['bw_if_param'] == "yes" || $tag_data['bw_if_param'] == "both" ) {
                $pattern = "/\\[".$tag_data['bw_bb_name']."=(".$tag_data['bw_param_regex'].")\\](.+)\\[\\/".$tag_data['bw_bb_name']."\\]/Uise";
                if ($tag_data['bw_if_value'] == "no") {
                    $replace = str_ireplace(array('#p#','#v#'),
                        array('\'.$this->clear_param(\'$1\', $tag_data[\'bw_param_replace\']).\'','\'.$this->clear_value(\'$2\').\''),
                        "'".$tag_data['bw_html_begin'].$tag_data['bw_html_end']."'");
                } else {
                    $replace = str_ireplace(array('#p#','#v#'),
                        array('\'.$this->clear_param(\'$1\', $tag_data[\'bw_param_replace\']).\'','\'.$this->clear_value(\'$2\').\''),
                        "\$this->make_value('".$tag_data['bw_html_begin']."', '\$2', '".$tag_data['bw_html_end']."', '".$tag_data['bw_value_replace']."')");
                }
                $content = preg_replace($pattern, $replace, $content);
            }
            if( $tag_data['bw_if_param'] == "no" || $tag_data['bw_if_param'] == "both" ) {
                $pattern = "/\\[".$tag_data['bw_bb_name']."\\](.+)\\[\\/".$tag_data['bw_bb_name']."\\]/Uise";
                if ($tag_data['bw_if_value'] == "no") {
                    $replace = str_ireplace(array('#p#','#v#'),
                        array('\'.$this->clear_value(\'$1\').\'','\'.$this->clear_value(\'$1\').\''),
                        "'".$tag_data['bw_html_begin'].$tag_data['bw_html_end']."'");
                } else {
                    $replace = str_ireplace(array('#p#','#v#'),
                        array('\'.$this->clear_value(\'$1\').\'','\'.$this->clear_value(\'$1\').\''),
                        "\$this->make_value('".$tag_data['bw_html_begin']."', '\$1', '".$tag_data['bw_html_end']."', '".$tag_data['bw_value_replace']."')");
                }
                $content = preg_replace($pattern, $replace, $content);
            }

        }
        if (!empty($this->bw_js_han)) {
            if (empty($this->bw_js_fun)) {
                $this->bw_js_han = "\n<script type=\"text/javascript\">\n<!-- \n$(document).ready(function() {\n".$this->bw_js_han."});\n //-->\n</script>\n";
            } else {
                $this->bw_js_han = "\n<script type=\"text/javascript\">\n<!-- \n".$this->bw_js_fun."$(document).ready(function() {\n".$this->bw_js_han."});\n //-->\n</script>\n";
                $this->bw_js_fun = "";
            }
        }
        $content = $content.$this->bw_js_han;
        return $content;
    }

    function handle_code($str, $serial)
    {
        $str_source             = $this->str_detag($str, "space,br");
        $str_highlight          = highlight_string($str_source, "1");
        $str_highlight          = preg_replace("/^\s?\<code\>\s?(\<span style\=\"color\: |\<font color\=\")".$this->setting['color_html']."\"\>(.*)(\<\/span\>|\<\/font\>)\s?\<\/code\>\s?$/is", "\$2", $str_highlight);
        $str_highlight          = preg_replace("/(\<span style\=\"color\: |\<font color\=\")\#([a-f0-9]{6})\"\>(.*)(\<\/span\>|\<\/font\>)/Uise", "\$this->handle_code_addtag('\$3', '\$2')", $str_highlight);
        $str_highlight_array    = preg_split("/\<br \/\>|\<br\>/is", $str_highlight);
        $str_highlight_count    = count($str_highlight_array);
        $result = "<ul>\n";
        for ($i = 0; $i < $str_highlight_count; $i++) {
            $result .= "<li><span style=\"color: ".$this->setting['color_html']."\">";
            $result .=  $str_highlight_array[$i];
            $result .= "</span></li>\n";
        }
        $result .= "</ul>\n";
        $this->bw_js_han .= "$('#block_code_".$serial." .block_code_title_right').bwcopyer({id: 'code_".$serial."', get: 'bbcode_code_get', ret: 'bbcode_code_ret'});\n";
        $this->bw_js_han .= "$('#block_code_".$serial." .block_code_title_right').append('<div style=\"display:none;\"><textarea style=\"width:0px;height:0px;\" id=\"code_".$serial."\"></textarea></div>');";
        $this->bw_js_han .= "xajax_bwbbcode_code_js('code_".$serial."', $('#block_code_".$serial." .block_code_content').html());\n";
        return $result;
    }

    function handle_code_addtag($str, $color)
    {
        $str        = str_replace("\\\"", "\"", $str);
        $str_array  = preg_split("/\<br \/\>|\<br\>/is", $str);
        if (is_array($str_array) && !empty($str_array)){
            foreach ($str_array as $k => $v) {
                $str_array[$k] = "<span style=\"color: #".$color."\">".$v."</span>";
            }
            $result = implode("<br />", $str_array);
        } else {
            $result = $str;
        }
        return $result;
    }

    // de tag
    function str_detag($str, $array="")
    {
        $check['space'] = "0";
        $check['br']    = "0";
        if (!empty($array)) {
            if (!is_array($array)) {
                $array = explode(",", $array);
            }
            foreach ($array as $v){
                if ($v == "space") {
                    $check['space'] = "1";
                } elseif ($v == "br") {
                    $check['br'] = "1";
                }
            }
        }
        if ($check['br'] == "1") {
            $search  = array("<br />");
            $replace = array("\n");
        }
        $search     = array_merge($search,      array("&quot;", "&#39;", "&lt;", "&gt;", "&#36;"));
        $replace    = array_merge($replace,     array("\"",     "'",    "<",     ">",    "$",));
        if ($check['space'] == "1") {
            $search  = array_merge($search,     array("&nbsp;"));
            $replace = array_merge($replace,    array(" "));
        }
        $search  = array_merge($search,         array("&amp;"));
        $replace = array_merge($replace,        array("&"));
        $str     = str_replace($search, $replace, $str);

        return $str;
    }

    // Debug of print var
    function fp($var, $type="")
    {
        $print = !empty($type) ? "var_dump" : "print_r";
        echo "\n<pre>";
        $print($var);
        echo "</pre>\n";
    }

    // error halt
    function halt($msg)
    {
        if ($this->halt_on_error != "no") {
            echo "<div style='font-family:sans-serif;font-size: 11px;'><b>Weaverdream info:</b> BBCode Error</div>\n";
            echo "<div style='width:600px;padding: 3px;background-color:#D6DFF7;border:#1151BF 1px solid;font-family:sans-serif;font-size: 11px;'>\n";
            printf("<b>Page:</b> ".$_SERVER['PHP_SELF']."<br>\n");
            printf("<b>Error:</b> %s<br>\n", $msg);
            echo "</div>\n";
            echo "<div style='font-family:sans-serif;font-size: 11px;'>You can try to <a href='javascript:location.reload()' target='_self'><font color='#1151BF' style='text-decoration:none;'>refresh</font></a> the page, if this doesn't fix the error, please contact <font color='#1151BF'>".$this->adminemail."</font> and report the error message.</div>\n";
        }

        if ($this->halt_on_error == "yes") {
            exit("<div style='font-family:sans-serif;font-size: 11px;'>BBCode halted.</div>\n");
        }
        return false;
    }
}
?>