<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\HTML\Helpers;

\defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\Database\ParameterType;
use Joomla\Utilities\ArrayHelper;

/**
 * Utility class for categories
 *
 * @since  1.5
 */
abstract class Category
{
	/**
	 * Cached array of the category items.
	 *
	 * @var    array
	 * @since  1.5
	 */
	protected static $items = array();

	/**
	 * Returns an array of categories for the given extension.
	 *
	 * @param   string  $extension  The extension option e.g. com_something.
	 * @param   array   $config     An array of configuration options. By default, only
	 *                              published and unpublished categories are returned.
	 *
	 * @return  array
	 *
	 * @since   1.5
	 */
	public static function options($extension, $config = array('filter.published' => array(0, 1)))
	{
		$hash = md5($extension . '.' . serialize($config));

		if (!isset(static::$items[$hash]))
		{
			$config = (array) $config;
			$db     = Factory::getDbo();
			$user   = Factory::getUser();
			$groups = $user->getAuthorisedViewLevels();

			$query = $db->getQuery(true)
				->select(
					[
						$db->quoteName('a.id'),
						$db->quoteName('a.title'),
						$db->quoteName('a.level'),
						$db->quoteName('a.language'),
					]
				)
				->from($db->quoteName('#__categories', 'a'))
				->where($db->quoteName('a.parent_id') . ' > 0');

			// Filter on extension.
			$query->where($db->quoteName('a.extension') . ' = :extension')
				->bind(':extension', $extension);

			// Filter on user access level
			$query->whereIn($db->quoteName('a.access'), $groups);

			// Filter on the published state
			if (isset($config['filter.published']))
			{
				if (is_numeric($config['filter.published']))
				{
					$query->where($db->quoteName('a.published') . ' = :published')
						->bind(':published', $config['filter.published'], ParameterType::INTEGER);
				}
				elseif (is_array($config['filter.published']))
				{
					$config['filter.published'] = ArrayHelper::toInteger($config['filter.published']);
					$query->whereIn($db->quoteName('a.published'), $config['filter.published']);
				}
			}

			// Filter on the language
			if (isset($config['filter.language']))
			{
				if (is_string($config['filter.language']))
				{
					$query->where($db->quoteName('a.language') . ' = :language')
						->bind(':language', $config['filter.language']);
				}
				elseif (is_array($config['filter.language']))
				{
					$query->whereIn($db->quoteName('a.language'), $config['filter.language'], ParameterType::STRING);
				}
			}

			// Filter on the access
			if (isset($config['filter.access']))
			{
				if (is_numeric($config['filter.access']))
				{
					$query->where($db->quoteName('a.access') . ' = :access')
						->bind(':access', $config['filter_access'], ParameterType::INTEGER);
				}
				elseif (is_array($config['filter.access']))
				{
					$config['filter.access'] = ArrayHelper::toInteger($config['filter.access']);
					$query->whereIn($db->quoteName('a.access'), $config['filter.access']);
				}
			}

			$query->order($db->quoteName('a.lft'));

			$db->setQuery($query);
			$items = $db->loadObjectList();

			// Assemble the list options.
			static::$items[$hash] = array();

			foreach ($items as &$item)
			{
				$repeat = ($item->level - 1 >= 0) ? $item->level - 1 : 0;
				$item->title = str_repeat('- ', $repeat) . $item->title;

				if ($item->language !== '*')
				{
					$item->title .= ' (' . $item->language . ')';
				}

				static::$items[$hash][] = HTMLHelper::_('select.option', $item->id, $item->title);
			}
		}

		return static::$items[$hash];
	}

	/**
	 * Returns an array of categories for the given extension.
	 *
	 * @param   string  $extension  The extension option.
	 * @param   array   $config     An array of configuration options. By default, only published and unpublished categories are returned.
	 *
	 * @return  array   Categories for the extension
	 *
	 * @since   1.6
	 */
	public static function categories($extension, $config = array('filter.published' => array(0, 1)))
	{
		$hash = md5($extension . '.' . serialize($config));

		if (!isset(static::$items[$hash]))
		{
			$config = (array) $config;
			$user = Factory::getUser();
			$db = Factory::getDbo();
			$query = $db->getQuery(true)
				->select(
					[
						$db->quoteName('a.id'),
						$db->quoteName('a.title'),
						$db->quoteName('a.level'),
						$db->quoteName('a.parent_id'),
						$db->quoteName('a.language'),
					]
				)
				->from($db->quoteName('#__categories', 'a'))
				->where($db->quoteName('a.parent_id') . ' > 0');

			// Filter on extension.
			$query->where($db->quoteName('extension') . ' = :extension')
				->bind(':extension', $extension);

			// Filter on user level.
			$groups = $user->getAuthorisedViewLevels();
			$query->whereIn($db->quoteName('a.access'), $groups);

			// Filter on the published state
			if (isset($config['filter.published']))
			{
				if (is_numeric($config['filter.published']))
				{
					$query->where($db->quoteName('a.published') . ' = :published')
						->bind(':published', $config['filter.published'], ParameterType::INTEGER);
				}
				elseif (is_array($config['filter.published']))
				{
					$config['filter.published'] = ArrayHelper::toInteger($config['filter.published']);
					$query->whereIn($db->quoteName('a.published'), $config['filter.published']);
				}
			}

			$query->order($db->quoteName('a.lft'));

			$db->setQuery($query);
			$items = $db->loadObjectList();

			// Assemble the list options.
			static::$items[$hash] = array();

			foreach ($items as &$item)
			{
				$repeat = ($item->level - 1 >= 0) ? $item->level - 1 : 0;
				$item->title = str_repeat('- ', $repeat) . $item->title;

				if ($item->language !== '*')
				{
					$item->title .= ' (' . $item->language . ')';
				}

				static::$items[$hash][] = HTMLHelper::_('select.option', $item->id, $item->title);
			}

			// Special "Add to root" option:
			static::$items[$hash][] = HTMLHelper::_('select.option', '1', Text::_('JLIB_HTML_ADD_TO_ROOT'));
		}

		return static::$items[$hash];
	}
}
