<?php
/**
 * WebEngine CMS
 * https://webenginecms.org/
 * 
 * @version 1.2.6
 * @author Lautaro Angelico <http://lautaroangelico.com/>
 * @copyright (c) 2013-2025 Lautaro Angelico, All Rights Reserved
 * 
 * Licensed under the MIT license
 * http://opensource.org/licenses/MIT
 */

class CacheManager {
	
	protected $_protectedCacheFiles = array(
		'plugins.cache',
		'blocked_ip.cache',
		'downloads.cache',
		'news.cache',
		'.htaccess',
		'.gitignore',
		'cron_state.json',
		'cron_state.json.lock',
	);
	protected $_jsonArrayFiles = array(
		'castle_siege.cache',
		'character_country.cache',
		'online_characters.cache',
	);
	protected $_file;
	protected $_cacheCronMap = array(
		'rankings_level.cache' => 'levels_ranking.php',
		'rankings_resets.cache' => 'resets_ranking.php',
		'rankings_pk.cache' => 'killers_ranking.php',
		'rankings_master.cache' => 'masterlevel_ranking.php',
		'rankings_guilds.cache' => 'guilds_ranking.php',
		'rankings_gr.cache' => 'grandresets_ranking.php',
		'rankings_online.cache' => 'online_ranking.php',
		'rankings_gens.cache' => 'gens_ranking.php',
		'rankings_votes.cache' => 'votes_ranking.php',
		'rankings_bloodcastle.cache' => 'event_rankings.php',
		'rankings_devilsquare.cache' => 'event_rankings.php',
		'rankings_chaoscastle.cache' => 'event_rankings.php',
		'server_info.cache' => 'server_info.php',
		'castle_siege.cache' => 'castle_siege.php',
		'character_country.cache' => 'character_country.php',
		'online_characters.cache' => 'online_characters.php',
	);
	protected $_realmCacheDefaults = array(
		'rankings_level.cache' => '',
		'rankings_resets.cache' => '',
		'rankings_pk.cache' => '',
		'rankings_master.cache' => '',
		'rankings_guilds.cache' => '',
		'rankings_gr.cache' => '',
		'rankings_online.cache' => '',
		'rankings_gens.cache' => '',
		'rankings_votes.cache' => '',
		'rankings_bloodcastle.cache' => '[]',
		'rankings_devilsquare.cache' => '[]',
		'rankings_chaoscastle.cache' => '[]',
		'server_info.cache' => '',
		'castle_siege.cache' => '[]',
		'character_country.cache' => '[]',
		'online_characters.cache' => '[]',
	);

	
	public function setFile($file) {
		$this->_file = $file;
	}
	
	public function getCacheFileListAndData($type='') {
		switch($type) {
			case 'guild':
				$cacheFiles = $this->_getGuildProfileCacheFileList();
				$basePath = $this->_guildProfilePath();
				break;
			case 'player':
				$cacheFiles = $this->_getPlayerProfileCacheFileList();
				$basePath = $this->_playerProfilePath();
				break;
			default:
				$cacheFiles = $this->_getCacheFileList();
				$basePath = $this->_realmCachePath();
		}
		if(!is_array($cacheFiles)) return;
		$result = array();
		foreach($cacheFiles as $row) {
			$filePath = $basePath . $row;
			$fileSize = filesize($filePath);
			$lastModification = date('Y/m/d H:i A', filemtime($filePath));
			$writable = is_writable($filePath);
			$result[] = array(
				'file' => $row,
				'size' => $fileSize,
				'edit' => $lastModification,
				'write' => $writable
			);
		}
		return $result;
	}
	
	public function clearCacheData() {
		if(!check_value($this->_file)) return;
		if(!in_array($this->_file, $this->_getCacheFileList())) throw new Exception('The requested cache file is not valid.');
		$filePath = class_exists('NexoraRealm') ? NexoraRealm::cachePath($this->_file) : __PATH_CACHE__ . $this->_file;
		$fileData = $this->_isJsonArrayFile($this->_file) || strpos($this->_file, 'rankings_bloodcastle') === 0 || strpos($this->_file, 'rankings_devilsquare') === 0 || strpos($this->_file, 'rankings_chaoscastle') === 0 ? '[]' : '';
		if(!nexoraAtomicWrite($filePath, $fileData)) throw new Exception('No se pudo limpiar el archivo de caché. Revisa permisos de escritura.');
		if(isset($this->_cacheCronMap[$this->_file]) && function_exists('nexoraCronResetState')) {
			nexoraCronResetState($this->_cacheCronMap[$this->_file], class_exists('NexoraRealm') ? NexoraRealm::active() : null);
		}
	}

