<?php
/*
 * JohnCMS NEXT Mobile Content Management System (http://johncms.com)
 *
 * For copyright and license information, please see the LICENSE.md
 * Installing the system or redistributions of files must retain the above copyright notice.
 *
 * @link        http://johncms.com JohnCMS Project
 * @copyright   Copyright (C) JohnCMS Community
 * @license     GPL-3
 */

namespace Johncms;

use Psr\Container\ContainerInterface;

class Bbcode implements Api\BbcodeInterface
{
    /**
     * @var Api\ConfigInterface
     */
    protected $config;

    /**
     * @var Api\UserInterface::class
     */
    protected $user;

    /**
     * @var UserConfig
     */
    protected $userConfig;

    /**
     * @var \GeSHi
     */
    protected $geshi;

    protected $homeUrl;

    public function __invoke(ContainerInterface $container)
    {
        $this->config = $container->get(Api\ConfigInterface::class);
        $this->user = $container->get(Api\UserInterface::class);
        $this->userConfig = $this->user->getConfig();
        $this->homeUrl = $this->config['homeurl'];

        return $this;
    }

    // Обработка тэгов и ссылок
    public function tags($var)
    {
        $var = preg_replace('#@([\w\d]{2,})#si', '@<a href="../profile/$1">$1</a>', $var);
        $var = preg_replace('#\[url=(.+?)\](.+?)\[/url]#si', '<a href="$1">$2</a>', $var);
        $var = preg_replace("#(^|[\n ])([\w]+?://[^ \"\n\r\t<]*)#is", "\\1<a href=\"\\2\">\\2</a>", $var);
        $var = $this->parseTime($var);               // Обработка тэга времени
        $var = $this->highlightCode($var);           // Подсветка кода
        $var = $this->highlightBb($var);             // Обработка ссылок
        $var = $this->highlightUrl($var);            // Обработка ссылок
        $var = $this->highlightBbcodeUrl($var);      // Обработка ссылок в BBcode
        $var = $this->youtube($var);
        $var = $this->hideText($var);
        $var = $this->randomizeText($var);
        $var = $this->highlightImage($var);
        $var = $this->mp3($var);

        return $var;
    }

    public function notags($var = '')
    {
        $var = preg_replace('#@([\w\d]{2,})#si', '@<a href="../profile/$1">$1</a>', $var);
        $var = preg_replace('#\[align=(.+?)\](.+?)\[/align]#si', '$2', $var);
        $var = preg_replace('#\[size=(.+?)\](.+?)\[/size]#si', '$2', $var);
        $var = preg_replace('#\[user=(.+?)\](.+?)\[/user]#si', '$2', $var); 
        $var = preg_replace('#\[forum=(.+?)\](.+?)\[/forum]#si', '$2', $var); 
        $var = preg_replace('!\[bd=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)](.+?)\[/border]!is', '$2', $var); 
        $var = preg_replace('!\[sh=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)](.+?)\[/shadow]!is', '$2', $var); 
        $var = preg_replace('!\[font=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)](.+?)\[/font]!is', '$2', $var);
        $var = preg_replace('#\[marquee=(.+?)\](.+?)\[/marquee]#si', '$2', $var);
        $var = preg_replace('#\[color=(.+?)\](.+?)\[/color]#si', '$2', $var);
        $var = preg_replace('#\[timestamp\](.+?)\[/timestamp]#si', '$2', $var);
        $var = preg_replace('#\[code=(.+?)\](.+?)\[/code]#si', '$2', $var);
        $var = preg_replace('!\[bg=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)](.+?)\[/bg]!is', '$2', $var);
        $var = preg_replace('#\[spoiler=(.+?)\]#si', '$2', $var);
        $replace = [
            '[small]'    => '',
            '[/small]'   => '',
            '[big]'      => '',
            '[/big]'     => '',
            '[green]'    => '',
            '[/green]'   => '',
            '[red]'      => '',
            '[/red]'     => '',
            '[blue]'     => '',
            '[/blue]'    => '',
            '[b]'        => '',
            '[/b]'       => '',
            '[i]'        => '',
            '[/i]'       => '',
            '[u]'        => '',
            '[/u]'       => '',
            '[s]'        => '',
            '[/s]'       => '',
            '[quote]'    => '',
            '[/quote]'   => '',
            '[youtube]'  => '',
            '[/youtube]' => '',
            '[php]'      => '',
            '[/php]'     => '',
            '[c]'        => '',
            '[/c]'       => '',
            '[*]'        => '',
            '[/*]'       => '',
            '[code]'        => '',
            '[/code]'       => '',
            '[img]'        => '',
            '[/img]'       => '',
        ];

        return strtr($var, $replace);
    }

