<?php

/**
 * vB_Api_Bbcode
 *
 * @package vBApi
 * @access public
 */
class vB_Api_Bbcode extends vB_Api
{
	/**#@+
	* These make up the bit field to disable specific types of BB codes.
	*/
	const ALLOW_BBCODE_BASIC	= 1;
	const ALLOW_BBCODE_COLOR	= 2;
	const ALLOW_BBCODE_SIZE		= 4;
	const ALLOW_BBCODE_FONT		= 8;
	const ALLOW_BBCODE_ALIGN	= 16;
	const ALLOW_BBCODE_LIST		= 32;
	const ALLOW_BBCODE_URL		= 64;
	const ALLOW_BBCODE_CODE		= 128;
	const ALLOW_BBCODE_PHP		= 256;
	const ALLOW_BBCODE_HTML		= 512;
	const ALLOW_BBCODE_IMG		= 1024;
	const ALLOW_BBCODE_QUOTE	= 2048;
	const ALLOW_BBCODE_CUSTOM	= 4096;
	/**#@-*/

	const EDITOR_INDENT	= 40;

	protected function __construct()
	{
		parent::__construct();
	}

	public function initInfo()
	{
		$response['defaultTags'] = $this->fetchTagList();
		$response['customTags'] = $this->fetchCustomTags();
		$response['defaultOptions'] = $this->fetchBbcodeOptions();
		$response['censorship'] = $this->fetchCensorshipInfo();
		$response['smilies'] = $this->fetchSmilies();

		$response['sessionUrl'] = vB::getCurrentSession()->get('sessionurl');
		$response['vBHttpHost'] = vB::getRequest()->getVbHttpHost();

		$options = vB::getDatastore()->get_value('options');
		$response['blankAsciiStrip'] = $options['blankasciistrip'];
		$response['wordWrap'] = $options['wordwrap'];
		$response['codeMaxLines'] = $options['codemaxlines'];
		$response['bbUrl'] = $options['bburl'];
		$response['viewAttachedImages'] = $options['viewattachedimages'];
		$response['urlNoFollow'] = $options['url_nofollow'];
		$response['urlNoFollowWhiteList'] = $options['url_nofollow_whitelist'];
		$response['useFileAvatar'] = $options['usefileavatar'];
		$response['sigpicUrl'] = $options['sigpicurl'];

		return $response;
	}

