<?php

/*
 * This file is part of Contao.
 *
 * (c) Leo Feyer
 *
 * @license LGPL-3.0-or-later
 */

namespace Contao;

use Contao\Image\ImportantPart;
use Contao\Image\PictureConfiguration;
use Contao\Image\PictureConfigurationItem;
use Contao\Image\ResizeConfiguration;
use Contao\Image\ResizeOptions;
use Contao\Model\Collection;

trigger_deprecation('contao/core-bundle', '4.3', 'Using the "Contao\Picture" class has been deprecated and will no longer work in Contao 5.0. Use the "contao.image.picture_factory" service instead.');

/**
 * Resizes images and creates picture data
 *
 * The class resizes images and prepares data for the `<picture>` element.
 *
 * Usage:
 *
 *     $picture = new Picture(new File('example.jpg'));
 *
 *     $data = $picture
 *         ->setImportantPart(array('x'=>10, 'y'=>10, 'width'=>100, 'height'=>100))
 *         ->setImageSize(ImageSizeModel::findByPk(1))
 *         ->setImageSizeItems(ImageSizeItemModel::findVisibleByPid(1, array('order'=>'sorting ASC')))
 *         ->getTemplateData()
 *     ;
 *
 *     // Shortcut
 *     $data = Picture::create('example.jpg', 1)->getTemplateData();
 *     $data = Picture::create('example.jpg', array(100, 100, 'crop'))->getTemplateData();
 *
 * @deprecated Deprecated since Contao 4.3, to be removed in Contao 5.0.
 *             Use the contao.image.picture_factory service instead.
 */
class Picture
{
	/**
	 * The Image instance of the source image
	 *
	 * @var Image
	 */
	protected $image;

	/**
	 * The image size
	 *
	 * @var ImageSizeModel|object
	 */
	protected $imageSize;

	/**
	 * The image size items collection
	 *
	 * @var array<ImageSizeItemModel|object>|Collection
	 */
	protected $imageSizeItems = array();

	/**
	 * Create a new object to handle a picture element
	 *
	 * @param File $file A file instance of the source image
	 */
	public function __construct(File $file)
	{
		$this->image = new Image($file);
	}

	/**
	 * Create a picture instance from the given image path and size
	 *
	 * @param string|File          $file The image path or File instance
	 * @param array|integer|string $size The image size as array (width, height, resize mode) or a tl_image_size ID or a predefined image size key
	 *
	 * @return static The created picture instance
	 */
	public static function create($file, $size=null)
	{
		if (\is_string($file))
		{
			$file = new File(rawurldecode($file));
		}

		$picture = new static($file);

		if (\is_array($size) && !empty($size[2]))
		{
			// tl_image_size ID as resize mode
			if (is_numeric($size[2]))
			{
				$size = (int) $size[2];
			}

			// Predefined image size as resize mode
			elseif (\is_string($size[2]) && $size[2][0] === '_')
			{
				$size = $size[2];
			}
		}

		$imageSize = null;

		if (!\is_array($size) && (!\is_string($size) || $size[0] !== '_'))
		{
			$imageSize = ImageSizeModel::findByPk($size);

			if ($imageSize === null)
			{
				$size = array();
			}
		}

		if (\is_string($size) && $size[0] === '_')
		{
			$imageSize = $size;
		}

		if (\is_array($size))
		{
			$size += array(0, 0, 'crop');

			$imageSize = new \stdClass();
			$imageSize->width = $size[0];
			$imageSize->height = $size[1];
			$imageSize->resizeMode = $size[2];
			$imageSize->zoom = 0;
		}

		$picture->setImageSize($imageSize);

		if ($imageSize !== null && !empty($imageSize->id))
		{
			$picture->setImageSizeItems(ImageSizeItemModel::findVisibleByPid($imageSize->id, array('order'=>'sorting ASC')));
		}

		$fileRecord = FilesModel::findByPath($file->path);
		$currentSize = $file->imageViewSize;

		if ($fileRecord !== null && $fileRecord->importantPartWidth && $fileRecord->importantPartHeight)
		{
			$picture->setImportantPart(array
			(
				'x' => (int) ($fileRecord->importantPartX * $currentSize[0]),
				'y' => (int) ($fileRecord->importantPartY * $currentSize[1]),
				'width' => (int) ($fileRecord->importantPartWidth * $currentSize[0]),
				'height' => (int) ($fileRecord->importantPartHeight * $currentSize[1]),
			));
		}

		return $picture;
	}

