<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.tinymce
 *
 * @copyright   (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
namespace Joomla\Plugin\Editors\TinyMCE\PluginTraits;

\defined('_JEXEC') or die();

use Joomla\CMS\Access\Access;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Filter\InputFilter;

/**
 * Handles the Joomla filters for the TinyMCE editor.
 *
 * @since  4.1.0
 */
trait GlobalFilters
{
	/**
	 * Get the global text filters to arbitrary text as per settings for current user groups
	 * @param   User  $user  The user object
	 *
	 * @return  InputFilter
	 *
	 * @since   4.1.0
	 */
	protected static function getGlobalFilters($user)
	{
		// Filter settings
		$config     = ComponentHelper::getParams('com_config');
		$userGroups = Access::getGroupsByUser($user->get('id'));
		$filters    = $config->get('filters');

		$forbiddenListTags       = [];
		$forbiddenListAttributes = [];
		$customListTags          = [];
		$customListAttributes    = [];
		$allowedListTags         = [];
		$allowedListAttributes   = [];

		$allowedList   = false;
		$forbiddenList = false;
		$customList    = false;
		$unfiltered    = false;

		/**
		 * Cycle through each of the user groups the user is in.
		 * Remember they are included in the public group as well.
		 */
		foreach ($userGroups as $groupId)
		{
			// May have added a group but not saved the filters.
			if (!isset($filters->$groupId))
			{
				continue;
			}

			// Each group the user is in could have different filtering properties.
			$filterData = $filters->$groupId;
			$filterType = strtoupper($filterData->filter_type);

			if ($filterType === 'NH')
			{
				// Maximum HTML filtering.
			}
			elseif ($filterType === 'NONE')
			{
				// No HTML filtering.
				$unfiltered = true;
			}
			else
			{
				/**
				 * Forbidden or allowed lists.
				 * Preprocess the tags and attributes.
				 */
				$tags           = explode(',', $filterData->filter_tags);
				$attributes     = explode(',', $filterData->filter_attributes);
				$tempTags       = [];
				$tempAttributes = [];

				foreach ($tags as $tag)
				{
					$tag = trim($tag);

					if ($tag)
					{
						$tempTags[] = $tag;
					}
				}

				foreach ($attributes as $attribute)
				{
					$attribute = trim($attribute);

					if ($attribute)
					{
						$tempAttributes[] = $attribute;
					}
				}

				/**
				 * Collect the list of forbidden or allowed tags and attributes.
				 * Each list is cumulative.
				 * "BL" is deprecated in Joomla! 4, will be removed in Joomla! 5
				 */
				if (in_array($filterType, ['BL', 'FL']))
				{
					$forbiddenList           = true;
					$forbiddenListTags       = array_merge($forbiddenListTags, $tempTags);
					$forbiddenListAttributes = array_merge($forbiddenListAttributes, $tempAttributes);
				}
				// "CBL" is deprecated in Joomla! 4, will be removed in Joomla! 5
				elseif (in_array($filterType, ['CBL', 'CFL']))
				{
					// Only set to true if Tags or Attributes were added
					if ($tempTags || $tempAttributes)
					{
						$customList           = true;
						$customListTags       = array_merge($customListTags, $tempTags);
						$customListAttributes = array_merge($customListAttributes, $tempAttributes);
					}
				}
				// "WL" is deprecated in Joomla! 4, will be removed in Joomla! 5
				elseif (in_array($filterType, ['WL', 'AL']))
				{
					$allowedList           = true;
					$allowedListTags       = array_merge($allowedListTags, $tempTags);
					$allowedListAttributes = array_merge($allowedListAttributes, $tempAttributes);
				}
			}
		}

		// Remove duplicates before processing (because the forbidden list uses both sets of arrays).
		$forbiddenListTags       = array_unique($forbiddenListTags);
		$forbiddenListAttributes = array_unique($forbiddenListAttributes);
		$customListTags          = array_unique($customListTags);
		$customListAttributes    = array_unique($customListAttributes);
		$allowedListTags         = array_unique($allowedListTags);
		$allowedListAttributes   = array_unique($allowedListAttributes);

		// Unfiltered assumes first priority.
		if ($unfiltered)
		{
			// Dont apply filtering.
			return false;
		}
		else
		{
			// Custom forbidden list precedes Default forbidden list.
			if ($customList)
			{
				$filter = InputFilter::getInstance([], [], 1, 1);

				// Override filter's default forbidden tags and attributes
				if ($customListTags)
				{
					$filter->blockedTags = $customListTags;
				}

				if ($customListAttributes)
				{
					$filter->blockedAttributes = $customListAttributes;
				}
			}
			// Forbidden list takes second precedence.
			elseif ($forbiddenList)
			{
				// Remove the allowed tags and attributes from the forbidden list.
				$forbiddenListTags       = array_diff($forbiddenListTags, $allowedListTags);
				$forbiddenListAttributes = array_diff($forbiddenListAttributes, $allowedListAttributes);

				$filter = InputFilter::getInstance($forbiddenListTags, $forbiddenListAttributes, 1, 1);

				// Remove allowed tags from filter's default forbidden list
				if ($allowedListTags)
				{
					$filter->blockedTags = array_diff($filter->blockedTags, $allowedListTags);
				}

				// Remove allowed attributes from filter's default forbidden list
				if ($allowedListAttributes)
				{
					$filter->blockedAttributes = array_diff($filter->blockedAttributes, $allowedListAttributes);
				}
			}
			// Allowed list take third precedence.
			elseif ($allowedList)
			{
				// Turn off XSS auto clean
				$filter = InputFilter::getInstance($allowedListTags, $allowedListAttributes, 0, 0, 0);
			}
			// No HTML takes last place.
			else
			{
				$filter = InputFilter::getInstance();
			}

			return $filter;
		}
	}
}