	/**
	* Grabs the list of default BB code tags.
	*
	* @param	string	Allows an optional path/URL to prepend to thread/post tags
	* @param	boolean	Force all BB codes to be returned?
	*
	* @return	array	Array of BB code tags
	*/
	public function fetchTagList($prepend_path = '', $force_all = false)
	{
		// TODO: we need to refactor $vbphrase
		global $vbphrase;
		static $tag_list;

		$options = vB::getDatastore()->get_value('options');

		if ($force_all)
		{
			$tag_list_bak = $tag_list;
			$tag_list = array();
		}

		if (empty($tag_list))
		{
			//set up some variable for later on to take into account the optional vbforum_url
			//we don't use the seo urls here because they don't play nice with the bbcode
			//processing.
			//
			//forum_path is the prefix for the forum based urls.  If provided we use it as the base.
			//if it is not an absolute url we also use the prepend_path (which is, itself, used to
			//make the url's absolute where needed).
			//forum_path_full is the same, however its always made absolute using the bburl when
			//it is not an absolute url.  This follows existing usage except for inserting the vbforum_url
			$forum_path = '';
			if ($options['vbforum_url'])
			{
				$forum_path = rtrim($options['vbforum_url'], '/') . '/';
			}

			$forum_path_full = $forum_path;
			if (strpos($forum_path, '://') === false)
			{
				$forum_path = $prepend_path . $forum_path;
				$forum_path_full =  rtrim($options['bburl'], '/') . '/' . $forum_path_full;
			}
			$tag_list = array();

			// [QUOTE]
			$tag_list['no_option']['quote'] = array(
				'callback'          => 'handle_bbcode_quote',
				'strip_empty'       => true,
				'strip_space_after' => 2
			);

			// [QUOTE=XXX]
			$tag_list['option']['quote'] = array(
				'callback'          => 'handle_bbcode_quote',
				'strip_empty'       => true,
				'strip_space_after' => 2,
			);

			// [HIGHLIGHT]
			$tag_list['no_option']['highlight'] = array(
				'html'        => '<span class="highlight">%1$s</span>',
				'strip_empty' => true
			);

			// [NOPARSE]-- doesn't need a callback, just some flags
			$tag_list['no_option']['noparse'] = array(
				'html'            => '%1$s',
				'strip_empty'     => true,
				'stop_parse'      => true,
				'disable_smilies' => true
			);

			// [VIDEO]
			$tag_list['option']['video'] = array(
				'callback' => 'handle_bbcode_video',
				'strip_empty'     => true,
				'disable_smilies' => true,
			);

			$tag_list['no_option']['video'] = array(
				'callback'    => 'handle_bbcode_url',
				'strip_empty' => true
			);

			if (($options['allowedbbcodes'] & vB_Api_Bbcode::ALLOW_BBCODE_BASIC) OR $force_all)
			{
				// [B]
				$tag_list['no_option']['b'] = array(
					'html'        => '<b>%1$s</b>',
					'strip_empty' => true
				);

				// [I]
				$tag_list['no_option']['i'] = array(
					'html'        => '<i>%1$s</i>',
					'strip_empty' => true
				);

				// [U]
				$tag_list['no_option']['u'] = array(
					'html'        => '<u>%1$s</u>',
					'strip_empty' => true
				);

				// [TABLE]
				$tag_list['no_option']['table'] = array(
					'callback' => 'parseTableTag',
					'strip_space_after' => 1,
					'strip_empty' => true
				);

				// [TABLE=]
				$tag_list['option']['table'] = array(
					'callback' => 'parseTableTag',
					'strip_space_after' => 1,
					'strip_empty' => true
				);

				// [HR]
				$tag_list['no_option']['hr'] = array(
					'html' => '<hr />%1$s',
					'strip_empty' => false
				);

				// [SUB]
				$tag_list['no_option']['sub'] = array(
					'html' => '<sub>%1$s</sub>',
					'strip_empty' => true
				);

				// [SUP]
				$tag_list['no_option']['sup'] = array(
					'html' => '<sup>%1$s</sup>',
					'strip_empty' => true
				);
			}

			if (($options['allowedbbcodes'] & vB_Api_Bbcode::ALLOW_BBCODE_COLOR) OR $force_all)
			{
				// [COLOR=XXX]
				$tag_list['option']['color'] = array(
					'html'         => '<font color="%2$s">%1$s</font>',
					'option_regex' => '#^\#?\w+$#',
					'strip_empty'  => true
				);
			}

			if (($options['allowedbbcodes'] & vB_Api_Bbcode::ALLOW_BBCODE_SIZE) OR $force_all)
			{
				// [SIZE=XXX]
				$tag_list['option']['size'] = array(
					'callback'    => 'handle_bbcode_size',
					'strip_empty'  => true
				);
			}

			if (($options['allowedbbcodes'] & vB_Api_Bbcode::ALLOW_BBCODE_FONT) OR $force_all)
			{
				// [FONT=XXX]
				$tag_list['option']['font'] = array(
					'html'         => '<font face="%2$s">%1$s</font>',
					'option_regex' => '#^[^["`\':]+$#',
					'strip_empty'  => true
				);
			}

			if (($options['allowedbbcodes'] & vB_Api_Bbcode::ALLOW_BBCODE_ALIGN) OR $force_all)
			{
				// [LEFT]
				$tag_list['no_option']['left'] = array(
					'html'              => '<div align="left">%1$s</div>',
					'strip_empty'       => true,
					'strip_space_after' => 1
				);

				// [CENTER]
				$tag_list['no_option']['center'] = array(
					'html'              => '<div align="center">%1$s</div>',
					'strip_empty'       => true,
					'strip_space_after' => 1
				);

				// [RIGHT]
				$tag_list['no_option']['right'] = array(
					'html'              => '<div align="right">%1$s</div>',
					'strip_empty'       => true,
					'strip_space_after' => 1
				);

				// [INDENT]
				$tag_list['no_option']['indent'] = array(
					'html'              => '<blockquote>%1$s</blockquote>',
					'strip_empty'       => true,
					'strip_space_after' => 1
				);
			}

			if (($options['allowedbbcodes'] & vB_Api_Bbcode::ALLOW_BBCODE_LIST) OR $force_all)
			{
				// [LIST]
				$tag_list['no_option']['list'] = array(
					'callback'    => 'handle_bbcode_list',
					'strip_empty' => true
				);

				// [LIST=XXX]
				$tag_list['option']['list'] = array(
					'callback'    => 'handle_bbcode_list',
					'strip_empty' => true
				);

				// [INDENT]
				$tag_list['no_option']['indent'] = array(
					'html'              => '<blockquote>%1$s</blockquote>',
					'strip_empty'       => true,
					'strip_space_after' => 1
				);
			}

			if (($options['allowedbbcodes'] & vB_Api_Bbcode::ALLOW_BBCODE_URL) OR $force_all)
			{
				// [EMAIL]
				$tag_list['no_option']['email'] = array(
					'callback'    => 'handle_bbcode_email',
					'strip_empty' => true
				);

				// [EMAIL=XXX]
				$tag_list['option']['email'] = array(
					'callback'    => 'handle_bbcode_email',
					'strip_empty' => true
				);

				// [URL]
				$tag_list['no_option']['url'] = array(
					'callback'    => 'handle_bbcode_url',
					'strip_empty' => true
				);

				// [URL=XXX]
				$tag_list['option']['url'] = array(
					'callback'    => 'handle_bbcode_url',
					'strip_empty' => true
				);

				// [THREAD]
				$tag_list['no_option']['thread'] = array(
					'html'        => '<a href="' . $forum_path . 'showthread.php?' . vB::getCurrentSession()->get('sessionurl') . 't=%1$s"' .
						($options['friendlyurl'] ? ' rel="nofollow"' : '') . '>' . $forum_path_full . 'showthread.php?t=%1$s</a>',
					'data_regex'  => '#^\d+$#',
					'strip_empty' => true
				);

				// [THREAD=XXX]
				$tag_list['option']['thread'] = array(
					'html'         => '<a href="' . $forum_path . 'showthread.php?' . vB::getCurrentSession()->get('sessionurl') . 't=%2$s"' .
						($options['friendlyurl'] ? ' rel="nofollow"' : '') .
						' title="' . vB_String::htmlSpecialCharsUni($options['bbtitle']) . ' - ' . $vbphrase['thread'] . ' %2$s">%1$s</a>',
					'option_regex' => '#^\d+$#',
					'strip_empty'  => true
				);

				// [POST]
				$tag_list['no_option']['post'] = array(
					'html'        => '<a href="' . $forum_path . 'showthread.php?' . vB::getCurrentSession()->get('sessionurl') . 'p=%1$s#post%1$s"' .
						($options['friendlyurl'] ? ' rel="nofollow"' : '') . '>' . $forum_path_full . 'showthread.php?p=%1$s</a>',
					'data_regex'  => '#^\d+$#',
					'strip_empty' => true
				);

				// [POST=XXX]
				$tag_list['option']['post'] = array(
					'html'         => '<a href="' . $forum_path . 'showthread.php?' . vB::getCurrentSession()->get('sessionurl') . 'p=%2$s#post%2$s"' .
						($options['friendlyurl'] ? ' rel="nofollow"' : '') .
						' title="' . vB_String::htmlSpecialCharsUni($options['bbtitle']) . ' - ' . $vbphrase['post'] . ' %2$s">%1$s</a>',
					'option_regex' => '#^\d+$#',
					'strip_empty'  => true
				);

				if (defined('VB_API') AND VB_API === true)
				{
					$tag_list['no_option']['thread']['html'] = '<a href="vb:showthread/t=%1$s">' . $options['bburl'] . '/showthread.php?t=%1$s</a>';
					$tag_list['option']['thread']['html'] = '<a href="vb:showthread/t=%2$s">%1$s</a>';
					$tag_list['no_option']['post']['html'] = '<a href="vb:showthread/p=%1$s">' . $options['bburl'] . '/showthread.php?p=%1$s</a>';
					$tag_list['option']['post']['html'] = '<a href="vb:showthread/p=%2$s">%1$s</a>';
				}
			}

			if (($options['allowedbbcodes'] & vB_Api_Bbcode::ALLOW_BBCODE_PHP) OR $force_all)
			{
				// [PHP]
				$tag_list['no_option']['php'] = array(
					'callback'          => 'handle_bbcode_php',
					'strip_empty'       => true,
					'stop_parse'        => true,
					'disable_smilies'   => true,
					'disable_wordwrap'  => true,
					'strip_space_after' => 2
				);
			}

			if (($options['allowedbbcodes'] & vB_Api_Bbcode::ALLOW_BBCODE_CODE) OR $force_all)
			{
				//[CODE]
				$tag_list['no_option']['code'] = array(
					'callback'          => 'handle_bbcode_code',
					'strip_empty'       => true,
					'disable_smilies'   => true,
					'disable_wordwrap'  => true,
					'strip_space_after' => 2
				);
			}

			if (($options['allowedbbcodes'] & vB_Api_Bbcode::ALLOW_BBCODE_HTML) OR $force_all)
			{
				// [HTML]
				$tag_list['no_option']['html'] = array(
					'callback'          => 'handle_bbcode_html',
					'strip_empty'       => true,
					'stop_parse'        => true,
					'disable_smilies'   => true,
					'disable_wordwrap'  => true,
					'strip_space_after' => 2
				);
			}

			// Legacy Hook 'bbcode_fetch_tags' Removed //
		}

		if ($force_all)
		{
			$tag_list_return = $tag_list;
			$tag_list = $tag_list_bak;
			return $tag_list_return;
		}
		else
		{
			return $tag_list;
		}
	}

