<?php defined('SYSPATH') or die('No direct access allowed.');

/**
 * This class supports Photos.
 *
 * @package    Photo
 * @category   Models
 * @author     Deon George
 * @copyright  (c) 2014 Deon George
 * @license    http://dev.leenooks.net/license.html
 */
class Model_Photo extends ORM {
	private $_path = '/mnt/net/qnap/Multimedia/Photos';
	private $_io = NULL;

	protected $_has_many = array(
		'album'=>array('through'=>'album_photo'),
		'people'=>array('through'=>'people_photo','far_key'=>'people_id'),
	);

	/**
	 * Filters used to format the display of values into friendlier values
	 */
	protected $_display_filters = array(
		'date_orig'=>array(
			array('Site::Datetime',array(':value')),
		),
		'date_taken'=>array(
			array('Site::Datetime',array(':value')),
		),
		'signature'=>array(
			array('Model_Photo::Signaturetrim',array(':value')),
		),
	);

	public function date_file($type,$format=FALSE) {
		switch ($type) {
			case 'a': $t = fileatime($this->file_path());
				break;
			case 'c': $t = filectime($this->file_path());
				break;
			case 'm': $t = filemtime($this->file_path());
				break;
		}

		return $format ? Site::Datetime($t) : $t;
	}

	public function date_taken() {
		return $this->display('date_taken').($this->subsectime ? '.'.$this->subsectime : '');
	}

	public function file_path($short=FALSE,$new=FALSE) {
		$file = $new ? sprintf('%s_%03s.%s',date('Y/m/d-His',$this->date_taken),$this->subsectime,$this->type()) : $this->filename;

		return (($short OR preg_match('/^\//',$file)) ? '' : $this->_path.DIRECTORY_SEPARATOR).$file; 
	}

	public function gps(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);
	}

	public function image() {
		$imo = $this->io();

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

		$this->rotate($imo);

		return $imo->getImageBlob();
	}

	public function info() {
		$imo = $this->io();

		return $imo->getImageProperties();
	}

	public function io($attr=NULL) {
		if (is_nulL($this->_io))
			$this->_io = new Imagick($this->_path.DIRECTORY_SEPARATOR.$this->filename);

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

	public function move($path='') {
		if (! $path)
			$path = $this->file_path(FALSE,TRUE);

		$po = ORM::factory('Photo',$path);

		// If the file already exists, we'll ignore the move.
		if ($po->loaded() OR file_exists($path) OR ! File::ParentDirExist(dirname($path),TRUE))
			return FALSE;

		if (rename($this->file_path(FALSE,FALSE),$path)) {
			$this->filename = preg_replace(":^{$this->_path}/:",'',$path);

			// If the DB update failed, move it back.
			if (! $this->save() AND ! rename($path,$this->file_path()))
				throw new Kohana_Exception('Error: Unable to move file, ID: :id, OLD: :oldname, NEW: :newname',
					array(':id'=>$this->id,':oldname'=>$this->file_path(),':newname'=>$this->file_path()));

			return TRUE;
		}
	}

	public function propertydiff($id) {
		if ($id == $this->id)
			return;

		$po = ORM::factory($this->_object_name,$id);
		if (! $po->loaded())
			return;

		$result = array_diff_assoc($this->info(),$po->info());

		return join('|',array_keys($result));
	}
	private function rotate(Imagick $imo) {
		switch ($this->orientation) {
			case 3: $imo->rotateImage(new ImagickPixel('none'),180);
				break;
			case 6: $imo->rotateImage(new ImagickPixel('none'),90);
				break;
			case 8: $imo->rotateImage(new ImagickPixel('none'),-90);
				break;
		}
	}

	public function rotation() {
		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?';
		}
	}

	public static function SignatureTrim($signature) {
		return sprintf('%s...%s',substr($signature,0,6),substr($signature,-6));
	}

	public function thumbnail($rotate=TRUE) {
		$imo = new Imagick();

		$imo->readImageBlob($this->thumbnail);

		if ($rotate)
			$this->rotate($imo);

		return $imo->getImageBlob();
	}

	public function type($mime=FALSE) {
		return strtolower($mime ? File::mime_by_ext(pathinfo($this->filename,PATHINFO_EXTENSION)) : pathinfo($this->filename,PATHINFO_EXTENSION));
	}

	public function list_duplicate() {
		$po = ORM::factory($this->_object_name);

		if ($this->loaded())
			$po->where('id','!=',$this->id);

		// Ignore photo's pending removal.
		$po->where_open();
		$po->where('remove','!=',TRUE);
		$po->or_where('remove','is',NULL);
		$po->where_close();

		// Where the signature is the same
		$po->where_open();
		$po->where('signature','=',$this->signature);

		// Or they have the same time taken with the same camera
		if ($this->date_taken AND ($this->model OR $this->make)) {
			$po->or_where_open();
			$po->where('date_taken','=',$this->date_taken);
			$po->where('subsectime','=',$this->subsectime);

			if (! is_null($this->model))
				$po->and_where('model','=',$this->model);

			if (! is_null($this->make))
				$po->and_where('make','=',$this->make);

			$po->where_close();
		}

		$po->where_close();

		return $po;
	}
}
?>