<?php
/**
* @package   Gridbox
* @author    Balbooa http://www.balbooa.com/
* @copyright Copyright @ Balbooa
* @license   http://www.gnu.org/licenses/gpl.html GNU/GPL
*/

namespace Balbooa\Plugin\System\Gridbox\Extension;

use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Cache\Cache;
use Joomla\CMS\Language\Text;
use Joomla\CMS\User\UserHelper;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Profiler\Profiler;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\String\PunycodeHelper;
use Balbooa\Component\Gridbox\Site\Helper\GridboxHelper;

defined('_JEXEC') or die;
 
class Gridbox extends CMSPlugin
{
    public $cache;
    public $performance;
    public $dispatcher;

    public function __construct($subject, $config)
    {
        $this->dispatcher = $subject;
        parent::__construct($subject, $config);
        $app = Factory::getApplication();
        if (!$app->isClient('site')) {
            return;
        }
        $this->checkUserSubscription();
        $this->performance = GridboxHelper::getPerformance();
        if ($this->performance->page_cache != 1) {
            return;
        }
        $options = [
            'defaultgroup' => 'gridbox',
            'browsercache' => $this->performance->browser_cache,
            'caching' => false,
        ];
        $this->cache = Cache::getInstance('page', $options);
    }

    public function checkUserSubscription()
    {
        $user = Factory::getUser();
        if (empty($user->id)) {
            return;
        }
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('*')
            ->from('#__gridbox_store_subscriptions')
            ->where('user_id = '.$user->id);
        $db->setQuery($query);
        $subscriptions = $db->loadObjectList();
        if (count($subscriptions) == 0) {
            return;
        }
        $addGroups = [];
        $removeGroups = [];
        foreach ($subscriptions as $subscription) {
            $user_groups = json_decode($subscription->user_groups);
            $status = empty($subscription->expires) || date('Y-m-d H:i:s') < $subscription->expires;
            $query = $db->getQuery(true)
                ->select('d.subscription')
                ->from('#__gridbox_pages AS p')
                ->leftJoin('#__gridbox_store_product_data AS d ON p.id = d.product_id')
                ->where('p.id = '.$subscription->product_id);
            $db->setQuery($query);
            $page = $db->loadObject();
            if (!$page) {
                $status = false;
            } else {
                $obj = json_decode($page->subscription);
                $update = false;
                $remove = [];
                foreach ($user_groups as $group) {
                    if (!in_array($group, $obj->groups) ||
                        ($obj->action == 'products' && $subscription->action != 'products')) {
                        $update = true;
                        $remove[] = $group;
                    }
                }
                foreach ($obj->groups as $group) {
                    if (!in_array($group, $user_groups) && $obj->action != 'products') {
                        $update = true;
                        break;
                    }
                }
                foreach ($remove as $group) {
                    UserHelper::removeUserFromGroup($user->id, $group);
                }
                if ($update) {
                    $user_groups = $obj->groups;
                    $subscription->user_groups = json_encode($user_groups);
                    $subscription->action = $obj->action;
                    $db->updateObject('#__gridbox_store_subscriptions', $subscription, 'id');
                }
            }
            if ($subscription->action == 'products') {
                continue;
            }

            
            $removeGroups = [];
            foreach ($user_groups as $group) {
                if ($status) {
                    $addGroups[] = (int)$group;
                } else {
                    $removeGroups[] = (int)$group;
                }
            }
        }
        foreach ($addGroups as $group) {
            if (!isset($user->groups[$group])) {
                UserHelper::addUserToGroup($user->id, $group);
            }
        }
        foreach ($removeGroups as $group) {
            if (isset($user->groups[$group]) && !in_array($group, $addGroups)) {
                UserHelper::removeUserFromGroup($user->id, $group);
            }
        }
    }

    protected function getCacheKey()
    {
        static $key;

        if (!$key) {
            $parts[] = Uri::getInstance()->toString();
            $key = md5(serialize($parts));
        }

        return $key;
    }

