<?php
/*
 * Copyright (c) 2013, webvariants GbR, http://www.webvariants.de
 *
 * This file is released under the terms of the MIT license. You can find the
 * complete text in the attached LICENSE file or online at:
 *
 * http://www.opensource.org/licenses/mit-license.php
 */

abstract class WV_Object {
	protected $_dirty   = false;
	protected $_deleted = false;

	private static $lastPDOException = null;

	public static function getLastPDOException() {
		return self::$lastPDOException;
	}

	protected function _set($attribute, $value, $policy = 'mixed') {
		$this->stopIfDeleted('WV_Exception', 'CANNOT_SET_IS_DELETED');

		$orig = isset($this->$attribute) ? $this->$attribute : null;

		switch ($policy) {
			case 'string':

				$this->$attribute = trim((string) $value);
				break;

			case 'bool':
			case 'boolean':

				$this->$attribute = (boolean) $value;
				break;

			case 'int':
			case 'integer':

				$this->$attribute = (int) $value;
				break;

			case 'uint':
			case 'uinteger':

				$this->$attribute = abs((int) $value);
				break;

			case 'float':
			case 'double':

				$this->$attribute = (float) $value;
				break;

			case 'ufloat':
			case 'udouble':

				$this->$attribute = abs((float) $value);
				break;

			case 'array':

				$this->$attribute = sly_makeArray($value);
				break;

			case 'uarray':

				$this->$attribute = array_unique(sly_makeArray($value));
				break;

			case 'intarray':

				$this->$attribute = array_map('intval', sly_makeArray($value));
				break;

			case 'uintarray':

				$this->$attribute = array_unique(array_map('intval', sly_makeArray($value)));
				break;

			case 'mixed':
			default:

				$this->$attribute = $value;
				break;
		}

		if ($orig !== $this->$attribute) {
			$this->_dirty = true;
		}

		// Wert zurückgeben, damit der Caller weiß, was wir aus $value gemacht haben.
		return $this->$attribute;
	}

	protected function setDirty($isDirty = true) {
		$this->_dirty = (boolean) $isDirty;
	}

	protected function setDeleted() {
		$this->_deleted = true;
	}

	public function isDirty() {
		return $this->_dirty;
	}

	public function isClean() {
		return !$this->_dirty;
	}

	public function isDeleted() {
		return $this->_deleted;
	}

	protected function stopIfDeleted($exceptionClass, $message, $code = -1) {
		if ($this->_deleted) {
			throw new $exceptionClass($message, $code);
		}
	}

	protected static function transactionGuard($callback, $params = array(), $exceptionClass = 'Exception') {
		$params = sly_makeArray($params);
		$sql    = WV_SQL::getInstance();

		if ($sql->isTransactionActive()) {
			return call_user_func_array($callback, $params);
		}

		$sql->beginTransaction();

		try {
			$retval = call_user_func_array($callback, $params);
			$sql->commit();
		}
		catch (Exception $e) {
			$sql->rollBack();

			self::$lastPDOException = $e;

			if (!empty($exceptionClass) && !($e instanceof $exceptionClass)) {
				// FUCK you, PHP: Bitchin' because second parameter is not a long
				// but PDOException returns a string in ->getCode(). Very clever...
				$e = new $exceptionClass($e->getMessage(), $e instanceof PDOException ? -1 : $e->getCode());
			}

			throw $e;
		}

		return $retval;
	}

	public static function getFromCache($namespace, $cacheKey, $callback, $params = array()) {
		$params   = sly_makeArray($params);
		$cache    = sly_Core::cache();
		$instance = $cache->get($namespace, $cacheKey);

		if (!$instance) {
			if ($cache->lock($namespace, $cacheKey)) {
				try {
					$instance = call_user_func_array($callback, $params);
					$cache->set($namespace, $cacheKey, $instance);
					$cache->unlock($namespace, $cacheKey);
				}
				catch (Exception $e) {
					$cache->unlock($namespace, $cacheKey);
					throw $e;
				}
			}
			else {
				$instance = $cache->waitForObject($namespace, $cacheKey);

				if (!$instance) {
					$instance = call_user_func_array($callback, $params);
				}
			}
		}

		return $instance;
	}
}
