<?php

namespace App\Models;

use DB;
use Illuminate\Support\Facades\Log;

class Photo extends Abstracted\Catalog
{
	protected $table = 'photo';

	// Imagick Object
	private $_o;

	// How should the image be rotated, based on the value of orientation
	private $_rotate = [
		3=>180,
		6=>90,
		8=>-90,
	];

	public function software()
	{
		return $this->belongsTo(Software::class);
	}

	/**
	 * Date the photo was taken
	 */
	public function date_taken(): string
	{
		return $this->date_created ? (date('Y-m-d H:i:s',$this->date_created).($this->subsectime ? '.'.$this->subsectime : '')) : 'UNKNOWN';
	}

	/**
	 * Determine the new name for the image
	 * @todo Implement in Parent
	 */
	public function file_path($short=FALSE,$new=FALSE)
	{
		$file = $this->filename;

		if ($new)
			$file = sprintf('%s.%s',((is_null($this->date_created) OR ! $this->date_created)
				? sprintf('UNKNOWN/%07s',$this->file_path_id())
				: sprintf('%s_%03s',$this->date_created->format('Y/m/d-His'),$this->subsectime).
					($this->subsectime ? '' : sprintf('-%05s',$this->id))),$this->type());

		return (($short OR preg_match('/^\//',$file)) ? '' : config('photo.dir').DIRECTORY_SEPARATOR).$file;
	}

	public function getIDLinkAttribute()
	{
		return $this->HTMLLinkAttribute($this->id,url('p/info').'/');
	}

	/**
	 * Return the image, rotated, minus exif data
	 */
	public function image()
	{
		if (is_null($imo = $this->o()))
			return NULL;

		if (array_key_exists('exif',$imo->getImageProfiles()))
			$imo->removeImageProfile('exif');

		$this->rotate($imo);

		return $imo->getImageBlob();
	}

	/**
	 * Calculate the GPS coordinates
	 */
	public static function latlon(array $coordinate,$hemisphere)
	{
		if (! $coordinate OR ! $hemisphere)
			return NULL;

		for ($i=0; $i<3; $i++)
		{
			$part = explode('/', $coordinate[$i]);

			if (count($part) == 1)
				$coordinate[$i] = $part[0];

			elseif (count($part) == 2)
				$coordinate[$i] = floatval($part[0])/floatval($part[1]);

			else
				$coordinate[$i] = 0;
		}

		list($degrees, $minutes, $seconds) = $coordinate;

		$sign = ($hemisphere == 'W' || $hemisphere == 'S') ? -1 : 1;

		return round($sign*($degrees+$minutes/60+$seconds/3600),$degrees > 100 ? 3 : 4);
	}

	/**
	 * Return an Imagick object or attribute
	 *
	 */
	protected function o($attr=NULL)
	{
		if (! file_exists($this->file_path()) OR ! is_readable($this->file_path()))
			return NULL;

		if (is_null($this->_o))
			$this->_o = new \Imagick($this->file_path());

		return is_null($attr) ? $this->_o : $this->_o->getImageProperty($attr);
	}

	/**
	 * Display the orientation of a photo
	 */
	public function orientation() {
		switch ($this->orientation) {
			case 1: return 'None!';
			case 3: return 'Upside Down';
			case 6: return 'Rotate Right';
			case 8: return 'Rotate Left';
			default:
				return 'unknown?';
		}
	}

	/**
	 * Rotate the image
	 */
	private function rotate(\Imagick $imo)
	{
		if (array_key_exists($this->orientation,$this->_rotate))
			$imo->rotateImage(new \ImagickPixel('none'),$this->_rotate[$this->orientation]);

		return $imo->getImageBlob();
	}

	public function property($property)
	{
		if (! $this->o())
			return NULL;

		switch ($property)
		{
			case 'creationdate':
				if ($this->property('exif:DateTimeOriginal') == '0000:00:00 00:00:00'
					&& $this->property('exif:DateTimeOriginal') == '0000:00:00 00:00:00')
					return NULL;

				return strtotime(
				$this->property('exif:DateTimeOriginal') && $this->property('exif:DateTimeOriginal') != '0000:00:00 00:00:00'
					? $this->property('exif:DateTimeOriginal')
					: $this->property('exif:DateTime'));
				break;

			case 'height': return $this->_o->getImageHeight();
			case 'orientation': return $this->_o->getImageOrientation();
			case 'signature': return $this->_o->getImageSignature();
			case 'width': return $this->_o->getImageWidth();

			default:
				return $this->_o->getImageProperty($property);
		}
	}

	public function properties()
	{
		return $this->o() ? $this->_o->getImageProperties() : [];
	}

	public function setDateCreated()
	{
		$this->date_created = $this->property('creationdate');
	}

	public function setLocation()
	{
		$this->gps_lat = static::latlon(preg_split('/,\s?/',$this->property('exif:GPSLatitude')),$this->property('exif:GPSLatitudeRef'));
		$this->gps_lon = static::latlon(preg_split('/,\s?/',$this->property('exif:GPSLongitude')),$this->property('exif:GPSLongitudeRef'));
		#$this->gps_altitude = $this->property('gps_altitude');
	}

	public function setMakeModel()
	{
		$this->make = $this->property('exif:Make') ? $this->property('exif:Make') : NULL;
		$this->model = $this->property('exif:Model') ? $this->property('exif:Model') : NULL;
		$this->software = $this->property('exif:Software') ? $this->property('exif:Software') : NULL;
	}

	public function setSignature()
	{
		$this->signature = $this->property('signature');
		$this->file_signature = md5_file($this->file_path());
		#$this->identifier = $this->property('identifier');
	}

	public function setSubSecTime()
	{
		$this->subsectime = $this->property('exif:SubSecTimeOriginal');

		// In case of an error.
		if ($this->subsectime > 32767)
			$this->subsectime = 32767;
	}

	public function setThumbnail()
	{
		try {
			$this->thumbnail = exif_thumbnail($this->file_path());
		} catch (\Exception $e) {
			// @todo Couldnt get the thumbnail, so we should create one.
			Log::info(sprintf('Unable to create thumbnail for %s (%s)',$this->id,$e->getMessage()));
		}

		if ($this->thumbnail === FALSE)
			$this->thumbnail = NULL;
	}

	/**
	 * Return the image's thumbnail
	 */
	public function thumbnail($rotate=TRUE)
	{
		if (! $this->thumbnail)
		{
			return $this->o()->thumbnailimage(200,200,true,true) ? $this->_o->getImageBlob() : NULL;
		}

		if (! $rotate OR ! array_key_exists($this->orientation,$this->_rotate) OR ! extension_loaded('imagick'))
			return $this->thumbnail;

		$imo = new \Imagick();
		$imo->readImageBlob($this->thumbnail);

		return $this->rotate($imo);
	}

	/**
	 * Return the extension of the image
	 * @todo mime-by-ext?
	 */
	public function type($mime=FALSE)
	{
		return strtolower($mime ? 'image/jpeg' : pathinfo($this->filename,PATHINFO_EXTENSION));
	}

	public function view()
	{
		return sprintf('<img height="240" src="%s"></img>',url('/p/thumbnail/'.$this->id));
	}
}