<?php
# prism.inc.php
#
# 2018: 1st version author: "tamaya"
#
# License: LGPL v3
#================================

/*
 * 初期化関数：タグ設置
 * @param   none
 * @return  none
 */
function plugin_prism_init(){
    global $head_tags;

    $css_path = SKIN_DIR.'sh/prism.css';// prism.cssの場所指定
    $js_path  = SKIN_DIR.'sh/prism.js'; // prism.jsの場所指定

    $head_tags[] = <<<EOT
<link rel="stylesheet" type="text/css" media="screen" href="{$css_path}" />
<script src="{$js_path}"></script>
EOT;
}
/*
 * Inline Start / インライン書式版開始側
 * @param   string   lang    言語
 * @param   string   first line number|false    開始行（0 または falseで行数表示無効）
 * @param   string   highlight line number ハイライト情報（整数か"1-2"のようなハイフン区切り整数でハイライト。）
 * @return  string   front HTML Tag 開始側タグ
 * */
function plugin_prism_inline(){
    $args = func_get_args();
    return plugin_prism_funcs::getFrontTag($args);
}
/*
 * Inline End / インライン書式用終了側
 */
function plugin_endprism_convert(){ return "</code></pre>";}
function plugin_endprism_inline(){ return "</code></pre>";}// インライン書式だとうまくいかない場合あり・

/*
 * Block / 複数行引数利用ブロック版
 * @param   array   $args
 *          string  $args[0]  lang 言語
 *          string  $args[1]  first line number|false 開始行（0 または falseで行数表示無効）
 *          string  $args[3]~ highlight line number    ハイライト情報（整数か"1-2"のようなハイフン区切り整数でハイライト。）
 *          string  $args[]   width    括弧()内最後の引数がwを含む場合のみ適用。w=400のような表記で幅を指定
 *          string  $args[]   code コード    {{}}内のデータ
 * @return  string  output HTML
 * */
function plugin_prism_convert(){
    $args = func_get_args();
    $code = htmlspecialchars(array_pop($args), ENT_QUOTES, 'UTF-8');// 整形するコードとして最終引数を取り出し。

    //最終引数から幅を設定する
    $style  = plugin_prism_funcs::popStyleOrDefault($args);// ※リファレンス渡し

    $output = plugin_prism_funcs::getFrontTag($args).$code."</code></pre>";

    // 幅が設定されていれば適用する。
    if($style !== ''){ $output = "<div style=\"$style\">".$output."</div>"; }

    return $output;
}
/*
 * functions / 必要な関数クラス
 */
class plugin_prism_funcs{
    /*
     * 開始タグ生成
     * @param   string   lang    言語
     * @param   string   first line number|false    開始行（0 または falseで行数表示無効）
     * @param   string   highlight line number ハイライト情報（整数か"1-2"のようなハイフン区切り整数でハイライト。）
     * @return  string   front HTML Tag 開始側タグ
     * */
    static public function getFrontTag($args){
        $lang = htmlspecialchars(array_shift($args), ENT_QUOTES, 'UTF-8');// 言語を取り出し。

        // 開始行設定
        $num_mode = ' class="line-numbers"';// 行表示
        $data_start = ''; // 開始行
        $start_num = count($args)>0 ? array_shift($args) : '';// 開始行設定を取り出し。
        if($start_num === '0' || $start_num === 'false'){
            // 0行目から、またはfalseのとき、行番号表示自体を無効とする。
            $num_mode = '';
        }else if($start_num > 1){
            // 2以上の場合、当該行開始にセットする。
            $data_start = ' data-start="'.(int)$start_num.'"';
        }
        // 第1引数がそれ以外の場合、行番号ありの開始行指定なしとする。

        // 強調行設定
        $dline = ''; // 強調行
        if(count($args)>0){
            // 第3引数以降をハイライト設定にする。
            $dline = self::getHighlightLine($args);
        }
        return "<pre{$num_mode}{$data_start}{$dline}><code class=\"language-{$lang}\">";
    }
    /*
     * 最後のオプションから幅を設定。
     * @param   array  &$args  プラグイン引数自体をリファレンス渡し。
     * @return  string $style 該当しない場合は判定用に''を返す。
     */
    static public function popStyleOrDefault(array &$args){
        $style  ='';
        $style .= self::popWidthOrDefault($args);// ※リファレンス渡し
        // 取得できた場合のみさらに1つだけ取得
        if($style != ''){ $style .= self::popWidthOrDefault($args); }
        return $style;
    }
    /*
     * 最後の引数が幅指定文字列なら幅のスタイルとして取り出し。
     * @param   array  &$args  プラグイン引数自体をリファレンス。
     * @return  string $width_style 該当しない場合は判定用に''を返す。
     */
    static public function popWidthOrDefault(array &$args){
        $unit = 'px';
        $prop_name = 'width';
        $last = $args[count($args)-1];
        if(stripos($last,'w') !== false){
            list($input_prop,$width) = explode('=',str_replace(':','=', $last),2);
            array_pop($args);// 取り出したら除去
            // 数値でない場合、いくつかの不要文字列を除去
            if(!is_numeric($width)){
                if(stripos($last,'px') === false){
                    if(stripos($last,'em') !== false){
                        $unit = 'em';
                    }else if(stripos($last,'%') !== false){
                        $unit = '%';
                    }
                }
                $width = (int)str_replace(array(' ', $unit, ';'), '', $width);
            }
            if(stripos($input_prop,'max')!==false){$prop_name = 'max-width';}
            if(stripos($input_prop,'min')!==false){$prop_name = 'min-width';}
            return "{$prop_name}:{$width}{$unit};";
        }
        return '';
    }
    /*
     * 強調行設定文字列生成
     * @param   array     強調行リスト
     * @return  string    強調行指定用の属性
     * */
    static private function getHighlightLine(array $arr){
        $dline = '';
        foreach($arr as $val){
            if($val===''){continue;} // 空の引数を無視。
            if($dline!==''){ $dline.=','; }
            $dline .= $val;
        }
        if($dline!=''){
           $dline = ' data-line="'.htmlspecialchars($dline, ENT_QUOTES, 'UTF-8').'"';
        }
        return $dline;
    }
}
