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

namespace Joomla\CMS\Extension;

\defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Application\CMSApplicationInterface;
use Joomla\CMS\Categories\CategoryInterface;
use Joomla\CMS\Categories\CategoryServiceInterface;
use Joomla\CMS\Categories\CategoryServiceTrait;
use Joomla\CMS\Categories\SectionNotFoundException;
use Joomla\CMS\Component\Router\RouterInterface;
use Joomla\CMS\Component\Router\RouterLegacy;
use Joomla\CMS\Component\Router\RouterServiceInterface;
use Joomla\CMS\Dispatcher\DispatcherInterface;
use Joomla\CMS\Dispatcher\LegacyComponentDispatcher;
use Joomla\CMS\Fields\FieldsServiceInterface;
use Joomla\CMS\Filesystem\Path;
use Joomla\CMS\Menu\AbstractMenu;
use Joomla\CMS\MVC\Factory\LegacyFactory;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Factory\MVCFactoryServiceInterface;
use Joomla\CMS\Tag\TagServiceInterface;
use Joomla\CMS\Tag\TagServiceTrait;

/**
 * Access to component specific services.
 *
 * @since  4.0.0
 */
class LegacyComponent
	implements ComponentInterface, MVCFactoryServiceInterface, CategoryServiceInterface, FieldsServiceInterface, RouterServiceInterface,
	TagServiceInterface
{
	use CategoryServiceTrait, TagServiceTrait {
		CategoryServiceTrait::getTableNameForSection insteadof TagServiceTrait;
		CategoryServiceTrait::getStateColumnForSection insteadof TagServiceTrait;
	}

	/**
	 * @var string
	 *
	 * @since  4.0.0
	 */
	private $component;

	/**
	 * LegacyComponentContainer constructor.
	 *
	 * @param   string  $component  The component
	 *
	 * @since  4.0.0
	 */
	public function __construct(string $component)
	{
		$this->component = str_replace('com_', '', $component);
	}

	/**
	 * Returns the dispatcher for the given application.
	 *
	 * @param   CMSApplicationInterface  $application  The application
	 *
	 * @return  DispatcherInterface
	 *
	 * @since   4.0.0
	 */
	public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface
	{
		return new LegacyComponentDispatcher($application);
	}

	/**
	 * Get the factory.
	 *
	 * @return  MVCFactoryInterface
	 *
	 * @since   4.0.0
	 * @throws  \UnexpectedValueException May be thrown if the factory has not been set.
	 */
	public function getMVCFactory(): MVCFactoryInterface
	{
		return new LegacyFactory;
	}

	/**
	 * Returns the category service.
	 *
	 * @param   array   $options  The options
	 * @param   string  $section  The section
	 *
	 * @return  CategoryInterface
	 *
	 * @since   4.0.0
	 * @throws  SectionNotFoundException
	 */
	public function getCategory(array $options = [], $section = ''): CategoryInterface
	{
		$classname = ucfirst($this->component) . ucfirst($section) . 'Categories';

		if (!class_exists($classname))
		{
			$path = JPATH_SITE . '/components/com_' . $this->component . '/helpers/category.php';

			if (!is_file($path))
			{
				throw new SectionNotFoundException;
			}

			include_once $path;
		}

		if (!class_exists($classname))
		{
			throw new SectionNotFoundException;
		}

		return new $classname($options);
	}

	/**
	 * Adds Count Items for Category Manager.
	 *
	 * @param   \stdClass[]  $items    The category objects
	 * @param   string       $section  The section
	 *
	 * @return  void
	 *
	 * @since   4.0.0
	 * @throws  \Exception
	 */
	public function countItems(array $items, string $section)
	{
		$helper = $this->loadHelper();

		if (!$helper || !\is_callable(array($helper, 'countItems')))
		{
			return;
		}

		$helper::countItems($items, $section);
	}

	/**
	 * Adds Count Items for Tag Manager.
	 *
	 * @param   \stdClass[]  $items      The content objects
	 * @param   string       $extension  The name of the active view.
	 *
	 * @return  void
	 *
	 * @since   4.0.0
	 * @throws  \Exception
	 */
	public function countTagItems(array $items, string $extension)
	{
		$helper = $this->loadHelper();

		if (!$helper || !\is_callable(array($helper, 'countTagItems')))
		{
			return;
		}

		$helper::countTagItems($items, $extension);
	}

	/**
	 * Returns a valid section for articles. If it is not valid then null
	 * is returned.
	 *
	 * @param   string  $section  The section to get the mapping for
	 * @param   object  $item     The item
	 *
	 * @return  string|null  The new section
	 *
	 * @since   4.0.0
	 */
	public function validateSection($section, $item = null)
	{
		$helper = $this->loadHelper();

		if (!$helper || !\is_callable(array($helper, 'validateSection')))
		{
			return $section;
		}

		return $helper::validateSection($section, $item);
	}

	/**
	 * Returns valid contexts.
	 *
	 * @return  array
	 *
	 * @since   4.0.0
	 */
	public function getContexts(): array
	{
		$helper = $this->loadHelper();

		if (!$helper || !\is_callable(array($helper, 'getContexts')))
		{
			return [];
		}

		return $helper::getContexts();
	}

	/**
	 * Returns the router.
	 *
	 * @param   CMSApplicationInterface  $application  The application object
	 * @param   AbstractMenu             $menu         The menu object to work with
	 *
	 * @return  RouterInterface
	 *
	 * @since  4.0.0
	 */
	public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface
	{
		$compname = ucfirst($this->component);
		$class = $compname . 'Router';

		if (!class_exists($class))
		{
			// Use the component routing handler if it exists
			$path = JPATH_SITE . '/components/com_' . $this->component . '/router.php';

			// Use the custom routing handler if it exists
			if (is_file($path))
			{
				require_once $path;
			}
		}

		if (class_exists($class))
		{
			$reflection = new \ReflectionClass($class);

			if (\in_array('Joomla\\CMS\\Component\\Router\\RouterInterface', $reflection->getInterfaceNames()))
			{
				return new $class($application, $menu);
			}
		}

		return new RouterLegacy($compname);
	}

	/**
	 * Returns the classname of the legacy helper class. If none is found it returns false.
	 *
	 * @return  boolean|string
	 *
	 * @since   4.0.0
	 */
	private function loadHelper()
	{
		$className = ucfirst($this->component) . 'Helper';

		if (class_exists($className))
		{
			return $className;
		}

		$file = Path::clean(JPATH_ADMINISTRATOR . '/components/com_' . $this->component . '/helpers/' . $this->component . '.php');

		if (!is_file($file))
		{
			return false;
		}

		\JLoader::register($className, $file);

		if (!class_exists($className))
		{
			return false;
		}

		return $className;
	}
}
