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

/**
 * This class extends Kohana's [ORM] class to create defaults for TSM.
 *
 * @package    PTA
 * @subpackage Core
 * @category   ORM
 * @author     Deon George
 * @copyright  (c) 2010 phpTSMadmin Development Team
 * @license    http://dev.osbill.net/license.html
 */
abstract class ORM_TSM extends ORM {
	// Suppress ORMs inclusion of <table_name>.*
	protected $_disable_wild_select = TRUE;
	// Suppress ORMs inclusion of <table_name>. to column joins
	protected $_disable_join_table_name = TRUE;
	// Suppress ORMs use of limit
	protected $_disable_limit = TRUE;
	// To enable effective caching, this must disabled.
	protected $_reload_on_wakeup = FALSE;

	// Enable the formating of columns
	protected $_object_formated = array();
	protected $_formated = FALSE;
	protected $_formats = array();

	protected $_tsm = array();

	/**
	 *
	 * Configuration to enable PLA to work with DSMADMC & DB2 connections
	 * This is required, because the schema is different between each
	 * connection?
	 */
	protected function _initialize() {
		// Set out DB connection configuration.
		$this->_db_group = Kohana::$config->load('config')->client_type;

		// Adjustments for DSMADMC or DB2 connections
		if (array_key_exists($this->_db_group,$this->_tsm))
			foreach ($this->_tsm[$this->_db_group] as $k => $v)
				if (preg_match('/^_/',$k))
					$this->{$k} = $v;

		if ($this->_db_group == 'db2')
			$this->_disable_join_table_name = FALSE;

		parent::_initialize();
	}

	public function __get($column) {
		// Get a substited column name - need for DB2/DSMADMC schema differences
		if (isset($this->_tsm[$this->_db_group]['translate']) AND array_key_exists($column,$this->_tsm[$this->_db_group]['translate']))
			return is_null($c=$this->_tsm[$this->_db_group]['translate'][$column]) ? NULL : parent::__get($c);
		else
			return parent::__get($column);
	}

	public function find() {
		Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__));

		Log::instance()->add(LOG::DEBUG,'METHOD :method: isCacheable: :cable, table: :table',array(':method'=>__METHOD__,':cable'=>($x=$this->isCacheable()) ? $x : 'N',':table'=>$this->_table_name));
		// Check if we can preload our data and havent already done it
		// Kohana uses Kohana::cache here, instead of Cache()
		if ($time = $this->isCacheable() AND is_null(Kohana::cache($cache_key = 'PRELOAD:'.$this->_table_name))) {
			Log::instance()->add(LOG::DEBUG,'PRELOADING :method: table: :table',array(':method'=>__METHOD__,':table'=>$this->_table_name));

			// Firstly set our cache, so that we dont get in a loop
			Kohana::cache($cache_key,TRUE,$time-1);

			// Find all records of this type
			$c = get_class($this);
			$x = new $c;

			foreach ($x->find_all() as $record) {
				// Simulate loading the record so that we can get the SQL to use as our cache key
				$y = new $c;
				$y->where($y->_primary_key,'=',(string)$record);

				// Code, as extracted from ORM to complete building the SQL
				$y->_build(Database::SELECT);
				$y->_db_builder->from(array($y->_table_name,$y->_object_name));
				if (! isset($y->_db_applied['order_by']) AND ! empty($y->_sorting))
					foreach ($y->_sorting as $column => $direction) {
						if (strpos($column, '.') === FALSE)
							// Sorting column for use in JOINs
							$column = ($y->_disable_join_table_name ? '' : $y->_table_name.'.').$column;

						$y->_db_builder->order_by($column, $direction);
					}

				// Set the cache key based on the database instance name and SQL
				$cache_key = 'Database::query("'.$y->_db.'", "'.(string)$y->_db_builder.'")';
				unset($y);

				// Cache the record, our subsequent find should get a cache hit now.
				Kohana::cache($cache_key, array($record->as_array()), $time);
				Log::instance()->add(LOG::DEBUG,'Cache SET for TIME: :time, KEY: :cache_key',array(':cache_key'=>$cache_key,':time'=>$time));
			}

			unset($x);
		}

		Log::instance()->add(LOG::DEBUG,'LEAVE :method',array(':method'=>__METHOD__));

		// Contiue as normal
		return parent::find();
	}

	private function isCacheable() {
		$config = Kohana::$config->load('database')->{Kohana::$config->load('config')->client_type};

		if ($config['caching'] AND isset($config['cachepreload'][$this->_table_name]) AND count($this->_db_pending) == 1 AND $this->_db_pending[0]['name'] == 'where' AND $this->_db_pending[0]['args'][0] == $this->_primary_key AND $this->_db_pending[0]['args'][1] == '=')
			return $config['cachepreload'][$this->_table_name];
		else
			return FALSE;
	}

	protected function _load_result($multiple = FALSE) {
		// We'll cache our query results
		if ($c = $this->_db->caching($this->_table_name))
			$this->_db_builder->cached($c);

		return parent::_load_result($multiple);
	}

	/**
	 * Proxy method to Database list_columns.
	 * This enables caching of the list_columns queries. Since this doesnt
	 * we hard code the cache to 7 days.
	 *
	 * @return array
	 * @todo This cache time needs to be better integrated with other caching times.
	 */
	public function list_columns() {
		// We'll cache our query results
		if ($this->_db->caching('SCHEMA')) {
			// Set the cache key based on the database instance name and SQL
			$cache_key = 'Database::query(LC:'.$this->_table_name.')';

			if (! is_null($result = Cache::instance()->get($cache_key)))
				// Return a cached result
				return $result;
		}

		// Proxy to database
		$result = $this->_db->list_columns($this->_table_name);

		// Cache the result array
		if (isset($cache_key))
			Cache::instance()->set($cache_key, $result, 604800);

		return $result;
	}

	// Load our values into the ORM object
	public function load_object(array $values) {
		return parent::_load_values($values);
	}

	public static function date($date,$format) {
		return $date ? date($format,strtotime($date)) : '';
	}

	protected function datatypemap($type) {
		$x = Kohana::$config->load('config')->tsmdatatypes;

		return array_key_exists($type,$x) ? $x[$type] : $x;
	}
}
?>