    public function onUserAfterLogin($options)
    {
        $app = Factory::getApplication();
        if (!$app->isClient('administrator')) {
            return;
        }
        setcookie('gridbox_username', $options['user']->username, 0, '/');
        $this->dashboardLogin();
    }

    public function dashboardLogin()
    {
        $dashboard_api = GridboxHelper::getGridboxApi('dashboard');
        if (!$dashboard_api) {
            return;
        }
        $dashboard = json_decode($dashboard_api->key);
        if (!$dashboard->settings->redirect) {
            return;
        }
        header('Location: index.php?option=com_gridbox');
        exit;
    }

    public function onAfterRoute()
    {
        $app = Factory::getApplication();
        $doc = Factory::getDocument();
        $pageTitle = $doc->getTitle();
        $view = $app->input->getCmd('view', '');
        $option = $app->input->getCmd('option', '');
        $task = $app->input->getCmd('task', '');
        $user = Factory::getUser();
        if (!$app->isClient('site')) {
            return;
        }
        GridboxHelper::checkURI();
        GridboxHelper::checkGridboxLoginData();
        if ($doc->getType() == 'html' && !str_contains($pageTitle, 'Gridbox Editor')
            && $view != 'gridbox'
            && $this->performance->page_cache == 1 && $user->get('guest')) {
            PluginHelper::importPlugin('pagecache');
            $results = $app->triggerEvent('onPageCacheSetCaching');
            $caching = !in_array(false, $results, true);
            if ($caching && $app->input->getMethod() == 'GET') {
                $this->cache->setCaching(true);
            }
            $data = $this->cache->get($this->getCacheKey(), 'gridbox');
            if ($data !== false) {
                $app->setBody($data);
                echo $app->toString();
                if (JDEBUG) {
                    Profiler::getInstance('Application')->mark('afterCache');
                }
                $app->close();
            }
        }
        if ($option == 'com_gridbox' && empty($task)) {
            $app->setTemplate('gridbox');
        }
    }

    public function onAfterRespond()
    {
        /**
         * @var Joomla\CMS\Application\SiteApplication
         */
        $app = Factory::getApplication();
        $doc = Factory::getDocument();
        $pageTitle = $doc->getTitle();
        $view = $app->input->get('view');
        if (!$app->isClient('site') || $doc->getType() != 'html'
            || strpos($pageTitle, 'Gridbox Editor') !== false || $view == 'gridbox') {
            return;
        }
        $user = Factory::getUser();
        if ($this->performance->page_cache != 1 || !$user->get('guest')) {
            return;
        }
        $data = $app->toString();
        $data = str_replace('<html ', '<html data-cached="true" ', $data);
        $this->cache->store($data, $this->getCacheKey(), 'gridbox');
    }

    public function dashboardNavigation()
    {
        $dashboard_api = GridboxHelper::getGridboxApi('dashboard');
        if (!$dashboard_api) {
            return;
        }
        $dashboard = json_decode($dashboard_api->key);
        if (!$dashboard->settings->navigation) {
            return;
        }
        /**
         * @var \Joomla\CMS\Application\SiteApplication
         */
        $app = Factory::getApplication();
        $html = $app->getBody();
        $html = str_replace('<body', '<body data-navigation="hidden"', $html);
        $app->setBody($html);
    }

    public function adminSidebar()
    {
        /**
         * @var \Joomla\CMS\Application\SiteApplication
         */
        $app = Factory::getApplication();
        $sidebar = $app->input->cookie->get('gridbox-sidebar', '', 'string');
        if ($sidebar != 'visible') {
            return;
        }
        $html = $app->getBody();
        $html = str_replace('<body', '<body data-sidebar="visible"', $html);
        $app->setBody($html);
    }

