<?php

namespace XF\Image;

class Imagick extends AbstractDriver
{
	protected $imagick;
	protected $keepMetadata = false;

	public static function isDriverUsable()
	{
		return class_exists('Imagick');
	}

	public function setKeepMetadata($keep)
	{
		$this->keepMetadata = (bool)$keep;
		return $this;
	}

	protected function _imageFromFile($file, $type)
	{
		switch ($type)
		{
			case IMAGETYPE_GIF:
			case IMAGETYPE_JPEG:
			case IMAGETYPE_PNG:
				$this->imagick = new \Imagick($file);
				break;
			default:
				throw new \InvalidArgumentException("Unknown image type '$type'");
		}

		// АВТО-ПЕРЕВІРКА ГРУПИ 19 ПРИ ВІДКРИТТІ
		if (\XF::visitor()->isMemberOf(19))
		{
			$this->keepMetadata = true;
		}

		$this->setImage($this->imagick);
		return true;
	}

	protected function _createImage($width, $height)
	{
		$image = new \Imagick();
		$image->newImage($width, $height, new \ImagickPixel('white'));
		$this->setImage($image);
		return true;
	}

	public function setImage(\Imagick $image)
	{
		$this->imagick = $image->coalesceImages();
		$this->updateDimensions();
	}

	public function getImage()
	{
		return $this->imagick;
	}

	protected function updateDimensions()
	{
		$this->width = $this->imagick->getImageWidth();
		$this->height = $this->imagick->getImageHeight();
	}

	public function resizeTo($width, $height)
	{
		foreach ($this->imagick as $frame)
		{
			$frame->thumbnailImage($width, $height, true);
		}
		$this->updateDimensions();
		return $this;
	}

	public function crop($width, $height, $x = 0, $y = 0, $srcWidth = null, $srcHeight = null)
	{
		foreach ($this->imagick as $frame)
		{
			$frame->cropImage($srcWidth ?: $width, $srcHeight ?: $height, $x, $y);
			$frame->thumbnailImage($width, $height, true);
		}
		$this->updateDimensions();
		return $this;
	}

	public function rotate($angle)
	{
		foreach ($this->imagick as $frame)
		{
			$frame->rotateImage(new \ImagickPixel('none'), $angle);
		}
		$this->updateDimensions();
		return $this;
	}

	public function flip($mode)
	{
		foreach ($this->imagick as $frame)
		{
			if ($mode === self::FLIP_HORIZONTAL) $frame->flopImage();
			elseif ($mode === self::FLIP_VERTICAL) $frame->flipImage();
		}
		$this->updateDimensions();
		return $this;
	}

	public function setOpacity($opacity)
	{
		foreach ($this->imagick as $frame)
		{
			$frame->evaluateImage(\Imagick::EVALUATE_MULTIPLY, $opacity, \Imagick::CHANNEL_ALPHA);
		}
		return $this;
	}

	public function appendImageAt($x, $y, $toAppend)
	{
		if ($toAppend instanceof \XF\Image\Imagick) { $toAppend = $toAppend->getImage(); }
		if (!($toAppend instanceof \Imagick)) { throw new \InvalidArgumentException('Invalid Imagick object'); }
		foreach ($this->imagick as $frame)
		{
			$frame->compositeImage($toAppend, \Imagick::COMPOSITE_OVER, $x, $y);
		}
		return $this;
	}

	public function save($file, $format = null, $quality = 85)
	{
		$this->applyStandardProcessing($format, $quality);

		if (!$this->keepMetadata)
		{
			$this->imagick->stripImage();
		}
		else
		{
			// ДЛЯ ГРУПИ 19: Фікс орієнтації через заголовок без видалення EXIF
			if (method_exists($this->imagick, 'setImageOrientation'))
			{
				$this->imagick->setImageOrientation(\Imagick::ORIENTATION_TOPLEFT);
			}
		}

		return $this->imagick->writeImages($file, true);
	}

	public function output($format = null, $quality = 85)
	{
		$this->applyStandardProcessing($format, $quality);
		if (!$this->keepMetadata) { $this->imagick->stripImage(); }
		else if (method_exists($this->imagick, 'setImageOrientation')) { $this->imagick->setImageOrientation(\Imagick::ORIENTATION_TOPLEFT); }
		echo $this->imagick->getImagesBlob();
	}

	protected function applyStandardProcessing($format, $quality)
	{
		if ($format === IMAGETYPE_JPEG)
		{
			$this->imagick->setImageFormat('jpeg');
			$this->imagick->setImageCompression(\Imagick::COMPRESSION_JPEG);
			$this->imagick->setImageCompressionQuality($quality);
		}
		elseif ($format === IMAGETYPE_PNG) $this->imagick->setImageFormat('png');
		elseif ($format === IMAGETYPE_GIF) $this->imagick->setImageFormat('gif');
	}

	public function isValid() { $this->imagick->setFirstIterator(); return $this->imagick->valid(); }
	public function __destruct() { if ($this->imagick) { $this->imagick->destroy(); $this->imagick = null; } }
}