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

function check_value($value) {
	if((@count($value)>0 and !@empty($value) and @isset($value)) || $value=='0') {
		return true;
	}
}

function redirect($type = 1, $location = null, $delay = 0) {
	if(!check_value($location)) {
		$to = __BASE_URL__;
	} else {
		$to = __BASE_URL__ . $location;
		
		if($location == 'login') {
			$_SESSION['login_last_location'] = $_REQUEST['page'].'/';
			if(check_value($_REQUEST['subpage'])) {
				$_SESSION['login_last_location'] .= $_REQUEST['subpage'].'/';
			}
		}
	}

	switch($type) {
		default:
			header('Location: '.$to.'');
			die();
		break;
		case 1:
			header('Location: '.$to.'');
			die();
		break;
		case 2:
			echo '<meta http-equiv="REFRESH" content="'.$delay.';url='.$to.'">';
		break;
		case 3:
			header('Location: '.$location.'');
			die();
		break;
	}
}

function isLoggedIn() {
	if(!$_SESSION['valid']) return;
	if(!check_value($_SESSION['userid'])) return;
	if(!check_value($_SESSION['username'])) return;
	if(!check_value($_SESSION['timeout'])) return;
	
	$loginConfigs = loadConfigurations('login');
	if(is_array($loginConfigs)) {
		if($loginConfigs['enable_session_timeout']) {
			if(time()-$_SESSION['timeout'] > $loginConfigs['session_timeout']) {
				logOutUser();
			}
		}
	}
	
	$_SESSION['timeout'] = time();
	return true;
}

function logOutUser() {
	$login = new login();
	$login->logout();
}

function message($type='info', $message="", $title="") {
	switch($type) {
		case 'error':
			$class = ' alert-danger';
		break;
		case 'success':
			$class = ' alert-success';
		break;
		case 'warning':
			$class = ' alert-warning';
		break;
		default:
			$class = ' alert-info';
		break;
	}
	
	if(check_value($title)) {
		echo '<div class="alert'.$class.'" role="alert"><strong>'.$title.'</strong><br />'.$message.'</div>';
	} else {
		echo '<div class="alert'.$class.'" role="alert">'.$message.'</div>';
	}
}

function lang($phrase, $return=true) {
	global $lang;
	$result = $lang[$phrase];
	if(!$result) $result = 'ERROR';
	
	if(config('language_debug',true)) {
		if($return) {
			return '<span title="'.$phrase.'" alt="'.$phrase.'">'.$result.'</span>';
		} else {
			echo '<span title="'.$phrase.'" alt="'.$phrase.'">'.$result.'</span>';
		}
	} else {
		if($return) {
			return $result;
		} else {
			echo $result;
		}
	}
}

function langf($phrase, $args=array(), $print=false) {
	global $lang;
	$result = @vsprintf($lang[$phrase], $args);
	if(!$result) $result = 'ERROR';
	
	if(config('language_debug',true)) {
		if($print) {
			echo '<span title="'.$phrase.'" alt="'.$phrase.'">'.$result.'</span>';
		} else {
			return '<span title="'.$phrase.'" alt="'.$phrase.'">'.$result.'</span>';
		}
	} else {
		if($print) {
			echo $result;
		} else {
			return $result;
		}
	}
}

# to be removed
function Encode($txt) {
	return $txt;
}

# to be removed
function Decode($txt) {
	return $txt;
}

function debug($value) {
	echo '<pre>';
		print_r($value);
	echo '</pre>';
}

function canAccessAdminCP($username) {
	if(!check_value($username)) return;
	if(array_key_exists($username, config('admins',true))) return true;
	return false;
}

# to be removed
function Encode_id($id) {
	return $id;
}

# to be removed
function Decode_id($id) {
	return $id;
}

function BuildCacheData($data_array) {
	$result = null;
	if(is_array($data_array)) {
		foreach($data_array as $row) {
			$count = count($row);
			$i = 1;
			foreach($row as $data) {
				$result .= $data;
				if($i < $count) {
					$result .= '¦';
				}
				$i++;
			}
			$result .= "\n";
		}
		return $result;
	} else {
		return null;
	}
}

function UpdateCache($file_name, $data) {
	$file = __PATH_CACHE__.$file_name;
	if(!file_exists($file)) return;
	if(!is_writable($file)) return;
	
	$fp = fopen($file, 'w');
	fwrite($fp, time()."\n");
	fwrite($fp, $data);
	fclose($fp);
	return true;
}