	/**
	* Loads any user specified custom BB code tags into the $tag_list
	*/
	protected function fetchCustomTags()
	{
		$customTags = array();

		$bbcodeoptions = vB::getDatastore()->get_value('bf_misc_bbcodeoptions');

		$bbcodes = vB::getDbAssertor()->getRows('bbcode');
		foreach($bbcodes as $customtag)
		{
			$has_option = $customtag['twoparams'] ? 'option' : 'no_option';
			$customtag['bbcodetag'] = strtolower($customtag['bbcodetag']);
			$customTags["$has_option"]["$customtag[bbcodetag]"] = array(
				'html'             => $customtag['bbcodereplacement'],
				'strip_empty'      => (intval($customtag['options']) & $bbcodeoptions['strip_empty']) ? 1 : 0 ,
				'stop_parse'       => (intval($customtag['options']) & $bbcodeoptions['stop_parse']) ? 1 : 0 ,
				'disable_smilies'  => (intval($customtag['options']) & $bbcodeoptions['disable_smilies']) ? 1 : 0 ,
				'disable_wordwrap' => (intval($customtag['options']) & $bbcodeoptions['disable_wordwrap']) ? 1 : 0
			);
		}

		return $customTags;
	}

	protected function fetchBbcodeOptions()
	{
		$options = vB::getDatastore()->get_value('options');

		// Parse Calendar
		$response['calendar'] = array(
			// TODO: we need to obtain this...
//			'dohtml'		=> $calendarinfo['allowhtml'],
//			'dobbcode'		=> $calendarinfo['allowbbcode'],
//			'dobbimagecode' => $calendarinfo['allowimgcode'],
//			'dosmilies'		=> $calendarinfo['allowsmilies']
		);

		// parse private message
		$response['privatemessage'] = array(
			'allowhtml'		 => $options['privallowhtml'],
			'allowbbcode'	 => $options['privallowbbcode'],
			'allowimagecode' => $options['privallowbbimagecode'],
			'allowsmilies'	 => $options['privallowsmilies'],
		);

		// parse non-forum item
		$response['nonforum'] = array(
			'dohtml'		=> $options['allowhtml'],
			'dobbcode'		=> $options['allowbbcode'],
			'dobbimagecode' => $options['allowbbimagecode'],
			'dosmilies'		=> $options['allowsmilies']
		);

		// parse visitor/group/picture message
		$response['visitormessage'] =
		$response['groupmessage']	=
		$response['picturecomment'] =
		$response['socialmessage']	= array(
			'dohtml'		=> $options['allowhtml'],
			'dobbcode'		=> $options['allowbbcode'],
			'dobbimagecode' => true, // this tag can be disabled manually; leaving as true means old usages remain (as documented)
			'dosmilies'		=> $options['allowsmilies']
		);

		return $response;
	}