	/**
	 * Set the important part settings
	 *
	 * @param array $importantPart The settings array
	 *
	 * @return $this The picture object
	 */
	public function setImportantPart(?array $importantPart = null)
	{
		$this->image->setImportantPart($importantPart);

		return $this;
	}

	/**
	 * Set the image size
	 *
	 * @param ImageSizeModel|object|string $imageSize The image size or a predefined image size key
	 *
	 * @return $this The picture object
	 */
	public function setImageSize($imageSize)
	{
		$this->imageSize = $imageSize;

		return $this;
	}

	/**
	 * Set the image size items collection
	 *
	 * @param array<ImageSizeItemModel|object>|Collection $imageSizeItems The image size items collection
	 *
	 * @return $this The picture object
	 */
	public function setImageSizeItems($imageSizeItems)
	{
		if ($imageSizeItems === null)
		{
			$imageSizeItems = array();
		}

		$this->imageSizeItems = $imageSizeItems;

		return $this;
	}

	/**
	 * Get the picture element definition array
	 *
	 * @return array The picture element definition
	 */
	public function getTemplateData()
	{
		$projectDir = System::getContainer()->getParameter('kernel.project_dir');
		$image = System::getContainer()->get('contao.image.factory')->create($projectDir . '/' . $this->image->getOriginalPath());

		if (\is_string($this->imageSize) && $this->imageSize[0] === '_')
		{
			$config = $this->imageSize;
		}
		else
		{
			$config = new PictureConfiguration();
			$config->setSize($this->getConfigurationItem($this->imageSize));

			$sizeItems = array();

			foreach ($this->imageSizeItems as $imageSizeItem)
			{
				$sizeItems[] = $this->getConfigurationItem($imageSizeItem);
			}

			$config->setSizeItems($sizeItems);
		}

		$importantPart = $this->image->getImportantPart();
		$imageSize = $image->getDimensions()->getSize();

		$image->setImportantPart(
			new ImportantPart(
				$importantPart['x'] / $imageSize->getWidth(),
				$importantPart['y'] / $imageSize->getHeight(),
				$importantPart['width'] / $imageSize->getWidth(),
				$importantPart['height'] / $imageSize->getHeight()
			)
		);

		$container = System::getContainer();
		$staticUrl = $container->get('contao.assets.files_context')->getStaticUrl();

		$picture = $container
			->get('contao.image.picture_factory')
			->create(
				$image,
				$config,
				(new ResizeOptions())
					->setImagineOptions($container->getParameter('contao.image.imagine_options'))
					->setBypassCache($container->getParameter('contao.image.bypass_cache'))
					->setSkipIfDimensionsMatch(true)
			)
		;

		return array
		(
			'img' => $picture->getImg($projectDir, $staticUrl),
			'sources' => $picture->getSources($projectDir, $staticUrl),
		);
	}

	/**
	 * Get the config for one picture source element
	 *
	 * @param ImageSizeModel|ImageSizeItemModel|object $imageSize The image size or image size item model
	 *
	 * @return PictureConfigurationItem
	 */
	protected function getConfigurationItem($imageSize)
	{
		$configItem = new PictureConfigurationItem();
		$resizeConfig = new ResizeConfiguration();

		$mode = $imageSize->resizeMode;

		if (substr_count($mode, '_') === 1)
		{
			$importantPart = $this->image->setImportantPart()->getImportantPart();

			$mode = explode('_', $mode);

			if ($mode[0] === 'left')
			{
				$importantPart['width'] = 1;
			}
			elseif ($mode[0] === 'right')
			{
				$importantPart['x'] = $importantPart['width'] - 1;
				$importantPart['width'] = 1;
			}

			if ($mode[1] === 'top')
			{
				$importantPart['height'] = 1;
			}
			elseif ($mode[1] === 'bottom')
			{
				$importantPart['y'] = $importantPart['height'] - 1;
				$importantPart['height'] = 1;
			}

			$this->image->setImportantPart($importantPart);

			$mode = ResizeConfiguration::MODE_CROP;
		}

		$resizeConfig
			->setWidth((int) $imageSize->width)
			->setHeight((int) $imageSize->height)
			->setZoomLevel((int) $imageSize->zoom)
		;

		if ($mode)
		{
			$resizeConfig->setMode($mode);
		}

		$configItem->setResizeConfig($resizeConfig);

		if (isset($imageSize->sizes))
		{
			$configItem->setSizes($imageSize->sizes);
		}

		if (isset($imageSize->densities))
		{
			$configItem->setDensities($imageSize->densities);
		}

		if (isset($imageSize->media))
		{
			$configItem->setMedia($imageSize->media);
		}

		return $configItem;
	}
}

class_alias(Picture::class, 'Picture');