	public function recoverRealmCacheScaffold($realm=null) {
		$basePath = class_exists('NexoraRealm') ? NexoraRealm::realmCacheDirectory($realm) : __PATH_CACHE__;
		if(!nexoraEnsureDirectory($basePath)) throw new Exception('El directorio de caché del reino no es escribible.');
		if(class_exists('NexoraRealm')) {
			nexoraEnsureDirectory(NexoraRealm::profileCacheDirectory('guilds', $realm));
			nexoraEnsureDirectory(NexoraRealm::profileCacheDirectory('players', $realm));
		}
		$created = array();
		$errors = array();
		foreach($this->_realmCacheDefaults as $file=>$defaultData) {
			$path = $basePath.$file;
			if(is_file($path)) continue;
			if(nexoraAtomicWrite($path, $defaultData)) $created[] = $file;
			else $errors[] = $file;
		}
		return array('created'=>$created, 'errors'=>$errors, 'path'=>$basePath);
	}

	public function getRealmCacheHealth($realm=null) {
		$basePath = class_exists('NexoraRealm') ? NexoraRealm::realmCacheDirectory($realm) : __PATH_CACHE__;
		$result = array();
		foreach($this->_realmCacheDefaults as $file=>$defaultData) {
			$path = $basePath.$file;
			$result[$file] = array(
				'exists' => is_file($path),
				'writable' => is_file($path) ? is_writable($path) : is_writable($basePath),
				'size' => is_file($path) ? (int)@filesize($path) : 0,
				'mtime' => is_file($path) ? (int)@filemtime($path) : 0,
			);
		}
		return $result;
	}

	public function expectedRealmCacheFiles() {
		return array_keys($this->_realmCacheDefaults);
	}
	
	public function deleteGuildCache() {
		$fileList = $this->_getGuildProfileCacheFileList();
		if(!is_array($fileList)) return;
		$basePath = $this->_guildProfilePath();
		foreach($fileList as $row) {
			unlink($basePath . $row);
		}
	}
	
	public function deletePlayerCache() {
		$fileList = $this->_getPlayerProfileCacheFileList();
		if(!is_array($fileList)) return;
		$basePath = $this->_playerProfilePath();
		foreach($fileList as $row) {
			unlink($basePath . $row);
		}
	}
	
	protected function _getCacheFileList() {
		$basePath = $this->_realmCachePath();
		if(!is_dir($basePath)) $this->recoverRealmCacheScaffold();
		if(!is_dir($basePath)) return array();
		$dir = opendir($basePath);
		if(!$dir) return array();
		$result = array();
		while(($file = readdir($dir)) !== false) {
			$path = $basePath.$file;
			if(is_file($path) && !$this->_isProtected($file)) $result[] = $file;
		}
		closedir($dir);
		sort($result);
		return $result;
	}
	
	protected function _getGuildProfileCacheFileList() {
		$basePath = $this->_guildProfilePath();
		if(!is_dir($basePath)) nexoraEnsureDirectory($basePath);
		$dir = @opendir($basePath);
		if(!$dir) return array();
		$result = array();
		while(($file = readdir($dir)) !== false) {
			if(filetype($basePath.$file) == "file" && !$this->_isProtected($file)) {
				$result[] = $file;
			}
		}
		closedir($dir);
		return $result;
	}
	
	protected function _getPlayerProfileCacheFileList() {
		$basePath = $this->_playerProfilePath();
		if(!is_dir($basePath)) nexoraEnsureDirectory($basePath);
		$dir = @opendir($basePath);
		if(!$dir) return array();
		$result = array();
		while(($file = readdir($dir)) !== false) {
			if(filetype($basePath.$file) == "file" && !$this->_isProtected($file)) {
				$result[] = $file;
			}
		}
		closedir($dir);
		return $result;
	}
	
	protected function _isProtected($file) {
		if(in_array($file, $this->_protectedCacheFiles)) return true;
		return false;
	}
	
	protected function _isJsonArrayFile($file) {
		if(in_array($file, $this->_jsonArrayFiles)) return true;
		return false;
	}

	protected function _realmCachePath() {
		return class_exists('NexoraRealm') ? NexoraRealm::realmCacheDirectory() : __PATH_CACHE__;
	}

	protected function _guildProfilePath() {
		return class_exists('NexoraRealm') ? NexoraRealm::profileCacheDirectory('guilds') : __PATH_GUILD_PROFILES_CACHE__;
	}

	protected function _playerProfilePath() {
		return class_exists('NexoraRealm') ? NexoraRealm::profileCacheDirectory('players') : __PATH_PLAYER_PROFILES_CACHE__;
	}
}