    /**
     * BbCode Threads
     *
     * @param string $var
     * @return string
     */
    public function threads($var)
    {
		$var = preg_replace('#\[i](.*?)\[/i]#si', '<span style="font-style:italic">$1</span>', $var);
		$var = preg_replace('#\[u](.*?)\[/u]#si', '<span style="text-decoration:underline">$1</span>', $var);
		$var = preg_replace('#\[s](.*?)\[/s]#si', '<span style="text-decoration:line-through">$1</span>', $var);
		$var = preg_replace('#\[b](.+?)\[/b]#is', '<span style="font-weight: bold">$1</span>', $var);
		$var = preg_replace('#\[red](.+?)\[/red]#is', '<span style="color:red">$1</span>', $var);
		$var = preg_replace('#\[blue](.+?)\[/blue]#is', '<span style="color:blue">$1</span>', $var);
		$var = preg_replace('#\[green](.+?)\[/green]#is', '<span style="color:green">$1</span>', $var);
		$var = preg_replace('!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)](.+?)\[/color]!is', '<span style="color:$1">$2</span>', $var);
			return $var;
}

    /**
     * BbCode Toolbar
     *
     * @param string $form
     * @param string $field
     * @return string
     */
    public function buttons($form, $field)
    {
        $colors = [
            'ffffff',
            'bcbcbc',
            '708090',
            '6c6c6c',
            '454545',
            'fcc9c9',
            'fe8c8c',
            'fe5e5e',
            'fd5b36',
            'f82e00',
            'ffe1c6',
            'ffc998',
            'fcad66',
            'ff9331',
            'ff810f',
            'd8ffe0',
            '92f9a7',
            '34ff5d',
            'b2fb82',
            '89f641',
            'b7e9ec',
            '56e5ed',
            '21cad3',
            '03939b',
            '039b80',
            'cac8e9',
            '9690ea',
            '6a60ec',
            '4866e7',
            '173bd3',
            'f3cafb',
            'e287f4',
            'c238dd',
            'a476af',
            'b53dd2',
        ];
        $font_color = '';
        $bg_color = '';

        foreach ($colors as $value) {
            $font_color .= '<a href="javascript:tag(\'[color=#' . $value . ']\', \'[/color]\'); show_hide(\'color\');" style="background-color:#' . $value . ';"></a>';
            $bg_color .= '<a href="javascript:tag(\'[bg=#' . $value . ']\', \'[/bg]\'); show_hide(\'bg\');" style="background-color:#' . $value . ';"></a>';
        }

        // Смайлы
        $smileys = !empty($this->user->smileys) ? unserialize($this->user->smileys) : [];

        if (!empty($smileys)) {
            $res_sm = '';
            $bb_smileys = '<small><a href="' . $this->homeUrl . '/help/?act=my_smilies">' . _t('Edit List', 'system') . '</a></small><br />';

            foreach ($smileys as $value) {
                $res_sm .= '<a href="javascript:tag(\':' . $value . '\', \':\'); show_hide(\'sm\');">:' . $value . ':</a> ';
            }

            /** @var Api\ToolsInterface::class $tools */
            $tools = \App::getContainer()->get(Api\ToolsInterface::class);

            $bb_smileys .= $tools->smilies($res_sm, $this->user->rights >= 1 ? 1 : 0);
        } else {
            $bb_smileys = '<small><a href="' . $this->homeUrl . '/help/?act=smilies">' . _t('Add Smilies', 'system') . '</a></small>';
        }

        // Код
        $code = [
            'php',
            'css',
            'js',
            'html',
            'sql',
            'xml',
        ];

        $codebtn = '';

        foreach ($code as $val) {
            $codebtn .= '<a href="javascript:tag(\'[code=' . $val . ']\', \'[/code]\'); show_hide(\'code\');">' . strtoupper($val) . '</a>';
        }

        $out = '<style>
.codepopup {margin-top: 3px;}
.codepopup a {
    border: 1px solid #a7a7a7;
    border-radius: 3px;
    background-color: #dddddd;
    color: black;
    font-weight: bold;
    padding: 2px 6px 2px 6px;
    display: inline-block;
    margin-right: 6px;
    margin-bottom: 3px;
    text-decoration: none;
}
</style>
            <script>
            function tag(text1, text2) {
              if ((document.selection)) {
                document.' . $form . '.' . $field . '.focus();
                document.' . $form . '.document.selection.createRange().text = text1+document.' . $form . '.document.selection.createRange().text+text2;
              } else if(document.forms[\'' . $form . '\'].elements[\'' . $field . '\'].selectionStart!=undefined) {
                var element = document.forms[\'' . $form . '\'].elements[\'' . $field . '\'];
                var str = element.value;
                var start = element.selectionStart;
                var length = element.selectionEnd - element.selectionStart;
                element.value = str.substr(0, start) + text1 + str.substr(start, length) + text2 + str.substr(start + length);
              } else {
                document.' . $form . '.' . $field . '.value += text1+text2;
              }
            }
            function show_hide(elem) {
              obj = document.getElementById(elem);
              if( obj.style.display == "none" ) {
                obj.style.display = "block";
              } else {
                obj.style.display = "none";
              }
            }
            </script>
            <a href="javascript:tag(\'[b]\', \'[/b]\')"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/bold.gif" alt="b" title="' . _t('Bold', 'system') . '" /></a>
            <a href="javascript:tag(\'[i]\', \'[/i]\')"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/italics.gif" alt="i" title="' . _t('Italic', 'system') . '" /></a>
            <a href="javascript:tag(\'[u]\', \'[/u]\')"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/underline.gif" alt="u" title="' . _t('Underline', 'system') . '" /></a>
            <a href="javascript:tag(\'[s]\', \'[/s]\')"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/strike.gif" alt="s" title="' . _t('Strike', 'system') . '" /></a>
            <a href="javascript:show_hide(\'color\');"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/color.gif" title="' . _t('Text Color', 'system') . '" alt="color" /></a>
            <a href="javascript:show_hide(\'bg\');"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/color_bg.gif" title="' . _t('Background Color', 'system') . '" alt="bg color" /></a>
					<a href="javascript:tag(\'[img=\', \']\');"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/im.gif" alt="bg image attachment" title="' . _t('Attach Image To Post', 'system') . '" /></a>
            <a href="javascript:tag(\'[left]\', \'[/left]\')"><img src="' . $this->homeUrl . '/images/bb/left.png" alt="left_align" title="' . _t('Align Text To Left', 'system') . '" border="0"/></a>
            <a href="javascript:tag(\'[center]\', \'[/center]\')"><img src="' . $this->homeUrl . '/images/bb/center.png" alt="center_align" title="' . _t('Align Text To Center', 'system') . '" border="0"/></a>
<a href="javascript:tag(\'[right]\', \'[/right]\')"><img src="' . $this->homeUrl . '/images/bb/right.png" alt="align_right" title="' . _t('Align Text To Right', 'system') . '" border="0"/></a>
            <a href="javascript:tag(\'[justify]\', \'[/justify]\')"><img src="' . $this->homeUrl . '/images/bb/justify.png" alt="justify_text" title="' . _t('Justify Text', 'system') . '" border="0"/></a>
					<a href="javascript:tag(\'[doc]\', \'[/doc]\')"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/pdf.png" width="16" height="16" alt="bg pdf" title="' . _t('Attach Pdf', 'system') . '" /></a>
            <a href="javascript:tag(\'[*]\', \'[/*]\')"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/list.gif" alt="li" title="' . _t('List', 'system') . '" /></a>
            <a href="javascript:tag(\'[spoiler=]\', \'[/spoiler]\');"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/sp.gif" alt="spoiler" title="' . _t('Spoiler', 'system') . '" /></a>
            <a href="javascript:tag(\'[quote]\', \'[/quote]\')"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/quote.gif" alt="quote" title="' . _t('Quote', 'system') . '" /></a>
            <a href="javascript:tag(\'[hide]\', \'[/hide]\')"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/hide.png" width="16" height="16"alt="hide_text" title="' . _t('Hide Text', 'system') . '" /></a>
            <a href="javascript:tag(\'[audio]\', \'[/audio]\')"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/mp3.png" alt="mp3_bb_icon" title="' . _t('Attach Mp3', 'system') . '" /></a>
            <a href="javascript:tag(\'[url=]\', \'[/url]\')"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/link.gif" alt="url" title="' . _t('URL', 'system') . '" /></a>
            <a href="javascript:show_hide(\'code\');"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/php.gif" title="' . _t('Code', 'system') . '" alt="Code" /></a>
            <a href="javascript:tag(\'[youtube]\', \'[/youtube]\')"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/youtube.gif" title="Youtube" alt="bg youtube" /></a>';

        if ($this->user->isValid()) {
            $out .= ' <a href="javascript:show_hide(\'sm\');"><img style="border: 0;" src="' . $this->homeUrl . '/images/bb/smileys.gif" alt="sm" title="' . _t('Smilies', 'system') . '" /></a><br />
                <div id="sm" style="display:none">' . $bb_smileys . '</div>';
        } else {
            $out .= '<br />';
        }
        $out .= '<div id="code" class="codepopup" style="display:none;">' . $codebtn . '</div>' .
            '<div id="color" class="bbpopup" style="display:none;">' . $font_color . '</div>' .
            '<div id="bg" class="bbpopup" style="display:none">' . $bg_color . '</div>';

        return $out;
    }

    /**
     * BbCode Mp3
     *
     * @param string $mp3
     * @return string
     */

    protected function mp3Player($mp3) {
        return '<span class="green"><audio controls><source src="' . $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['SERVER_NAME'] . '/files/mp3/' . basename($mp3) . '"></audio></span>';
    }
    
    protected function downloadMp3($mp3) 
    {
        $dir = ROOT_PATH . 'files/mp3';
        if (!is_dir($dir)) {
            mkdir($dir);
            @chmod($dir, 0777);
        } 
        
        $headers = get_headers($mp3, 1);
        $newfile = md5($mp3) . '.mp3'; // START_TIME
        
        if (!file_exists($dir . DIRECTORY_SEPARATOR . $newfile)) {
            if ($headers['Content-Type'] == 'audio/mpeg') {
                $uploadfil = new \SplFileObject($mp3, 'rb');
                $file = new \SplFileObject($dir . DIRECTORY_SEPARATOR . $newfile, 'w');
                $file->setFlags(\SplFileObject::SKIP_EMPTY);
                if ($file->flock(LOCK_EX)) { 
                    $file->ftruncate(0);
                    while (!$uploadfil->eof()) {
                        $file->fwrite($uploadfil->fgets());
                    }
                } 
                $file->flock(LOCK_UN);
            }
        }
        
        return (file_exists($dir . DIRECTORY_SEPARATOR . $newfile) ? $dir . DIRECTORY_SEPARATOR . $newfile : false);
    }
    
    protected function mp3($var) 
    {
        return preg_replace_callback(
            '#\[mp3](.+?)\[/mp3]#is',
            function ($matches) {
                $path = $this->downloadMp3(trim($matches[1]));
                return $path ? $this->mp3Player($path) : false;
            }, 
            $var,
            3
        );
    }


    /**
     * Обработка тэга [time]
     *
     * @param string $var
     * @return string
     */
    protected function parseTime($var)
    {
        $var = preg_replace_callback(
            '#\[time\](.+?)\[\/time\]#s',
            function ($matches) {
                $shift = ($this->config['timeshift'] + $this->userConfig->timeshift) * 3600;

                if (($out = strtotime($matches[1])) !== false) {
                    return date("d.m.Y / g:i:s a", $out + $shift);
                } else {
                    return $matches[1];
                }
            },
            $var
        );

        $var = preg_replace_callback(
            '#\[timestamp\](.+?)\[\/timestamp\]#s',
            function ($matches) {
                $shift = ($this->config['timeshift'] + $this->userConfig->timeshift) * 3600;

                if (($out = strtotime($matches[1])) !== false) {
                    return '<small class="gray">' . _t('New Post Added', 'system') . ': ' . date("d.m.Y / g:i:s a", $out + $shift) . '</small>';
                } else {
                    return $matches[1];
                }
            },
            $var
        );

        return $var;
    }

    /**
     * BBCode Hidden From Guest
     *
     * @param string $var
     * @return string
     */

    protected function hideText($var)
    {
        $homeurl = $this->homeUrl;
        return preg_replace_callback(
            '#\[hide\](.+?)\[\/hide\]#s',
            function ($matches) {
              if ($this->user->isValid()) {
                  return $matches[1];
              } else {
                  $showText = '<div class="quote" style="overflow: auto;"><font size="8">Text can only be viewed by members..!!</font></div>';
                  return $showText;
             }
                 },
                $var
               );
              }

    /**
     * Randomize Text Bbcode
     *
     * @param string $var
     * @return string
     */

protected function randomizeText($text)
    {
        return preg_replace_callback(
            '#\[random\](.*?)\[/random\]#si',
            function ($matches) {
             $text = explode('|', $matches['1']);
					$arr = array_rand($text);
                 return $text[$arr];
                 },
                $text
               );
              }




    /**
     * Парсинг ссылок
     * За основу взята доработанная функция от форума phpBB 3.x.x
     *
     * @param $text
     * @return mixed
     */
    protected function highlightUrl($text)
    {
        $homeurl = $this->homeUrl;

        // Обработка внутренних ссылок
        $text = preg_replace_callback(
            '#(^|[\n\t (>.])(' . preg_quote($homeurl,
                '#') . ')/((?:[a-zа-яё0-9\-._~!$&\'(*+,;=:@|]+|%[\dA-F]{2})*(?:/(?:[a-zа-яё0-9\-._~!$&\'(*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-zа-яё0-9\-._~!$&\'(*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-zа-яё0-9\-._~!$&\'(*+,;=:@/?|]+|%[\dA-F]{2})*)?)#iu',
            function ($matches) {
                return $this->urlCallback(1, $matches[1], $matches[2], $matches[3]);
            },
            $text
        );

        // Обработка обычных ссылок типа xxxx://aaaaa.bbb.cccc. ...
        $text = preg_replace_callback(
            '#(^|[\n\t (>.])([a-z][a-z\d+]*:/{2}(?:(?:[a-zа-яё0-9\-._~!$&\'(*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-zа-яё0-9.]+:[a-zа-яё0-9.]+:[a-zа-яё0-9.:]+\])(?::\d*)?(?:/(?:[a-zа-яё0-9\-._~!$&\'(*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-zа-яё0-9\-._~!$&\'(*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-zа-яё0-9\-._~!$&\'(*+,;=:@/?|]+|%[\dA-F]{2})*)?)#iu',
            function ($matches) {
                return $this->urlCallback(2, $matches[1], $matches[2], '');
            },
            $text
        );

        return $text;
    }

    private function urlCallback($type, $whitespace, $url, $relative_url)
    {
        $orig_url = $url;
        $orig_relative = $relative_url;
        $url = htmlspecialchars_decode($url);
        $relative_url = htmlspecialchars_decode($relative_url);
        $text = '';
        $chars = ['<', '>', '"'];
        $split = false;

        foreach ($chars as $char) {
            $next_split = strpos($url, $char);
            if ($next_split !== false) {
                $split = ($split !== false) ? min($split, $next_split) : $next_split;
            }
        }

        if ($split !== false) {
            $url = substr($url, 0, $split);
            $relative_url = '';
        } else {
            if ($relative_url) {
                $split = false;
                foreach ($chars as $char) {
                    $next_split = strpos($relative_url, $char);
                    if ($next_split !== false) {
                        $split = ($split !== false) ? min($split, $next_split) : $next_split;
                    }
                }
                if ($split !== false) {
                    $relative_url = substr($relative_url, 0, $split);
                }
            }
        }

        $last_char = ($relative_url) ? $relative_url[strlen($relative_url) - 1] : $url[strlen($url) - 1];

        switch ($last_char) {
            case '.':
            case '?':
            case '!':
            case ':':
            case ',':
                $append = $last_char;
                if ($relative_url) {
                    $relative_url = substr($relative_url, 0, -1);
                } else {
                    $url = substr($url, 0, -1);
                }
                break;

            default:
                $append = '';
                break;
        }

        $short_url = (mb_strlen($url) > 40) ? mb_substr($url, 0, 30) . ' ... ' . mb_substr($url, -5) : $url;

        switch ($type) {
            case 1:
                $relative_url = preg_replace('/[&?]sid=[0-9a-f]{32}$/', '', preg_replace('/([&?])sid=[0-9a-f]{32}&/', '$1', $relative_url));
                $url = $url . '/' . $relative_url;
                $text = $relative_url;
                if (!$relative_url) {
                    return $whitespace . $orig_url . '/' . $orig_relative;
                }
                break;

            case 2:
                $text = $short_url;
                if (!$this->userConfig->directUrl) {
                    $url = $this->homeUrl . '/go.php?url=' . rawurlencode($url);
                }
                break;

            case 4:
                $text = $short_url;
                $url = 'mailto:' . $url;
                break;
        }
        $url = htmlspecialchars($url);
        $text = htmlspecialchars($text);
        $append = htmlspecialchars($append);

        return $whitespace . '<a href="' . $url . '">' . $text . '</a>' . $append;
    }

    /**
     * Подсветка кода
     *
     * @param string $var
     * @return mixed
     */
    protected function highlightCode($var)
    {
        $var = preg_replace_callback('#\[php\](.+?)\[\/php\]#s', [$this, 'phpCodeCallback'], $var);
        $var = preg_replace_callback('#\[code=(.+?)\](.+?)\[\/code]#is', [$this, 'codeCallback'], $var);

        return $var;
    }

    private function phpCodeCallback($code)
    {
        return $this->codeCallback([1 => 'php', 2 => $code[1]]);
    }

    private function codeCallback($code)
    {
        $parsers = [
            'php'  => 'php',
            'css'  => 'css',
            'html' => 'html5',
            'js'   => 'javascript',
            'sql'  => 'sql',
            'xml'  => 'xml',
        ];

        $parser = isset($code[1]) && isset($parsers[$code[1]]) ? $parsers[$code[1]] : 'php';

        if (null === $this->geshi) {
            $this->geshi = new \GeSHi;
            $this->geshi->set_link_styles(GESHI_LINK, 'text-decoration: none');
            $this->geshi->set_link_target('_blank');
            $this->geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS, 2);
            $this->geshi->set_line_style('background: rgba(255, 255, 255, 0.5)', 'background: rgba(255, 255, 255, 0.35)', false);
            $this->geshi->set_code_style('padding-left: 6px; white-space: pre-wrap');
        }

        $this->geshi->set_language($parser);
        $php = strtr($code[2], ['<br />' => '']);
        $php = html_entity_decode(trim($php), ENT_QUOTES, 'UTF-8');
        $this->geshi->set_source($php);

        return '<div class="phpcode" style="overflow-x: auto">' . $this->geshi->parse_code() . '</div>';
    }

    /**
     * Обработка URL в тэгах BBcode
     *
     * @param $var
     * @return mixed
     */
    protected function highlightBbcodeUrl($var)
    {
        return preg_replace_callback('~\[url=(https?://.+?|//.+?)](.+?)\[/url]~iu',
            function ($url) {
                $home = parse_url($this->homeUrl);
                $tmp = parse_url($url[1]);

                if ($home['host'] == $tmp['host'] || $this->userConfig->directUrl) {
                    return '<a href="' . $url[1] . '">' . $url[2] . '</a>';
                } else {
                    return '<a href="' . $this->homeUrl . '/go.php?url=' . urlencode(htmlspecialchars_decode($url[1])) . '">' . $url[2] . '</a>';
                }
            },
            $var);
    }

    /**
     * Список замен для основных тегов BB-кода.
     *
     * @return array
     */
    protected function replacements()
    {
        return [
            // Жирный
            'b'       => [
                'from' => '#\[b](.+?)\[/b]#is',
                'to'   => '<span style="font-weight: bold">$1</span>',
            ],
            // Курсив
            'i'       => [
                'from' => '#\[i](.+?)\[/i]#is',
                'to'   => '<span style="font-style:italic">$1</span>',
            ],
            // Подчёркнутый
            'u'       => [
                'from' => '#\[u](.+?)\[/u]#is',
                'to'   => '<span style="text-decoration:underline">$1</span>',
            ],
            // Зачёркнутый
            's'       => [
                'from' => '#\[s](.+?)\[/s]#is',
                'to'   => '<span style="text-decoration:line-through">$1</span>',
            ],
            // Маленький шрифт
            'small'   => [
                'from' => '#\[small](.+?)\[/small]#is',
                'to'   => '<span style="font-size:x-small">$1</span>',
            ],
            // Большой шрифт
            'big'     => [
                'from' => '#\[big](.+?)\[/big]#is',
                'to'   => '<span style="font-size:large">$1</span>',
            ],
            // Красный
            'red'     => [
                'from' => '#\[red](.+?)\[/red]#is',
                'to'   => '<span style="color:red">$1</span>',
            ],
            // Зеленый
            'green'   => [
                'from' => '#\[green](.+?)\[/green]#is',
                'to'   => '<span style="color:green">$1</span>',
            ],
            // Синий
            'blue'    => [
                'from' => '#\[blue](.+?)\[/blue]#is',
                'to'   => '<span style="color:blue">$1</span>',
            ],
            // PDF file
            'doc'    => [
                'from' => '#\[doc\](.+?)\[/doc]#is',
                'to'   => '<iframe src="http://docs.google.com/gview?url=$1&embedded=true" style="width:100%;height:400px;" frameborder="0"></iframe>',
            ],
            // Textarea
            'textarea'    => [
                'from' => '#\[textarea\](.+?)\[/textarea\]#si',
                'to'   => '<textarea>' . htmlentities('\1') . '</textarea>',
            ],
            // Font
            'font'    => [
                'from' => '!\[font=([0-9a-z]+)](.+?)\[/font]!is',
                'to'   => '<span style="font-family:$1">$2</span>',
            ],
            // Button
            'button'    => [
                'from' => '#\[button](.+?)\[/button]#is',
                'to'   => '<span style="color:blue">$1</span>',
            ],
            // Subscript Text
            'sub'    => [
                'from' => '#\[sub\](.*?)\[/sub\]#si',
                'to'   => '<span style="vertical-align:sub">\1</span>',
            ],
            // Superscript Text
            'sup'    => [
                'from' => '#\[sup\](.*?)\[/sup\]#si',
                'to'   => '<span style="vertical-align:sup">\1</span>',
            ],
            // Left Align Text
            'left'    => [
                'from' => '#\[left\](.*?)\[/left\]#si',
                'to'   => '<div style="text-align:left">\1</div>',
            ],
            // Right align text
            'right'    => [
                'from' => '#\[right\](.*?)\[/right\]#si',
                'to'   => '<div style="text-align:right">\1</div>',
            ],
            // Justify Align Text
            'justify'    => [
                'from' => '#\[justify\](.*?)\[/justify\]#si',
                'to'   => '<div style="text-align:justify">\1</div>',
            ],
            // Center Align Text
            'center'    => [
                'from' => '#\[center\](.*?)\[/center\]#si',
                'to'   => '<div style="text-align:center">\1</div>',
            ],
            // Set Align
            'align'    => [
                'from' => '!\[align=(left|center|right|justify)\](.+?)\[/align]!is',
                'to'   => '<div style="text-align:$1">\1</div>',
            ],
            // Text Size
            'size'    => [
                'from' => '!\[size=(xx-small|x-small|small|medium|large|x-large|xx-large)\](.+?)\[/size\]!is',
                'to'   => '<span style="font-size:$1">$2</span>',
            ],
            // Image Fetch Url
            'img'    => [
                'from' => '#\[img]([a-zA-Z0-9\-\_\jpg|jpeg|gif|png|tif|tiff|bmp|JPG|JPEG|GIF|PNG|TIF|TIFF|BMP\[\]\/\.%]+?)\[/img]#is',
                'to'   => '<img src="http://$1"></img>',
            ],
            // Image Fetch URL With Custom Size
            'imgresize'    => [
                'from' => '#\[img=(\d{1,3}){1}x(\d{1,3}){1}\]([a-zA-Z0-9\-\_\jpg|jpeg|gif|png|tif|tiff|bmp|JPG|JPEG|GIF|PNG|TIF|TIFF|BMP\[\]\/\.%]+?)\[/img]#si',
                'to'   => '<img src="http://$3" width="$1" height="$2"></img>',
            ],
            // Shadow Text
            'sh'    => [
                'from' => '#\[sh\](.*?)\[/sh\]#si',
                'to'   => '<span style="text-shadow: 1px 3px 9px;">\1</span>',
            ],
            // Red shadow text
            'rsh'    => [
                'from' => '#\[rsh\](.*?)\[/rsh\]#si',
                'to'   => '<span style="text-shadow: 1px 3px 9px red;">\1</span>',
            ],
            // Green shadow Text
            'gsh'    => [
                'from' => '#\[gsh\](.*?)\[/gsh\]#si',
                'to'   => '<span style="text-shadow: 1px 3px 9px green;">\1</span>',
            ],
            // Orange shadow Text
            'osh'    => [
                'from' => '#\[osh\](.*?)\[/osh\]#si',
                'to'   => '<span style="text-shadow: 1px 3px 9px orange;">\1</span>',
            ],
            // Blue shadow Text
            'bsh'    => [
                'from' => '#\[bsh\](.*?)\[/bsh\]#si',
                'to'   => '<span style="text-shadow: 1px 3px 9px blue;">\1</span>',
            ],
            // Border
            'bd'    => [
                'from' => '#\[bd\](.*?)\[/bd\]#si',
                'to'   => '<span style="border: solid 2px; padding: 4px; margin: 2px;">\1</span>',
            ],
            // Line Break
            'hr'    => [
                'from' => '#\[hr\]#si',
                'to'   => '<hr style="margin: 2px;border: 0; border-bottom: 1px dotted #aaa"/>',
            ],
            // Line Break
            'br'    => [
                'from' => '#\[br\]#si',
                'to'   => '<br />',
            ],
            // Blinking Text
            'blink'    => [
                'from' => '#\[blink\](.*?)\[/blink\]#si',
                'to'   => '<div style="text-decoration:blink">\1</div>',
            ],
            // Marquee Text
            'marquee'    => [
                'from' => '#\[marquee](.+?)\[/marquee]#is',
                'to'   => '<marquee>$1</marquee>',
            ],
            // Marquee Right
            'marqueeright'    => [
                'from' => '#\[marquee=right](.+?)\[/marquee]#si',
                'to'   => '<marquee direction="right">$1</marquee>',
            ],
            // Marquee Right
            'marqueeright'    => [
                'from' => '#\[marquee=right](.+?)\[/marquee]#si',
                'to'   => '<marquee direction="right">$1</marquee>',
            ],
            // Marquee Left
            'marqueeleft'    => [
                'from' => '#\[marquee=left](.+?)\[/marquee]#is',
                'to'   => '<marquee direction="left">$1</marquee>',
            ],
            // Marquee Alternate
            'marqueealt'    => [
                'from' => '#\[marquee=alt](.+?)\[/marquee]#is',
                'to'   => '<marquee behaviour="alternate">$1</marquee>',
            ],
            // Marquee Up
            'marqueeup'    => [
                'from' => '#\[marquee=up](.+?)\[/marquee]#is',
                'to'   => '<marquee direction="up">$1</marquee>',
            ],
            // Marquee Down
            'marqueedown'    => [
                'from' => '#\[marquee=down](.+?)\[/marquee]#is',
                'to'   => '<marquee direction="down">$1</marquee>',
            ],
            // SoundCloud Code
            'soundcloud'    => [
                'from' => '#\[soundcloud](.+?)\[/soundcloud]#is',
                'to'   => '<object height="81" width="100%"><param name="movie" value="http://player.soundcloud.com/player.swf?url=$1&amp;g=bb"></param><param name="allowscriptaccess" value="always"></param><embed allowscriptaccess="always" height="81" src="http://player.soundcloud.com/player.swf?url=$1&amp;g=bb" type="application/x-shockwave-flash" width="100%"></embed></object><a href="$1">$1</a>',
            ],
            // Link to user profile
            'user'    => [
                'from' => '!\[user=([0-9a-f]+)](.+?)\[/user]!is',
                'to'   => '<a href="' . $this->homeUrl . '/profile/index.php?info=$1">$2</a>',
            ],
            //mp3
            'audio' => [
                'from' => '#\[audio](.+?)\[/audio]#is',
                'to' => '<p align="left"><span class="green"><audio controls><source src="$1"></audio></span></p>',
            ],
            // Link To Forum Post
            'forum'    => [
                'from' => '!\[forum=([0-9a-f]+)](.+?)\[/forum]!is',
                'to'   => '<a href="' . $this->homeUrl. '/forum/index.php?id=$1">$2</a>',
            ],
            // Цвет шрифта
            'color'   => [
                'from' => '!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)](.+?)\[/color]!is',
                'to'   => '<span style="color:$1">$2</span>',
            ],
            // Цвет фона
            'bg'      => [
                'from' => '!\[bg=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)](.+?)\[/bg]!is',
                'to'   => '<span style="background-color:$1">$2</span>',
            ],
            // Цитата
            'quote'   => [
                'from' => '#\[(quote|c)](.+?)\[/(quote|c)]#is',
                'to'   => '<div class="bbcode_container"><div class="bbcode_quote"><div class="quote_container"><div class="bbcode_quote_container"></div>$2</div></div></div>',
            ],
            // Список
            'list'    => [
                'from' => '#\[\*](.+?)\[/\*]#is',
                'to'   => '<span class="bblist">$1</span>',
            ],
            // Спойлер
            'customspoiler' => [
                'from' => '#\[spoiler=(.+?)](.+?)\[/spoiler]#is',
                'to'   => '<div><div class="spoilerhead" style="cursor:pointer;" onclick="var _n=this.parentNode.getElementsByTagName(\'div\')[1];if(_n.style.display==\'none\'){_n.style.display=\'\';}else{_n.style.display=\'none\';}">$1 (+/-)</div><div class="spoilerbody" style="display:none">$2</div></div>',
            ],
            // Спойлер
            'spoiler' => [
                'from' => '#\[spoiler\](.*?)\[\/spoiler\]#is',
                'to'   => '<div><div class="spoilerhead" style="cursor:pointer;" onclick="var _n=this.parentNode.getElementsByTagName(\'div\')[1];if(_n.style.display==\'none\'){_n.style.display=\'\';}else{_n.style.display=\'none\';}">Click To View Contents</div><div class="spoilerbody" style="display:none">$1</div></div>',
            ],
        ];
    }

    /**
     * Обработка bbCode
     *
     * @param string $var
     * @return string
     */
    protected function highlightBb($var)
    {
        $replacements = array_values($this->replacements());
        $search = array_column($replacements, 'from');
        $replace = array_column($replacements, 'to');

        return preg_replace($search, $replace, $var);
    }

    /**
     * BBCode Images
     *
     * @param string $var
     * @return string
     */

    protected function highlightImage($var)
    {
        $homeurl = $this->homeUrl;
        return preg_replace_callback(
            '#\[img=([0-9]+)_([0-9]{3})\]#s',
            function ($matches) {
             $name = $matches[1] . '_' . $matches[2];
             $file = $homeurl . '/files/images/' . $name . '_preview.jpg';
            if (file_exists(ROOT_PATH . 'files/images/' . $name . '_preview.jpg')) {
                 return '<a href="' . $homeurl . '/files/images/'.$name.'.jpg" class="lightbox" title="'.$name.'"><img itemprop="image" src="'.$file.'" border="0" style="max-width:90%; height: auto;" target="_blank" alt="Removed"></a>';
               } else {
                 return '<b>[<span style="color:red">Image Removed</span>]</b>';
                  }
                 },
                $var
               );
              }

    /**
     * BBCode Adepeter
     *
     * @param string $var
     * @return string
     */

				public function adepeter($var = '') {
			$var = preg_replace('#\[color=(.+?)\](.+?)\[/color]#si', '$2', $var);
			$var = preg_replace('{\[hide\](.*?)\[/hide\]}si','',$var);
			$var = preg_replace('!\[bg=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)](.+?)\[/bg]!is', '$2', $var);
        $replace = [
            '[img]'    => '',
            '[/img]'   => '',
            '[youtube]'      => '',
            '[/youtube]'     => '',
            '[spoiler]'    => '',
            '[/spoiler]'   => '',
            '[thank]'        => '',
            '[/thank]'       => '',
        ];

        return strtr($var, $replace);
    }



    /**
     * Youtube bbcode
     *
     * @param string $var
     * @return string
     */
    protected function youtube($var)
    {
        return preg_replace_callback(
            '#\[youtube\](.+?)\[\/youtube\]#s',
            function ($matches) {
                if (preg_match('/youtube.com/', $matches[1])) {
                    $values = explode('=', $matches[1]);
                    $valuesto = explode('&', $values[1]);

                    return $this->youtubePlayer($valuesto[0]);
                } elseif (preg_match('/youtu.be/', $matches[1])) {
                    return $this->youtubePlayer(trim(parse_url($matches[1])['path'], '//'));
                } else {
                    $valuesto = explode('&', $matches[1]);

                    return $this->youtubePlayer($valuesto[0]);
                }
            },
            $var, 3
        );
    }

    protected function youtubePlayer($result)
    {
        if ($this->userConfig->youtube) {
            return '
<style>.video-container {
	position:relative;
	padding-bottom:56.25%;
	padding-top:30px;
	height:0;
	overflow:hidden;
}
.video-container iframe, .video-container object, .video-container embed {
	position:absolute;
	top:0;
	left:0;
	width:100%;
	height:100%;
}
</style>
<div style="max-width: 500px">
<div class="video-container">
<iframe allowfullscreen="allowfullscreen" src="//www.youtube.com/embed/' . $result . '" frameborder="0"></iframe>
</div></div>';
        } else {
            return '<div><a target="_blank" href="//m.youtube.com/watch?v=' . $result . '"><img src="//img.youtube.com/vi/' . $result . '/1.jpg" border="0" alt="youtube.com/embed/' . $result . '"></a></div>';
        }
    }
}
