<?php

/**
 * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * @package fusionLib
 * @copyright Copyright (c) 2014 fusionLib. All rights reserved.
 * @link http://fusionlib.com
 */

/**
 * flCacheRedis Class
 *
 * Class to implement Redis based storage for caching.
 *
 * @see http://redis.io
 * @see https://github.com/nicolasff/phpredis
 *
 * @package fusionLib
 */
class flCacheRedis extends flCache {

	/**
	 * The Redis interface object.
	 *
	 * @var Redis
	 */
	private $cache = null;

	/**
	 * Construct the Redis cache.
	 *
	 * @param string|Redis $server String defining the server:port of the Redis server e.g. localhost:6379 or a Redis object to use.
	 * @param int $lifetime The default lifetime for objects in seconds.
	 * @param string $prefix Prefix for cache keys.
	 * @throws flCacheException
	 */
	function __construct($server, $lifetime = 3600, $prefix = '') {
		parent::__construct($lifetime, 'flCache.' . $prefix);

		if($server instanceof Redis)
			$this->cache = $server;
		else {
			// Test if PHPRedis is present
			if(extension_loaded('redis'))
				$this->cache = new Redis();
			else
				throw new flCacheException('The PhpRedis extension required by flCacheRedis is not available.');

			// Connect to servers
			$d = explode(':', $server);
			if(!isset($d[1])) $d[1] = 6379;
			if(!$this->cache->connect($d[0], isset($d[1]) ? $d[1] : 6379))
				throw new flCacheException('flCacheRedis failed to connect to the Redis server.');
		}
	}

	/**
	 * Get the inner interface object.
	 *
	 * @return Redis The inner interface object.
	 */
	function _getInnerObject() {
		return $this->cache;
	}

	/**
	 * Store an element in the cache.
	 *
	 * @param string $id The id to store the element as.
	 * @param mixed $data The data to store.
	 * @param int $lifetime The lifetime of the object in seconds, null to use the default or 0 to never expire.
	 * @return bool true if the data is cached or false if it could not be cached.
	 */
	function store($id, $data, $lifetime = null) {

		// Calculate expire time
		$expire = $lifetime === null ? $this->lifetime : $lifetime;
		return $expire ? $this->cache->setex($this->prefix . $id, $expire, serialize($data)) : $this->cache->set($this->prefix . $id, serialize($data));
	}

	/**
	 * Get the element from the cache.
	 *
	 * @param string $id The id of the element to get.
	 * @return mixed false if the element is not cached or has expired; else the cached data.
	 */
	function get($id) {
		if(($d = $this->cache->get($this->prefix . $id)) === false)
			return false;
		else
			return unserialize($d);
	}

	/**
	 * Remove the given element from the cache.
	 *
	 * @param string $id The id of the element to remove.
	 */
	function remove($id) {
		$this->cache->delete($this->prefix . $id);
	}

	/**
	 * Flush the cache.
	 */
	function flush() {
		$this->cache->eval("return redis.call('DEL', unpack(redis.call('KEYS', 'flCache.*')))");
	}

	/**
	 * Get the UNIX timestamp according to the server.
	 *
	 * @return int The timestamp.
	 */
	function getServerTime() {
		$t = $this->cache->time();
		return $t[0];
	}
}