	protected function fetchCensorshipInfo()
	{
		$options = vB::getDatastore()->get_value('options');

		$response = array('words'=>array(), 'char'=>$options['censorchar']);

		if ($options['enablecensor'])
		{
			$censorwords = preg_quote($options['censorwords'], '#');
			$response['words'] = preg_split('#[ \r\n\t]+#', $censorwords, -1, PREG_SPLIT_NO_EMPTY);
		}

		return $response;
	}

	public function fetchSmilies()
	{
		$smilieCache['html'] = $smilieCache['no_html'] = array();

		if ($smilies = vB::getDatastore()->get_value('smiliecache'))
		{
			// we can get the smilies from the smiliecache datastore
			DEVDEBUG('returning smilies from the datastore');

			return $smilies;
		}
		else
		{
			// we have to get the smilies from the database
			DEVDEBUG('querying for smilies');

			return vB::getDbAssertor()->getRows('fetchSmilies', array(vB_dB_Query::QUERYTYPE_KEY=>  vB_dB_Query::QUERY_STORED));
		}
	}

	/** Extracts the video and photo content from text.
	 *
	 *	@param	string
	 *
	 *	@return	mixed	array of 'url', 'provider', 'code'
	 **/
	public function extractVideo($rawtext)
	{
		$videos = array();
		$filter = '~\[video.*\[\/video~i';
		$matches = array();
		$count = preg_match_all($filter, $rawtext, $matches);

		if ($count > 0 )
		{
			foreach ($matches[0] as $match)
			{
				$pos = strpos($match,']');
				if ($pos)
				{
					$codes = substr($match,7, $pos -7);
					$codes = explode(';', $codes);
					if (count($codes) > 1)
					{
						$url = substr($match,$pos + 1, -7);

						if (!empty($url))
						{
							//we have all the necessary variables.
							$videos[] = array('url' => $url, 'provider' => $codes[0],
							 'code' => $codes[1]);
						}
					}
				}
			}
			return $videos;
		}
		else
		{
			return 0;
		}

	}
}