    public function onAfterRenderAdmin()
    {
        /**
         * @var \Joomla\CMS\Application\SiteApplication
         */
        $app = Factory::getApplication();
        $doc = Factory::getDocument();
        $option = $app->input->get('option');
        if (!$app->isClient('administrator') || $doc->getType() != 'html'
            || $option != 'com_gridbox') {
            return;
        }
        $this->dashboardNavigation();
        $this->adminSidebar();
    }

    public function onAfterRenderSite()
    {
        $app = Factory::getApplication();
        $doc = Factory::getDocument();
        $view = $app->input->get('view', '');
        $option = $app->input->get('option', '');
        $pageTitle = $doc->getTitle();
        if (!$app->isClient('site') || $doc->getType() != 'html') {
            return;
        }
        $app->getDispatcher()->dispatch('onBeforeRenderGridbox');
        $this->addMetaData();
        $this->protectEmails($view, $option, $pageTitle);
        $this->setMicrodata($view, $option);
        $this->fixSmartSearch($view, $option);
        $this->loadIcons($view, $pageTitle);
        $this->initItems($view);
        $this->compressGridbox($view, $option, $pageTitle);
        $this->clearScriptType($view, $pageTitle);
        $app->getDispatcher()->dispatch('onAfterRenderGridbox');
        $this->loadCSS($view, $option);
    }

    public function loadCSS($view, $option)
    {
        $app = Factory::getApplication();
        $body = $app->getBody();
        $css = GridboxHelper::loadUsedCSS($body, $view, $option);
        $body = str_replace('[gridbox-plugins-css]', $css, $body);
        $app->setBody($body);
    }

    public function clearScriptType($view, $pageTitle)
    {
        if ($view == 'gridbox' || str_contains($pageTitle, 'Gridbox Editor')) {
            return;
        }
        $app = Factory::getApplication();
        $body = $app->getBody();
        $body = str_replace(' type="text/javascript"', '', $body);
        $app->setBody($body);
    }

    public function compressGridbox(string $view, string $option, string $pageTitle): void
    {
        $app = Factory::getApplication();
        $tmpl = $app->input->get('tmpl');

        if ($option != 'com_gridbox') return;
        if ($view == 'gridbox') return;
        if (str_contains($pageTitle, 'Gridbox Editor')) return;
        if ($tmpl == 'component') return;
        if (!$this->shouldCompress()) return;

        $body = $app->getBody();
        $body = GridboxHelper::compressGridbox($body);
        $app->setBody($body);
    }

    protected function shouldCompress(): bool
    {
        $p = $this->performance;

        return $p->compress_css == 1
            || $p->compress_js == 1
            || $p->compress_html == 1
            || $p->compress_images == 1
            || $p->adaptive_images == 1
            || $p->defer_loading == 1
            || $p->images_lazy_load == 1
            || $p->enable_canonical == 1;
    }
    
    public function initItems($view)
    {
        if ($view == 'gridbox') {
            return;
        }
        $app = Factory::getApplication();
        $body = $app->getBody();
        $str = GridboxHelper::initItems($body);
        if (empty($str)) {
            return;
        }
        $body = str_replace('</head>', $str."</head>", $body);
        $app->setBody($body);
    }

    public function loadIcons($view, $pageTitle)
    {
        if ($view == 'gridbox' || strpos($pageTitle, 'Gridbox Editor') !== false) {
            return;
        }
        $app = Factory::getApplication();
        $body = $app->getBody();
        $icons = GridboxHelper::checkIconsLibrary($body);
        if (empty($icons)) {
            return;
            
        }
        $body = str_replace('</head>', $icons.'</head>', $body);
        $app->setBody($body);
    }

    public function fixSmartSearch($view, $option)
    {
        if ($option != 'com_finder' || $view != 'search') {
            return;
        }
        /**
         * @var \Joomla\CMS\Application\SiteApplication
         */
        $app = Factory::getApplication();
        $body = $app->getBody();
        $body = GridboxHelper::fixSmartSearch($body);
        $app->setBody($body);
    }

