<?php

use Joomla\CMS\Uri\Uri;

/**
 * Helper class which is using to parser bbcode
 *
 */
class BBCodeParser
{

	public static $programingLanguages = array(
		//added pre class for code presentation  		
		'/\[phpcode\](.*?)\[\/phpcode\]/is',
		'/\[csscode\](.*?)\[\/csscode\]/is',
		'/\[jscode\](.*?)\[\/jscode\]/is',
		'/\[htmlcode\](.*?)\[\/htmlcode\]/is',
	);
	public static $search = array(
		//added line break  
		'/\[br\]/is',
		'/\[b\](.*?)\[\/b\]/is',
		'/\[i\](.*?)\[\/i\]/is',
		'/\[u\](.*?)\[\/u\]/is',
		'/\[url\=(.*?)\](.*?)\[\/url\]/is',
		'/\[url\](.*?)\[\/url\]/is',
		'/\[align\=(left|center|right)\](.*?)\[\/align\]/is',
		'/\[img\](.*?)\[\/img\]/is',
		'/\[mail\=(.*?)\](.*?)\[\/mail\]/is',
		'/\[mail\](.*?)\[\/mail\]/is',
		'/\[font\=(.*?)\](.*?)\[\/font\]/is',
		'/\[size\=(.*?)\](.*?)\[\/size\]/is',
		'/\[color\=(.*?)\](.*?)\[\/color\]/is',
		//added textarea for code presentation  
		'/\[codearea\](.*?)\[\/codearea\]/is',
		//added pre class for code presentation  
		'/\[code\](.*?)\[\/code\]/is',
		'/\[quote\](.*?)\[\/quote\]/is',
		//added paragraph  
		'/\[p\](.*?)\[\/p\]/is');

	public static $replace = array(
		//added line break  
		'<br />',
		'<strong>$1</strong>',
		'<em>$1</em>',
		'<u>$1</u>',
		// added nofollow to prevent spam  
		'<a href="$1" rel="nofollow" title="$2 - $1">$2</a>',
		'<a href="$1" rel="nofollow" title="$1">$1</a>',
		'<div style="text-align: $1;">$2</div>',
		//added alt attribute for validation  
		'<img src="$1" alt="" />',
		'<a href="mailto:$1">$2</a>',
		'<a href="mailto:$1">$1</a>',
		'<span style="font-family: $1;">$2</span>',
		'<span style="font-size: $1;">$2</span>',
		'<span style="color: $1;">$2</span>',
		//added textarea for code presentation  
		'<textarea class="code_container" rows="30" cols="70">$1</textarea>',
		//added pre class for code presentation  
		'<pre class="code">$1</pre>',
		'<blockquote>$1</blockquote>',
		//added paragraph  
		'<p>$1</p>');

	public static $smileys = array(':D' => 'happy.png', ':(' => 'sad.png', ':)' => 'smile.png');

	/**
	 * Add new bbcode
	 *
	 * @param string $search
	 * @param string $replace
	 */
	public static function addBBCode($search, $replace)
	{
		self::$search[]  = $search;
		self::$replace[] = $replace;
	}

	/**
	 * Add new Smiley
	 *
	 * @param string $abbr
	 * @param string $img
	 */
	public static function addSmiley($abbr, $img)
	{
		self::$smileys[$abbr] = $img;
	}

	/**
	 * Parse the given text, replace all bbcode with the actual HTML code
	 *
	 * @param string $text
	 *
	 * @return the parsed text
	 */
	public static function parse($text)
	{
		$text    = preg_replace_callback(self::$programingLanguages, 'BBCodeParser::processHightlightCode', $text);
		$text    = preg_replace(self::$search, self::$replace, $text);
		$rootUri = Uri::root(true);
		foreach (self::$smileys as $smiley => $img)
		{
			$text = str_replace($smiley,
				"<img src='" . $rootUri . '/media/com_helpdeskpro/assets/images/emoticons/' . $img . "' />", $text);
		}
		$text = self::makeClickableLinks($text);

		return $text;
	}

	/**
	 * Highlight the programming code
	 *
	 * @param array $matches
	 *
	 * @return string
	 */
	public static function processHightlightCode($matches)
	{
		$language = $matches[0];
		$pos      = strpos($language, 'code');
		if ($pos !== false)
		{
			$language = substr($language, 1, $pos - 1);
		}
		else
		{
			$language = 'php';
		}
		$code = $matches[1];
		$code = str_replace('<br />', "\r\n", $code);

		return '<pre class="brush:' . $language . '">' . $code . '</pre>';
	}

	/**
	 * Convert all links in the given text to a tag so that it could be clickable
	 *
	 * @param $value      string
	 *
	 * @param $protocols  array
	 *
	 * @param $attributes array
	 *
	 * @return string
	 */
	public static function makeClickableLinks($value, $protocols = array('http', 'mail'), array $attributes = array())
	{

		// Link attributes
		$attr = '';
		foreach ($attributes as $key => $val)
		{
			$attr = ' ' . $key . '="' . htmlentities($val) . '"';
		}

		$links = array();

		// Extract existing links and tags
		$value = preg_replace_callback('~(<a .*?>.*?</a>|<.*?>)~i', function ($match) use (&$links)
		{
			return '<' . array_push($links, $match[1]) . '>';
		}, $value);

		// Extract text links for each protocol
		foreach ((array) $protocols as $protocol)
		{
			switch ($protocol)
			{
				case 'http':
				case 'https':
					$value = preg_replace_callback('~(?:(https?)://([^\s<]+)|(www\.[^\s<]+?\.[^\s<]+))(?<![\.,:])~i', function ($match) use ($protocol, &$links, $attr)
					{
						if ($match[1]) $protocol = $match[1];
						$link = $match[2] ?: $match[3];

						return '<' . array_push($links, "<a $attr target=\"_blank\" href=\"$protocol://$link\">$protocol://$link</a>") . '>';
					}, $value);
					break;
				case 'mail':
					$value = preg_replace_callback('~([^\s<]+?@[^\s<]+?\.[^\s<]+)(?<![\.,:])~', function ($match) use (&$links, $attr)
					{
						return '<' . array_push($links, "<a $attr href=\"mailto:{$match[1]}\">{$match[1]}</a>") . '>';
					}, $value);
					break;
				case 'twitter':
					$value = preg_replace_callback('~(?<!\w)[@#](\w++)~', function ($match) use (&$links, $attr)
					{
						return '<' . array_push($links, "<a $attr href=\"https://twitter.com/" . ($match[0][0] == '@' ? '' : 'search/%23') . $match[1] . "\">{$match[0]}</a>") . '>';
					}, $value);
					break;
				default:
					$value = preg_replace_callback('~' . preg_quote($protocol, '~') . '://([^\s<]+?)(?<![\.,:])~i', function ($match) use ($protocol, &$links, $attr)
					{
						return '<' . array_push($links, "<a $attr href=\"$protocol://{$match[1]}\">{$match[1]}</a>") . '>';
					}, $value);
					break;
			}
		}

		// Insert all link
		return preg_replace_callback('/<(\d+)>/', function ($match) use (&$links)
		{
			return $links[$match[1] - 1];
		}, $value);
	}
}