function LoadCacheData($file_name) {
	$file = __PATH_CACHE__.$file_name;
	if(!file_exists($file)) return;
	if(!is_readable($file)) return;
	
	$cache_file = file_get_contents($file);
	$file_lanes = explode("\n",$cache_file);
	$nlines = count($file_lanes);
	for($i=0; $i<$nlines; $i++) {
		if(check_value($file_lanes[$i])) {
			$line_data[$i] = explode("¦",$file_lanes[$i]);
		}
	}
	return $line_data;
}

function sec_to_hms($input_seconds=0) {
	$result = sec_to_dhms($input_seconds);
	if(!is_array($result)) return array(0,0,0);
	return array((($result[0]*24)+$result[1]), $result[2], $result[3]);
}

function sec_to_dhms($input_seconds=0) {
	if($input_seconds < 1) return array(0,0,0,0);
	$days_module = $input_seconds % 86400;
	$days = ($input_seconds-$days_module)/86400;
	$hours_module = $days_module % 3600;
	$hours = ($days_module-$hours_module)/3600;
	$minutes_module = $hours_module % 60;
	$minutes = ($hours_module-$minutes_module)/60;
	$seconds = $minutes_module;
	return array($days,$hours,$minutes,$seconds);
}

/*
 * Calculates the exact time left before the next Castle Siege battle.
 * Configs:
 * 		- cs_battle_day: Values: 1(Monday) to 7(Sunday)
 * 		- cs_battle_time: Value: h:m:s (in 24 hour format!)
 * 		- cs_battle_duration: Value: numeric (time in minutes!)
 * 
*/
function cs_CalculateTimeLeft() {
	loadModuleConfigs('castlesiege');
	$weekDays = array("", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday");
	$battleDay = $weekDays[mconfig('cs_battle_day')];
	$today = date("l");
	$battleTime = mconfig('cs_battle_time');
	$battleDate = strtotime("next $battleDay $battleTime");
	$timeOffset = $battleDate - time();
	if($today == $battleDay) {
		$currentTime = strtotime(date("H:i:s"));
		$battleTimeToday = strtotime($battleTime);
		$timeOffsetToday = $battleTimeToday - time();
		if($battleTimeToday > $currentTime) {
			// CS BATTLE IS TODAY
			return $timeOffsetToday;
		} else {
			$timeOffsetToday = $timeOffsetToday*(-1);
			if((mconfig('cs_battle_duration')*60) > $timeOffsetToday) {
				// CS BATTLE IN PROGRESS
				return;
			} else {
				// CS BATTLE IS ON NEXT DATE
				return $timeOffset;
			}
		}
	} else {
		// CS BATTLE IS ON NEXT DATE
		return $timeOffset;
	}
}

function listCronFiles($selected="") {
	$dir = opendir(__PATH_CRON__);
	while(($file = readdir($dir)) !== false) {
		if(filetype(__PATH_CRON__ . $file) == "file" && $file != ".htaccess" && $file != "cron.php") {
			
			if(check_value($selected) && $selected == $file) {
				$return[] = "<option value=\"$file\" selected=\"selected\">$file</option>";
			} else {
				$return[] = "<option value=\"$file\">$file</option>";
			}
		}
	}
	closedir($dir);
	return join('', $return);
}

function cronFileAlreadyExists($cron_file) {
	$database = Connection::Database('Me_MuOnline');
	$check = $database->query_fetch_single("SELECT * FROM ".WEBENGINE_CRON." WHERE cron_file_run = ?", array($cron_file));
	if(!is_array($check)) {
		return true;
	}
}

function addCron() {
	$database = Connection::Database('Me_MuOnline');
	if(check_value($_POST['cron_name']) && check_value($_POST['cron_file']) && check_value($_POST['cron_time'])) {
		
		$filePath = __PATH_CRON__.$_POST['cron_file'];

		// Check Cron File Exists
		if(!file_exists($filePath)) {
			message('error','The selected file doesn\'t exist.');
			return;
		}
		// Check Cron File Databse
		if(!cronFileAlreadyExists($_POST['cron_file'])) {
			message('error','A cron job with the same file already exists.');
			return;
		}
		// Check Cron Time
		if(!Validator::UnsignedNumber($_POST['cron_time'])) {
			$_POST['cron_time'] = 300;
		}
		
		$sql_data = array(
			$_POST['cron_name'],
			$_POST['cron_description'],
			$_POST['cron_file'],
			$_POST['cron_time'],
			1,
			0,
			md5_file($filePath)
		);
		
		$query = $database->query("INSERT INTO ".WEBENGINE_CRON." (cron_name, cron_description, cron_file_run, cron_run_time, cron_status, cron_protected, cron_file_md5) VALUES (?, ?, ?, ?, ?, ?, ?)", $sql_data);
		if($query) {
			message('success','Cron job successfully added!');
		} else {
			message('error','Could not add cron job.');
		}
		
	} else {
		message('error','Please complete all the required fields.');
	}
}

function updateCronLastRun($file) {
	$database = Connection::Database('Me_MuOnline');
	$update = $database->query("UPDATE ".WEBENGINE_CRON." SET cron_last_run = ? WHERE cron_file_run = ?", array(time(), $file));
	if(!$update) return;
	return true;
}

function getCronJobDATA($id) {
	$database = Connection::Database('Me_MuOnline');
	$result = $database->query_fetch_single("SELECT * FROM ".WEBENGINE_CRON." WHERE cron_id = ?", array($id));
	if(is_array($result)) {
		return $result;
	}
}

function deleteCronJob($id) {
	$database = Connection::Database('Me_MuOnline');
	$cronDATA = getCronJobDATA($id);
	if(is_array($cronDATA)) {
		if($cronDATA['cron_protected']) {
			message('error','This cron job is protected therefore cannot be deleted.');
			return;
		}
		$delete = $database->query("DELETE FROM ".WEBENGINE_CRON." WHERE cron_id = ?", array($id));
		if($delete) {
			message('success','Cron job "<strong>'.$cronDATA['cron_name'].'</strong>" successfully deteled!');
		} else {
			message('error','Could not delete cron job.');
		}
	} else {
		message('error','Could not find cron job.');
	}
}

function togglestatusCronJob($id) {
	$database = Connection::Database('Me_MuOnline');
	$cronDATA = getCronJobDATA($id);
	if(is_array($cronDATA)) {
		if($cronDATA['cron_status'] == 1) {
			$status = 0;
		} else {
			$status = 1;
		}
		$toggle = $database->query("UPDATE ".WEBENGINE_CRON." SET cron_status = ? WHERE cron_id = ?", array($status, $id));
		if($toggle) {
			message('success','Cron job "<strong>'.$cronDATA['cron_name'].'</strong>" status successfully changed!');
		} else {
			message('error','Could not update cron job.');
		}
	} else {
		message('error','Could not find cron job.');
	}
}

function editCronJob($id,$name,$desc,$file,$time,$cron_times,$current_file) {
	$database = Connection::Database('Me_MuOnline');
	if(check_value($name) && check_value($file) && check_value($time)) {
		$filePath = __PATH_CRON__.$file;

		// Check Cron File Exists
		if(!file_exists($filePath)) {
			message('error','The selected file doesn\'t exist.');
			return;
		}
		// Check Cron File Databse
		if($file != $current_file) {
			if(!cronFileAlreadyExists($file)) {
				message('error','A cron job with the same file already exists.');
				return;
			}
		}
		// Check Cron Time
		if(!array_key_exists($time, $cron_times)) {
			message('error','The selected cron time doesn\'t exist.');
			return;
		}

		$query = $database->query("UPDATE ".WEBENGINE_CRON." SET cron_name = ?, cron_description = ?, cron_file_run = ?, cron_run_time = ? WHERE cron_id = ?", array($name, $desc, $file, $cron_times[$time], $id));
		if($query) {
			message('success','Cron job successfully updated!');
		} else {
			message('error','Could not edit cron job.');
		}
	} else {
		message('error','You must fill all the required fields.');
	}
}

function returnGuildLogo($binaryData="", $size=40) {
	$imgSize = Validator::UnsignedNumber($size) ? $size : 40;
	return '<img src="'.__PATH_API__.'guildmark.php?data='.$binaryData.'&size='.urlencode($size).'" width="'.$imgSize.'" height="'.$imgSize.'">';
}

function getGensRank($contributionPoints) {
	global $custom;
	foreach($custom['gens_ranks'] as $points => $title) {
		if($contributionPoints >= $points) return $title;
	}
	return $title;
}

function getGensLeadershipRank($rankPosition) {
	global $custom;
	foreach($custom['gens_ranks_leadership'] as $title => $range) {
		if($rankPosition >= $range[0] && $rankPosition <= $range[1]) return $title;
	}
	return;
}

function webengineConfigs() {
	if(!file_exists(__PATH_CONFIGS__ . 'webengine.json')) throw new Exception('WebEngine\'s configuration file doesn\'t exist, please reupload the website files.');
	
	$webengineConfigs = file_get_contents(__PATH_CONFIGS__ . 'webengine.json');
	if(!check_value($webengineConfigs)) throw new Exception('WebEngine\'s configuration file is empty, please run the installation script.');
	
	return json_decode($webengineConfigs, true);
}

function config($config_name, $return = false) {
	$config = webengineConfigs();
	if($return) {
		return $config[$config_name];
	} else {
		echo $config[$config_name];
	}
}

function convertXML($object) {
	return json_decode(json_encode($object), true);
}

function loadModuleConfigs($module) {
	global $mconfig;
	if(moduleConfigExists($module)) {
		$xml = simplexml_load_file(__PATH_MODULE_CONFIGS__.$module.'.xml');
		$mconfig = array();
		if($xml) {
			$moduleCONFIGS = convertXML($xml->children());
			$mconfig = $moduleCONFIGS;
		}
	}
}

function moduleConfigExists($module) {
	if(file_exists(__PATH_MODULE_CONFIGS__.$module.'.xml')) {
		return true;
	}
}

function globalConfigExists($config_file) {
	if(file_exists(__PATH_CONFIGS__.$config_file.'.xml')) {
		return true;
	}
}

function mconfig($configuration) {
	global $mconfig;
	if(@array_key_exists($configuration, $mconfig)) {
		return $mconfig[$configuration];
	} else {
		return null;
	}
}

function gconfig($config_file,$return=true) {
	global $gconfig;
	if(globalConfigExists($config_file)) {
		$xml = simplexml_load_file(__PATH_CONFIGS__.$config_file.'.xml');
		$gconfig = array();
		if($xml) {
			$globalCONFIGS = convertXML($xml->children());
			if($return) {
				return $globalCONFIGS;
			} else {
				$gconfig = $globalCONFIGS;
			}
		}
	}
}

function loadConfigurations($file) {
	if(!check_value($file)) return;
	if(!moduleConfigExists($file)) return;
	$xml = simplexml_load_file(__PATH_MODULE_CONFIGS__ . $file . '.xml');
	if($xml) return convertXML($xml->children());
	return;
}

function loadConfig($name="webengine") {
	if(!check_value($name)) return;
	if(!file_exists(__PATH_CONFIGS__ . $name . '.json')) return;
	$cfg = file_get_contents(__PATH_CONFIGS__ . $name . '.json');
	if(!check_value($cfg)) return;
	return json_decode($cfg, true);
}

function getPlayerClassAvatar($code=0, $htmlImageTag=true, $tooltip=true, $cssClass=null) {
	global $custom;
	$imageFileName = array_key_exists($code, $custom['character_class']) ? $custom['character_class'][$code][2] : 'avatar.jpg';
	$imageFullPath = __PATH_TEMPLATE_IMG__ . config('character_avatars_dir', true) . '/' . $imageFileName;
	$className = $custom['character_class'][$code][0];
	if(!$htmlImageTag) return $imageFullPath;
	$result = '<img';
	if(check_value($cssClass)) $result .= ' class="'.$cssClass.'"';
	if($tooltip) $result .= ' data-toggle="tooltip" data-placement="top" title="'.$className.'" alt="'.$className.'"';
	$result .= ' src="'.$imageFullPath.'" />';
	return $result;
}

function playerProfile($playerName) {
	if(!config('player_profiles',true)) return $playerName;
	return '<a href="'.__BASE_URL__.'profile/player/req/'.urlencode($playerName).'/" target="_blank">'.$playerName.'</a>';
}

function guildProfile($guildName) {
	if(!config('guild_profiles',true)) return $guildName;
	return '<a href="'.__BASE_URL__.'profile/guild/req/'.urlencode($guildName).'/" target="_blank">'.$guildName.'</a>';
}

function encodeCache($data, $pretty=false) {
	if($pretty) return json_encode($data, JSON_PRETTY_PRINT);
	return json_encode($data);
}

function decodeCache($data) {
	return json_decode($data, true);
}

function updateCacheFile($fileName, $data) {
	$file = __PATH_CACHE__ . $fileName;
	if(!file_exists($file)) return;
	if(!is_writable($file)) return;
	
	$fp = fopen($file, 'w');
	fwrite($fp, $data);
	fclose($fp);
	return true;
}

function loadCache($fileName) {
	$file = __PATH_CACHE__ . $fileName;
	if(!file_exists($file)) return;
	if(!is_readable($file)) return;
	
	$cacheDataRaw = file_get_contents($file);
	if(!check_value($cacheDataRaw)) return;
	
	$cacheData = decodeCache($cacheDataRaw);
	if(!is_array($cacheData)) return;
	
	return $cacheData;
}

function checkBlockedIp() {
	if(in_array(access, array('cron'))) return;
	if(!check_value($_SERVER['REMOTE_ADDR'])) return true;
	if(!Validator::Ip($_SERVER['REMOTE_ADDR'])) return true;
	$blockedIpCache = loadCache('blocked_ip.cache');
	if(!is_array($blockedIpCache)) return;
	if(in_array($_SERVER['REMOTE_ADDR'], $blockedIpCache)) return true;
}

function getCronList() {
	$db = Connection::Database('Me_MuOnline');
	$result = $db->query_fetch("SELECT * FROM ".WEBENGINE_CRON." ORDER BY cron_id ASC");
	if(!is_array($result)) return;
	return $result;
}

function addRankingMenuLink($phrase, $module, $filesExclusivity=null) {
	global $rankingMenuLinks;
	if(!check_value($phrase)) return;
	if(!check_value($module)) return;
	
	if(is_array($filesExclusivity)) {
		if(!in_array(strtolower(config('server_files',true)), array_map('strtolower', $filesExclusivity))) return;
	}
	
	if(lang($phrase) != 'ERROR') {
		$phrase = lang($phrase);
	}
	
	$rankingMenuLinks[] = array($phrase, $module);
}

function getRankingMenuLinks() {
	global $rankingMenuLinks;
	if(!is_array($rankingMenuLinks)) return;
	return $rankingMenuLinks;
}

function loadJsonFile($filePath) {
	if(!file_exists($filePath)) return;
	if(!is_readable($filePath)) return;
	$jsonData = file_get_contents($filePath);
	if($jsonData == false) return;
	$result = json_decode($jsonData, true);
	if(!is_array($result)) return;	
	return $result;
}

function getCountryCodeFromIp($ip) {
	$api = 'http://ip-api.com/json/'.$ip.'?fields=status,countryCode';
    $handle = curl_init();
    curl_setopt($handle, CURLOPT_URL, $api);
    curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
    $json = curl_exec($handle);
    curl_close($handle);
    if(!check_value($json)) return;
    $result = json_decode($json, true);
	if(!is_array($result)) return;
	if($result['status'] == 'fail') return;
	if(!check_value($result['countryCode'])) return;
	return $result['countryCode'];
}

function getCountryFlag($countryCode='default') {
	if(!check_value($countryCode)) $countryCode = 'default';
	return __PATH_COUNTRY_FLAGS__ . strtolower($countryCode) . '.gif';
}

function returnMapName($id=0) {
	global $custom;
	if(!is_array($custom['map_list'])) return 'Lorencia Bar';
	if(!array_key_exists($id, $custom['map_list'])) {
		if(config('error_reporting',true)) return 'Map Number ('.$id.')';
		return 'Lorencia Bar';
	}
	return $custom['map_list'][$id];
}

function returnPkLevel($id) {
	global $custom;
	if(!is_array($custom['pk_level'])) return;
	if(!array_key_exists($id, $custom['pk_level'])) return;
	return $custom['pk_level'][$id];
}

function getDirectoryListFromPath($path) {
	if(!file_exists($path)) return;
	$files = scandir($path);
	foreach($files as $row) {
		if(in_array($row, array('.','..'))) continue;
		if(!is_dir($path.$row)) continue;
		$result[] = $row;
	}
	if(!is_array($result)) return;
	return $result;
}

function getInstalledLanguagesList() {
	$languageDir = getDirectoryListFromPath(__PATH_LANGUAGES__);
	if(!is_array($languageDir)) return;
	foreach($languageDir as $language) {
		if(!file_exists(__PATH_LANGUAGES__.$language.'/language.php')) continue;
		$result[] = $language;
	}
	if(!is_array($result)) return;
	return $result;
}