    public function setMicrodata($view, $option)
    {
        if ($option != 'com_gridbox' || $view != 'page') {
            return;
        }
        /**
         * @var \Joomla\CMS\Application\SiteApplication
         */
        $app = Factory::getApplication();
        $body = $app->getBody();
        if (strpos($body, 'ba-item-star-rating') || strpos($body, 'ba-item-reviews')) {
            $body = GridboxHelper::setMicrodata($body);
            $app->setBody($body);
        }
    }

    public function protectEmails($view, $option, $pageTitle)
    {
        /**
         * @var \Joomla\CMS\Application\SiteApplication
         */
        $app = Factory::getApplication();
        
        if ($view == 'gridbox' || $this->performance->email_encryption != 1
            || $option == 'com_users' || strpos($pageTitle, 'Gridbox Editor') !== false) {
            return;
        }

        $html = $app->getBody();
        $pos = strpos($html, '</head>');
        $head = substr($html, 0, $pos);
        $body = substr($html, $pos);
        if (strpos($body, '@') === false) {
            return;
        }
        $body = $this->EncryptEmails($body);
        $html = $head.$body;
        $app->setBody($html);
    }

    public function addMetaData()
    {
        /**
         * @var \Joomla\CMS\Application\SiteApplication
         */
        $app = Factory::getApplication();
        $html = $app->getBody();
        $str = GridboxHelper::checkMeta();
        $html = str_replace('</head>', $str.'</head>', $html);
        $app->setBody($html);
    }

    public function onAfterRender()
    {
        $this->onAfterRenderAdmin();
        $this->onAfterRenderSite();
    }

    public function getPattern($link, $html)
    {
        $pattern = '~(?:<a ([^>]*)href\s*=\s*"mailto:'.$link.'"([^>]*))>'.$html.'</a>~i';

        return $pattern;
    }

    public function addEmailAttributes($email, $before, $after)
    {
        if ($before !== '') {
            $before = str_replace("'", "\'", $before);
            $email = str_replace(".innerHTML += '<a '", ".innerHTML += '<a {$before}'", $email);
        }
        if ($after !== '') {
            $after = str_replace("'", "\'", $after);
            $email = str_replace("'\'>'", "'\'{$after}>'", $email);
        }

        return $email;
    }

    protected function convertEncoding($text)
    {
        $text = html_entity_decode($text);
        $text = str_replace('a', '&#97;', $text);
        $text = str_replace('e', '&#101;', $text);
        $text = str_replace('i', '&#105;', $text);
        $text = str_replace('o', '&#111;', $text);
        $text = str_replace('u', '&#117;', $text);
        $text = htmlentities($text, ENT_QUOTES, 'UTF-8', false);

        return $text;
    }

    protected function cloak($mail, $mailto = true, $text = '', $email = true)
    {
        if ($mailto && (empty($text) || $email)) {
            $text = PunycodeHelper::emailToUTF8($text ?: $mail);
        } else if (!$mailto) {
            $mail = PunycodeHelper::emailToUTF8($mail);
        }
        $mail = $this->convertEncoding($mail);
        $rand = md5($mail . mt_rand(1, 100000));
        $mail = explode('@', $mail);
        $mail_parts = explode('.', $mail[1]);
        if ($mailto) {
            if ($text) {
                $text = $this->convertEncoding($text);
                if ($email) {
                    $text = explode('@', $text);
                    $text_parts = explode('.', $text[1]);
                    $tmpScript = "var addy_text".$rand." = '".$text[0]."' + '&#64;' + '"
                        .implode("' + '&#46;' + '", $text_parts). "';";
                } else {
                    $tmpScript = "var addy_text".$rand." = '".$text."';";
                }
                $tmpScript .= "document.getElementById('cloak".$rand
                    ."').innerHTML += '<a ' + path + '\'' + prefix + ':' + addy".$rand." + '\'>'+addy_text".$rand."+'<\/a>';";
            } else {
                $tmpScript = "document.getElementById('cloak".$rand
                    ."').innerHTML += '<a ' + path + '\'' + prefix + ':' + addy".$rand." + '\'>' +addy".$rand."+'<\/a>';";
            }
        } else {
            $tmpScript = "document.getElementById('cloak".$rand."').innerHTML += addy".$rand.";";
        }
        $script = "
                document.getElementById('cloak".$rand."').innerHTML = '';
                var prefix = '&#109;a' + 'i&#108;' + '&#116;o';
                var path = 'hr' + 'ef' + '=';
                var addy".$rand." = '".$mail[0]."' + '&#64;';
                addy".$rand." = addy".$rand." + '".implode("' + '&#46;' + '", $mail_parts)."';
                $tmpScript
        ";
        $inlineScript = "<script type='text/javascript'>".$script."</script>";

        return '<span id="cloak'.$rand.'">'.Text::_('JLIB_HTML_CLOAKING').'</span>'.$inlineScript;
    }

