<?php
namespace Engine\GenDocument\Image;

/**
 *
 * @author Dan Baluta
 *
 */
class ThumbnailCreator
{

	/**
	 * Destination directory where thumbs will be saved
	 */
	protected $thumbDir;

	/**
	 * Destination file format
	 *  jpg or png
	 */
	protected $thumbFormat = 'jpg';

	/**
	 * Thumb maximum width
	 */
	protected $maxWidth = 250;

	/**
	 * Thumb maximum height
	 */
	protected $maxHeight = 250;

	/**
	 * Thumb quality 0 to 10
	 */
	protected $thumbQuality = 7;


	/**
	 * Set thumbs folder
	 */
	public function setThumbDir($thumbDir)
	{
		//create thumbs folder if it doesn't exist
		if (!\Engine\Dir::check($thumbDir)) {
			\Engine\Dir::create($thumbDir);
		}
		$this->thumbDir = $thumbDir;
	}

	/**
	 * Set thumbs format
	 * @throws \Engine\GenDocument\Image\Exception
	 */
	public function setThumbFormat($thumbFormat)
	{
		if ($thumbFormat!='png' && $thumbFormat!='jpg'){
			throw new Exception("Invalid thumbnail format {$thumbFormat}");
		}
		$this->thumbFormat = $thumbFormat;
	}

	/**
	 * Set thumb max width
	 * @throws \Engine\GenDocument\Image\Exception
	 */
	public function setMaxWidth($maxWidth)
	{
		if (!$maxWidth || $maxWidth<0 || !is_numeric($maxWidth)) {
			throw new Exception("Invalid max width {$maxWidth}");
		}
		$this->maxWidth = $maxWidth;
	}

	/**
	 * Set thumb max height
	 * @throws \Engine\GenDocument\Image\Exception
	 */
	public function setMaxHeight($maxHeight)
	{
		if (!$maxHeight || $maxHeight<0 || !is_numeric($maxHeight)) {
			throw new Exception("Invalid max height {$maxHeight}");
		}
		$this->maxHeight = $maxHeight;
	}

	/**
	 * Set thumb quality 0-10
	 * @throws \Engine\GenDocument\Image\Exception
	 */
	public function setThumbQuality($thumbQuality)
	{
		if ($thumbQuality<0 or $thumbQuality>10) {
			throw new Exception("Invalid thumbnail quality {$thumbQuality}");
		}
		$this->thumbQuality = $thumbQuality;
	}

	/**
	 * Generate the path to the cache file on disk
	 * @return string
	 */
	protected function generateThumbnailPath($source)
	{
		//destination file
		$dest = $this->thumbDir.sprintf("%s-%s%d%d%d-%d.%s",
			preg_replace("/[^a-z0-9]/i", "", __CLASS__),
			md5($source),
			$this->maxWidth,
			$this->maxHeight,
			$this->thumbQuality,
			filemtime($source),
			$this->thumbFormat
		);

		return $dest;
	}

	/**
	 * Create a thumbnail file
	 * @throws Exception
	 * @return multitype:Ambigous <number, multitype:> Ambigous <number, unknown>
	 */
	protected function createThumbnail($source, $dest)
	{
		// get extension and real image type
		$extension = strtolower(pathinfo($source, PATHINFO_EXTENSION));
		$imagetype = exif_imagetype($source);

		$src = null;
		$is_image = false;
		switch ($imagetype) {
			case IMAGETYPE_GIF: // GIF
				$src = @imagecreatefromgif($source);
				if ($src) {
					$is_image = true;
				} else {
					throw new Exception("Invalid GIF file");
				}
			break;

			case IMAGETYPE_JPEG: // JPEG
				$src = @imagecreatefromjpeg($source);
				if ($src) {
					$is_image = true;
				} else {
					throw new Exception("Invalid JPEG file");
				}
			break;

			case IMAGETYPE_PNG: // PNG
				$src = @imagecreatefrompng($source);
				if ($src) {
					$is_image = true;
				} else {
					throw new Exception("Invalid PNG file");
				}
			break;

			default:
				throw new Exception("Unsupported image type: {$extension}");
		}

		//is image?
		if (!$is_image) {
			throw new Exception("Invalid source file extension {$extension}");
		}

		list($width, $height) = getimagesize($source);

		if ($this->maxWidth<$width) {
			$newWidth  = $this->maxWidth;
			$newHeight = (int)(($newWidth/$width)*$height);
		}
		elseif ($this->maxHeight<$height) {
			$newHeight = $this->maxHeight;
			$newWidth  = (int)(($newHeight/$height)*$width);
		}
		else {
			$newWidth  = $width;
			$newHeight = $height;
		}

		$tmp = imagecreatetruecolor($newWidth, $newHeight);

		//Destination file
		if ($this->thumbFormat=='jpg') {
			/* white background instead of transparency in jpg files */
			$white = imagecolorallocate($tmp,  255, 255, 255);
			imagefilledrectangle($tmp, 0, 0, $newWidth, $newHeight, $white);

			//resize image
			imagecopyresampled($tmp,$src,0,0,0,0,$newWidth,$newHeight,$width,$height);

			//save with quality
			imagejpeg($tmp, $dest, $this->thumbQuality*10);
		}
		elseif ($this->thumbFormat=='png') {
			/* preserve transparency in png files */
			imagealphablending($tmp, false);
			imagesavealpha($tmp, true);
			$transparent = imagecolorallocatealpha($tmp, 255, 255, 255, 127);
			imagefilledrectangle($tmp, 0, 0, $newWidth, $newHeight, $transparent);

			//resize image
			imagecopyresampled($tmp,$src,0,0,0,0,$newWidth,$newHeight,$width,$height);

			//save with quality
			imagepng($tmp, $dest, 9);
		}
		else {
			throw new Exception("Implementation not available for this format {$this->thumbFormat}");
		}

		//destroy temp files
		imagedestroy($src);
		imagedestroy($tmp);

		return [$newWidth, $newHeight];
	}

	/**
	 * Generate file thumbnail
	 * @throws \Engine\GenDocument\Image\Exception
	 */
	public function createCached($source)
	{
		if (!is_file($source) || !is_readable($source)) {
			throw new Exception("Invalid source file {$source}");
		}

		//original dimensions and size
		list($originalWidth, $originalHeight) = getimagesize($source);

		$originalSize = filesize($source);
		$originalName = \Engine\File::getNameFull($source);
		$originalMtime = filemtime($source);

		//destination file
		$dest = $this->generateThumbnailPath($source);

		// destination already exists?
		$cacheHit = false;
		if (is_file($dest)) {
			$cacheHit = true;
			list($thumbWidth, $thumbHeight) = getimagesize($dest);
		}
		else {
			$cacheHit = false;
			list($thumbWidth, $thumbHeight) = $this->createThumbnail($source, $dest);
		}

		$thumbInfo = [
			'originalWidth' => 	$originalWidth,
			'originalHeight' => $originalHeight,
			'originalSize' => 	$originalSize,
			'originalName' => 	$originalName,
			'originalMtime' => 	$originalMtime,
			'file' => 			$dest,
			'width' => 			$thumbWidth,
			'height' => 		$thumbHeight,
			'cacheHit' => 		$cacheHit,
		];

		return $thumbInfo;
	}
}