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

/**
 * This class overrides Kohana's ORM
 *
 * This file contains enhancements for Kohana, that should be considered upstream and maybe havent been yet.
 * It also contains some functionality for OSB, which cannot be covered in ORM_OSB.
 *
 * @package    WWZ
 * @category   Modifications
 * @author     Deon George
 * @copyright  (c) 2014 Deon George
 * @license    http://dev.leenooks.net/license.html
 */
abstract class lnApp_ORM extends Kohana_ORM {
	protected $_table_names_plural = FALSE;
	protected $_model_names_plural = FALSE;
	private $_object_formated = array();
	private $_formated = FALSE;

	// Our filters used to display values in a friendly format
	protected $_display_filters = array();

	// Whether to show a SystemMessage when a record is saved.
	protected $_save_message = FALSE;

	/**
	 * Format fields for display purposes
	 *
	 * @param string column name
	 * @return mixed
	 */
	private function _format() {
		foreach ($this->_display_filters as $column => $formats)
			$this->_object_formated[$column] = $this->run_filter($column,$this->__get($column),array($column=>$formats));

		$this->_formated = TRUE;
	}

	/**
	 * Overrides Kohana cache so that it can be globally disabled.
	 */
	public function cached($lifetime=NULL) {
		return $this->_db->caching($this->_table_name) ? parent::cached($lifetime) : $this;
	}

	public function clear() {
		$this->_formated = FALSE;
		$this->_object_formated = array();

		return parent::clear();
	}

	/**
	 * Return a formated columns, as per the model definition
	 */
	public function display($column) {
		// Trigger a load of the record.
		$value = $this->__get($column);

		// If some of our fields need to be formated for display purposes.
		if (! $this->_formated AND $this->_display_filters)
			$this->_format();

		if (isset($this->_object_formated[$column]))
			return $this->_object_formated[$column];
		else
			return is_array($value) ? join(', ',$value) : $value;
	}

	public function display_filters(array $filters) {
		$this->_display_filters = Arr::merge($this->_display_filters,$filters);
	}

	public function dump() {
		$result = array();

		$result['this'] = $this->object();

		if (isset($this->_sub_items))
			foreach ($this->_sub_items as $o)
				$result['sub'][] = $o->dump();

		return $result;
	}

	/**
	 * This function is our AJAX helper, used by module list_autocomplete()
	 */
	public function list_autocomplete($term,$index,$value,array $label,array $limit=array(),array $options=NULL) {
		$result = array();

		$query = empty($options['object']) ? $this : $options['object'];

		foreach ($limit as $w) {
			list($k,$s,$v) = $w;

			$query->and_where($k,$s,$v);
		}

		$c = 0;
		foreach ((empty($options['object']) ? $query->find_all() : $query->execute()) as $o) {
			// If we got here via a DB query, we need to reload our ORM object from the result.
			if (! is_object($o)) {
				if (empty($options['key']))
					throw new Kohana_Exception('Missing key for non object');

				$o = $this->clear()->where($options['key'],'=',$o[$options['key']])->find();
			}

			switch ($index) {
				case 'url':
					if (empty($options['urlprefix']))
						throw new Kohana_Exception('Missing URL Prefix');

					$v = $options['urlprefix'].$o->resolve($value);

					break;

				default: $v = $o->resolve($value);
			}

			$k = '';
			foreach ($label as $k => $details)
				foreach ($details as $lvalue)
					$k = preg_replace('/%s/',$o->resolve($lvalue),$k,1);

			$result[$c++] = array(
				'value'=>$v,
				'label'=>$k,
			);
		}

		return $result;
	}

	/**
	 * Return an array of data that can be used in a SELECT statement.
	 * The ID and VALUE is defined in the model for the select.
	 */
	public function list_select($blank=FALSE,$object=NULL) {
		$result = array();

		if (is_null($object))
			$object = $this->find_all();

		if ($blank)
			$result[NULL] = '';

		if ($this->_form AND array_intersect(array('id','value'),$this->_form))
			foreach ($object as $o)
				$result[$o->{$this->_form['id']}] = $o->resolve($this->_form['value']);

		return $result;
	}

	/**
	 * This function is used so that methods can be called via variables
	 */
	public function resolve($key) {
		eval("\$x = \$this->$key;");

		return $x;
	}

	public function save(Validation $validation=NULL) {
		parent::save();

		if ($this->saved() AND $this->_save_message AND (PHP_SAPI !== 'cli'))
			SystemMessage::factory()
				->title('Record Updated')
				->type('success')
				->body(sprintf('Record %s:%s Updated',$this->_table_name,$this->id));

		return $this;
	}

	/**
	 * We override this function, because we do set our own primary key value
	 */
	public function values(array $values, array $expected = NULL) {
		parent::values($values,$expected);

		if (isset($values[$this->_primary_key]))
			$this->{$this->_primary_key} = $values[$this->_primary_key];

		return $this;
	}
}
?>
