<?php
 use TCMS\TException;
 class Cache {
 private static $cacheDriver = null;
 private static $cacheData = null;
 private static function initCacheDriver() {
 if(self::$cacheDriver == null) {
 $cacheConfig = Config::getAppConfig('cache');
 switch($cacheConfig['driver']) {
 case 'file': self::$cacheDriver = new FileCache($cacheConfig);
 break;
 case 'memcache': self::$cacheDriver = new MyMemcache($cacheConfig);
 break;
 }
 self::$cacheData = self::$cacheDriver->get(APP_ID . 'saddo2s2sccsoasp', 1);
 if(!self::$cacheData) {
 self::$cacheData = [];
 }
 }
 }
 private static function setCacheKey($key, $expiresTime, $type) {
 if($expiresTime) {
 if(is_numeric($expiresTime)) {
 $expiresTime = time() + $expiresTime;
 }
 else if($expiresTime instanceof DateTime) {
 $expiresTime = strtotime($expiresTime->format('Y-M-d H:i:s'));
 }
 else {
 throw new TException("Cache: expiresTime phải là số hoặc DateTime", 500);
 }
 }
 self::$cacheData[$key] = ['i' => $expiresTime, 't' => $type];
 }
 public static function set($key, $value, $expiresTime = 0) {
 self::initCacheDriver();
 $type = self::$cacheDriver->set($key, $value, $expiresTime);
 if($type) {
 self::setCacheKey($key, $expiresTime, $type);
 }
 }
 public static function forever($key, $value) {
 self::initCacheDriver();
 $type = self::$cacheDriver->set($key, $value);
 if($type) {
 self::setCacheKey($key, 0, $type);
 }
 }
 public static function remember($key, $expiresTime, Callable $getData) {
 self::initCacheDriver();
 $type = self::getDataType($key);
 if($type) {
 return self::$cacheDriver->get($key, $type);
 }
 $value = call_user_func($getData);
 if($value) {
 self::set($key, $value, $expiresTime);
 }
 return $value;
 }
 public static function rememberForever($key, Callable $getData) {
 return self::remember($key, 0, $getData);
 }
 public static function get($key, Callable $returnData = null) {
 self::initCacheDriver();
 $type = self::getDataType($key);
 if(!$type) {
 if($returnData) {
 $data = call_user_func($returnData);
 return $data;
 }
 return false;
 }
 return self::$cacheDriver->get($key, $type);
 }
 public static function clearAll() {
 self::initCacheDriver();
 self::$cacheDriver->clearAll();
 }
 public static function remove($key) {
 self::initCacheDriver();
 $type = self::getDataType($key);
 if($type) {
 self::$cacheDriver->remove($key, $type);
 if(isset(self::$cacheData[$key])) {
 unset(self::$cacheData[$key]);
 }
 }
 }
 public static function has(string $key) {
 return self::getDataType($key) > 0;
 }
 private static function getDataType(string $key) {
 self::initCacheDriver();
 if(isset(self::$cacheData[$key])) {
 $time = self::$cacheData[$key]['i'];
 if($time && $time < time()) {
 return false;
 }
 return self::$cacheData[$key]['t'];
 }
 return false;
 }
 public static function __save_1Cache__Data() {
 if(self::$cacheData !== null) {
 Cache::set(APP_ID . 'saddo2s2sccsoasp', self::$cacheData, 0);
 }
 }
 }
 class FileCache {
 private $cachePath = '';
 public function __construct($cacheConfig = array()) {
 $this->cachePath = ROOT_PATH . 'data' . DIRECTORY_SEPARATOR . 'cache';
 if(!file_exists($this->cachePath)) {
 mkdir($this->cachePath);
 }
 }
 public function set($key, $value, $expiresTime = 0) {
 $path = $this->cachePath . DIRECTORY_SEPARATOR . APP_ID;
 if(!file_exists($path) && !mkdir($path)) {
 throw new TException('Không thể tạo thư mục ' . $path, 500);
 }
 $path .= DIRECTORY_SEPARATOR . $key;
 if(is_array($value) || is_object($value)) {
 $path .= ".json";
 $type = 1;
 $value = serialize($value);
 }
 else {
 $type = 2;
 $path .= ".data";
 }
 $fp = fopen($path, 'w');
 if(!$fp) {
 throw new TException('Không thể ghi file ' . $path, 500);
 }
 fwrite($fp, $value);
 fclose($fp);
 return $type;
 }
 public function get($key, $type) {
 $path = $this->cachePath . DIRECTORY_SEPARATOR . APP_ID;
 if(!file_exists($path)) {
 return false;
 }
 $path .= DIRECTORY_SEPARATOR . $key;
 if($type == 1) {
 $path .= '.json';
 $isString = false;
 }
 else {
 $path .= '.data';
 $isString = true;
 }
 if(!file_exists($path)) {
 return false;
 }
 $content = file_get_contents($path);
 if(!$isString) {
 return unserialize($content);
 }
 return $content;
 }
 public function clearAll() {
 }
 public function remove($key, $type) {
 $path = $this->cachePath . DIRECTORY_SEPARATOR . APP_ID;
 if(!file_exists($path)) {
 return false;
 }
 $path .= DIRECTORY_SEPARATOR . GlobalVars::$requestInfo['module'];
 if(!file_exists($path)) {
 return false;
 }
 $path .= DIRECTORY_SEPARATOR . str_replace("controller", "", strtolower(GlobalVars::$requestInfo['controller'])) . '_' . $key . ($type == 1 ? '.json' : '.data');
 if(file_exists($path)) {
 unlink($path);
 }
 return true;
 }
 }
 class MyMemcache {
 private $memcache = false;
 public function __construct($cacheConfig = array()) {
 $this->memcache = new Memcache;
 $this->memcache->connect($cacheConfig['host'], $cacheConfig['port'], 10);
 }
 public function set($key, $value, $expiresTime = 0) {
 if(is_array($value) || is_object($value)) {
 $type = 1;
 $value = serialize($value);
 }
 else {
 $type = 2;
 }
 $this->memcache->set($key, $value, 0, $expiresTime);
 return $type;
 }
 public function get($key, $type) {
 $val = $this->memcache->get($key);
 if(!$val) {
 return false;
 }
 if($type == 1) {
 return unserialize($val);
 }
 return $val;
 }
 public function clearAll() {
 $this->memcache->flush();
 }
 public function remove($key, $type) {
 $this->memcache->delete($key);
 return true;
 }
 }
 ?>