    public function EncryptEmails($html)
    {
        $regEmail = '([\w\.\'\-\+]+\@(?:[a-z0-9\.\-]+\.)+(?:[a-zA-Z0-9\-]{2,10}))';
        $regEmailLink = $regEmail.'([?&][\x20-\x7f][^"<>]+)';
        $regText = '((?:[\x20-\x7f]|[\xA1-\xFF]|[\xC2-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF4][\x80-\xBF]{3})[^<>]+)';
        $regImage = '(<img[^>]+>)';
        $regTextSpan = '(<span[^>]+>|<span>|<strong>|<strong><span[^>]+>|<strong><span>)'.$regText.'(</span>|</strong>|</span></strong>)';
        $regEmailSpan = '(<span[^>]+>|<span>|<strong>|<strong><span[^>]+>|<strong><span>)'.$regEmail.'(</span>|</strong>|</span></strong>)';
        $pattern = $this->getPattern($regEmail, $regEmail);
        $pattern = str_replace('"mailto:', '"http://mce_host([\x20-\x7f][^<>]+/)', $pattern);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[3][0];
            $emailText = $matches[5][0];
            $replacement = $this->cloak($email, true, $emailText);
            $replacement = $this->addEmailAttributes($replacement, $matches[1][0], $matches[4][0]);
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = $this->getPattern($regEmail, $regText);
        $pattern = str_replace('"mailto:', '"http://mce_host([\x20-\x7f][^<>]+/)', $pattern);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[3][0];
            $emailText = $matches[5][0];
            $replacement = $this->cloak($email, true, $emailText, 0);
            $replacement = $this->addEmailAttributes($replacement, $matches[1][0], $matches[4][0]);
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = $this->getPattern($regEmail, $regEmail);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[2][0];
            $emailText = $matches[4][0];
            $replacement = $this->cloak($email, true, $emailText);
            $replacement = $this->addEmailAttributes($replacement, $matches[1][0], $matches[3][0]);
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = $this->getPattern($regEmail, $regEmailSpan);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[2][0];
            $emailText = $matches[4][0] . $matches[5][0] . $matches[6][0];
            $replacement = $this->cloak($email, true, $emailText);
            $replacement = html_entity_decode($this->addEmailAttributes($replacement, $matches[1][0], $matches[3][0]));
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = $this->getPattern($regEmail, $regTextSpan);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[2][0];
            $emailText = $matches[4][0] . addslashes($matches[5][0]) . $matches[6][0];
            $replacement = $this->cloak($email, true, $emailText, 0);
            $replacement = html_entity_decode($this->addEmailAttributes($replacement, $matches[1][0], $matches[3][0]));
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = $this->getPattern($regEmail, $regText);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[2][0];
            $emailText = addslashes($matches[4][0]);
            $replacement = $this->cloak($email, true, $emailText, 0);
            $replacement = $this->addEmailAttributes($replacement, $matches[1][0], $matches[3][0]);
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = $this->getPattern($regEmail, $regImage);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[2][0];
            $emailText = $matches[4][0];
            $replacement = $this->cloak($email, true, $emailText, 0);
            $replacement = html_entity_decode($this->addEmailAttributes($replacement, $matches[1][0], $matches[3][0]));
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = $this->getPattern($regEmail, $regImage.$regEmail);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[2][0];
            $emailText = $matches[4][0] . $matches[5][0];
            $replacement = $this->cloak($email, true, $emailText);
            $replacement = html_entity_decode($this->addEmailAttributes($replacement, $matches[1][0], $matches[3][0]));
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = $this->getPattern($regEmail, $regImage.$regText);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[2][0];
            $emailText = $matches[4][0] . addslashes($matches[5][0]);
            $replacement = $this->cloak($email, true, $emailText, 0);
            $replacement = html_entity_decode($this->addEmailAttributes($replacement, $matches[1][0], $matches[3][0]));
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = $this->getPattern($regEmailLink, $regEmail);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[2][0] . $matches[3][0];
            $emailText = $matches[5][0];
            $email = str_replace('&amp;', '&', $email);
            $replacement = $this->cloak($email, true, $emailText);
            $replacement = $this->addEmailAttributes($replacement, $matches[1][0], $matches[4][0]);
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = $this->getPattern($regEmailLink, $regText);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[2][0] . $matches[3][0];
            $emailText = addslashes($matches[5][0]);
            $email = str_replace('&amp;', '&', $email);
            $replacement = $this->cloak($email, true, $emailText, 0);
            $replacement = $this->addEmailAttributes($replacement, $matches[1][0], $matches[4][0]);
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = $this->getPattern($regEmailLink, $regEmailSpan);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[2][0] . $matches[3][0];
            $emailText = $matches[5][0] . $matches[6][0] . $matches[7][0];
            $replacement = $this->cloak($email, true, $emailText);
            $replacement = html_entity_decode($this->addEmailAttributes($replacement, $matches[1][0], $matches[4][0]));
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = $this->getPattern($regEmailLink, $regTextSpan);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[2][0] . $matches[3][0];
            $emailText = $matches[5][0] . addslashes($matches[6][0]) . $matches[7][0];
            $replacement = $this->cloak($email, true, $emailText, 0);
            $replacement = html_entity_decode($this->addEmailAttributes($replacement, $matches[1][0], $matches[4][0]));
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = $this->getPattern($regEmailLink, $regImage);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[1][0] . $matches[2][0] . $matches[3][0];
            $emailText = $matches[5][0];
            $email = str_replace('&amp;', '&', $email);
            $replacement = $this->cloak($email, true, $emailText, 0);
            $replacement = html_entity_decode($this->addEmailAttributes($replacement, $matches[1][0], $matches[4][0]));
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = $this->getPattern($regEmailLink, $regImage.$regEmail);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[1][0] . $matches[2][0] . $matches[3][0];
            $emailText = $matches[4][0] . $matches[5][0] . $matches[6][0];
            $email = str_replace('&amp;', '&', $email);
            $replacement = $this->cloak($email, true, $emailText);
            $replacement = html_entity_decode($this->addEmailAttributes($replacement, $matches[1][0], $matches[4][0]));
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = $this->getPattern($regEmailLink, $regImage . $regText);
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[1][0] . $matches[2][0] . $matches[3][0];
            $emailText = $matches[4][0] . $matches[5][0] . addslashes($matches[6][0]);
            $email = str_replace('&amp;', '&', $email);
            $replacement = $this->cloak($email, true, $emailText, 0);
            $replacement = html_entity_decode($this->addEmailAttributes($replacement, $matches[1][0], $matches[4][0]));
            $html = substr_replace($html, $replacement, $matches[0][1], strlen($matches[0][0]));
        }
        $pattern = '~(?![^<>]*>)'.$regEmail.'~i';
        while (preg_match($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
            $email = $matches[1][0];
            $replacement = $this->cloak($email, false);
            $html = substr_replace($html, $replacement, $matches[1][1], strlen($email));
        }

        return $html;
    }
}