<?php
/*
* @package LabCMS
* @copyright (c) 2006 Alexander Levin aka Loki (loki_angel@mail.ru)
* @support http://labcms.ru
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*/

abstract class DefaultObject
{
	protected $data=array();
	protected $validation=HTML_QuickForm2_Rule::ONBLUR_CLIENT_SERVER;
	protected $cache_key;
	protected $cache_time=604800;//60*60*24*7
	
	public function getUserObj($user_id, &$users=array(), $user_data=array())
	{
		if (array_key_exists($user_id, $users)) return $users[$user_id];
		
		if ($user_id) {
			$user=User::getUser($user_id);
		} else {
			if (!count($user_data)) return null;
			$user=User::getUser();
			$user->set($user_data);
		}
		return $user;
	}
	
	protected function _getItemsByArrayId($id)
	{
		if (!$id) return array();

		if (config::get('core.cache_solid')) {
			return $this->_getItemsByArrayIdSolid($id);
		}

		if (!is_array($id)) $id = array($id);
		$idNeedToGet = array_unique($id);
		$result = array();

		$cacheKeys = build_cache_keys($idNeedToGet, $this->_getCacheKey());
		if (false !== ($data = TCache::get($cacheKeys))) {
			foreach ($cacheKeys as $id => $key) {
				if (array_key_exists($id, $data)) {
					if ($data[$id]) {
						$result[$data[$id]->id] = $data[$id];
					}
					unset($cacheKeys[$id]);
				}
			}
		}

		//если остались ключи без значений, то запрашиваем данные из хранилища
		if (count($cacheKeys) && $data = $this->_getItemsByArrayIdFromStorage(array_keys($cacheKeys))) {
			foreach ($data as $item) {
				$result[$item->id] = $item;
				TCache::Set($item, $this->_getCacheKey().$item->id, array(), $this->_getCacheTime());
				unset($cacheKeys[$item->id]);
			}
		}

		//если и теперь остались ключи без результата, то сохраняем их в кэш пустыми
		if (count($cacheKeys)) {
			foreach ($cacheKeys as $id=>$key) {
				TCache::Set(null, $key, array(), $this->_getCacheTime());
			}
		}
		$result = array_sort_by_keys($result, $idNeedToGet);
		return $result;
	}

	protected function _getItemsByArrayIdSolid($id)
	{
		if (!is_array($id)) {
			$id = array($id);
		}
		$id = array_unique($id);
		$result = array();
		$key = $this->_getCacheKey().implode('_', $id);
		if (false === ($data = TCache::get($key))) {
			$data = $this->_getItemsByArrayIdFromStorage($id);
			foreach ($data as $item) {
				$result[$item->id] = $item;
			}
			TCache::Set($result, $key, array($this->_getCacheKeyCommon()), $this->_getCacheTime());
			return $result;
		}
		return $data;
	}

	protected function _getItemsByArrayIdFromStorage($id){trigger_error('not implemented _getItemsByArrayIdFromStorage');}

	protected function _getCacheTime()
	{
		return $this->cache_time;
	}
	protected function _getCacheKey()
	{
		if (!$this->cache_key) die('Не указан cache_key в '.get_class($this));
		return $this->cache_key;
	}

	protected function _getCacheKeyCommon()
	{
		if (!$this->cache_key) die('Не указан cache_key в '.get_class($this));
		return $this->cache_key.'_update';
	}

	public function getArray()
	{
		trigger_error('deprecated', E_USER_NOTICE);
		return $this->data;
	}
	
	public function update($data)
	{
		trigger_error('deprecated', E_USER_NOTICE);
		$this->_filterKeys($data);
		if ($this->_updateDB($data)) {
			$this->set($data);
			$this->_resetItemCache();
			return true;
		}
		return false;
	}
	
	//TODO to delete
	//abstract protected function _updateDB(&$data);
	//abstract protected function _resetItemCache();
	
	protected function _filterKeys(&$data)
	{
		trigger_error('deprecated', E_USER_NOTICE);
		if ($this->allowed_keys==null) {
			$error=get_class($this) . ': allowed_keys must be an array';
			error_log($error, 0);
			die($error);
		}
		foreach ($data as $key=>$v) {
			if (!in_array($key, $this->allowed_keys)) unset($data[$key]);
		}
	}
	
	public function __set($key, $value)
	{
		$this->data[$key]=$value;
	}
	
	// ссылка нужна для корректной работы с массивами вида $this->arr['key']
	public function &__get($key)
	{
		if (array_key_exists($key, $this->data)) {
			return $this->data[$key];
		} else {
			//эта конструкция тут потому, что метод по ссылке может возвращать только переменную
			$null=null;
			return $null;
		}
	}
	
	public function set($data)
	{
		foreach ($data as $k=>$v) {
			$this->__set($k, $v);
		}
	}
	
	// ссылка нужна для корректной работы с массивами вида $this->arr['key']
	public function &__isset($key)
	{
		//по ссылке может быть возвращена только переменная
		$result=array_key_exists($key, $this->data);
		return $result;
	}
}