<?php

namespace Plugin;

use pocketmine\plugin\PluginBase;
use pocketmine\command\CommandExecutor;
use pocketmine\utils\Config;
use pocketmine\utils\TextFormat;
use pocketmine\command\CommandSender;
use pocketmine\Server;
use pocketmine\Player;
use pocketmine\OfflinePlayer;

class ServerAuth extends PluginBase {
	
	const PRODUCER = "EvolSoft";
	
	const VERSION = "2.0.0";
	
	const MAIN_WEBSITE = "http://www.evolsoft.tk";
	
	const PREFIX = "§a» ";
	
	const ERR_USER_NOT_REGISTERED = 0;

	const SUCCESS = 1;
	
	const ERR_WRONG_PASSWORD = 2;
	
	const ERR_USER_NOT_AUTHENTICATED = 3;
	
	const ERR_USER_ALREADY_AUTHENTICATED = 4;
	
	const ERR_USER_ALREADY_REGISTERED = 5;
	
	const ERR_PASSWORD_TOO_SHORT = 6;
	
	const ERR_PASSWORD_TOO_LONG = 7;
	
	const ERR_MAX_IP_REACHED = 8;
	
	const ERR_GENERIC = 9;
	
	const CANCELLED = 10;
	
	const TOO_MANY_ATTEMPTS = 11;
	
	private $auth_users = array();
	
	private $auth_attempts = array();
	
	public $chlang;
	
	public $cached_registered_users = array();
	
	public $task;

    public $mysql;
    
    public $canc_message;
    
    private $database;
    
    private $register_message = true;
    
    private $login_message = true;
    
    private static $object = null;
    
    public static function getAPI(){
    	return self::$object;
    }
    
    public function onLoad(){
    	if(!(self::$object instanceof ServerAuth)){
    		self::$object = $this;
    	}
    }
    
    public function translateColors($symbol, $message){
    
    	$message = str_replace($symbol."0", TextFormat::BLACK, $message);
    	$message = str_replace($symbol."1", TextFormat::DARK_BLUE, $message);
    	$message = str_replace($symbol."2", TextFormat::DARK_GREEN, $message);
    	$message = str_replace($symbol."3", TextFormat::DARK_AQUA, $message);
    	$message = str_replace($symbol."4", TextFormat::DARK_RED, $message);
    	$message = str_replace($symbol."5", TextFormat::DARK_PURPLE, $message);
    	$message = str_replace($symbol."6", TextFormat::GOLD, $message);
    	$message = str_replace($symbol."7", TextFormat::GRAY, $message);
    	$message = str_replace($symbol."8", TextFormat::DARK_GRAY, $message);
    	$message = str_replace($symbol."9", TextFormat::BLUE, $message);
    	$message = str_replace($symbol."a", TextFormat::GREEN, $message);
    	$message = str_replace($symbol."b", TextFormat::AQUA, $message);
    	$message = str_replace($symbol."c", TextFormat::RED, $message);
    	$message = str_replace($symbol."d", TextFormat::LIGHT_PURPLE, $message);
    	$message = str_replace($symbol."e", TextFormat::YELLOW, $message);
    	$message = str_replace($symbol."f", TextFormat::WHITE, $message);
    
    	$message = str_replace($symbol."k", TextFormat::OBFUSCATED, $message);
    	$message = str_replace($symbol."l", TextFormat::BOLD, $message);
    	$message = str_replace($symbol."m", TextFormat::STRIKETHROUGH, $message);
    	$message = str_replace($symbol."n", TextFormat::UNDERLINE, $message);
    	$message = str_replace($symbol."o", TextFormat::ITALIC, $message);
    	$message = str_replace($symbol."r", TextFormat::RESET, $message);
    
    	return $message;
    }
    
    public function replaceArrays($message, $array){
    	foreach($array as $key => $value){
    		$message = str_replace("{" . strtoupper($key) . "}", $value, $message);
    	}
    	return $message;
    }
    
    public function checkDatabase($host, $port, $username, $password){
    	$status = array();
    	$db = @new \mysqli($host, $username, $password, null, $port);
    	if($db->connect_error){
    		$status[0] = false;
    		$status[1] = $db->connect_error;
    		return $status;
    	}else{
    		$db->close();
    		$status[0] = true;
    		$status[1] = "Success!";
    		return $status;
    	}
    }
	
    public function initializeDatabase($host, $port, $username, $password, $database, $table_prefix){
    	$db = @new \mysqli($host, $username, $password, null, $port);
    	if($db->connect_error){
    		return false;
    	}else{
    		$query = "CREATE DATABASE " . $database;
    		if($db->query($query) == true) {
    			$db->select_db($database);
    			if(\mysqli_num_rows($db->query("SHOW TABLES LIKE '" . $table_prefix . "serverauth'")) == 0){
    				$query = "CREATE TABLE " . $table_prefix . "serverauth (version VARCHAR(50), api_version VARCHAR(50), password_hash VARCHAR(50))";
    				$db->query($query);
    			}
    			if(\mysqli_num_rows($db->query("SHOW TABLES LIKE '" . $table_prefix . "serverauthdata'")) == 0){
    				$query = "CREATE TABLE " . $table_prefix . "serverauthdata (user VARCHAR(50), password VARCHAR(200), ip VARCHAR(50), firstlogin VARCHAR(50), lastlogin VARCHAR(50))";
    				$db->query($query);
    			}
    		    if(\mysqli_num_rows($db->query("SELECT version, api_version FROM " . $table_prefix . "serverauth")) == 0){
    				$query = "INSERT INTO " . $table_prefix . "serverauth (version, api_version, password_hash) VALUES ('" . $this->getVersion() . "', '" . $this->getAPIVersion() . "', '" . $this->getPasswordHash() . "')";
    				$db->query($query);
    			}else{
    				$query = "UPDATE " . $table_prefix . "serverauth SET version='" . $this->getVersion() . "', api_version='" . $this->getAPIVersion() . "', password_hash='" . $this->getPasswordHash() . "' LIMIT 1";
    				$db->query($query);
    			}
    		}else{
    			$db->select_db($database);
    			if(\mysqli_num_rows($db->query("SHOW TABLES LIKE '" . $table_prefix . "serverauth'")) == 0){
    				$query = "CREATE TABLE " . $table_prefix . "serverauth (version VARCHAR(50), api_version VARCHAR(50), password_hash VARCHAR(50))";
    				$db->query($query);
    			}
    			if(\mysqli_num_rows($db->query("SHOW TABLES LIKE '" . $table_prefix . "serverauthdata'")) == 0){
    				$query = "CREATE TABLE " . $table_prefix . "serverauthdata (user VARCHAR(50), password VARCHAR(200), ip VARCHAR(50), firstlogin VARCHAR(50), lastlogin VARCHAR(50))";
    				$db->query($query);
    			}
    		    if(\mysqli_num_rows($db->query("SELECT version, api_version FROM " . $table_prefix . "serverauth")) == 0){
                    $query = "INSERT INTO " . $table_prefix . "serverauth (version, api_version, password_hash) VALUES ('" . $this->getVersion() . "', '" . $this->getAPIVersion() . "', '" . $this->getPasswordHash() . "')";
    				$db->query($query);
    			}else{
    				$query = "UPDATE " . $table_prefix . "serverauth SET version='" . $this->getVersion() . "', api_version='" . $this->getAPIVersion() . "', password_hash='" . $this->getPasswordHash() . "' LIMIT 1";
    				$db->query($query);
    			}
    		}
    		$this->database = $db;
    	}
		return true;
    }
    
    private function grep($path, $str){
    	$count = 0;
    	foreach(glob($path . "*.yml") as $filename){
    		foreach(file($filename) as $fli=>$fl){
    			if(strpos($fl, $str) !== false){
    				$count += 1;
    			}
    		}
    	}
    	return $count;
    }

    public function onEnable(){
	    @mkdir($this->getDataFolder());
	    @mkdir($this->getDataFolder() . "users/");
	    @mkdir($this->getDataFolder() . "languages/");
	    foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getFile() . "resources/languages")) as $resource){
	    	$resource = str_replace("\\", "/", $resource);
	    	$resarr = explode("/", $resource);
	    	if(substr($resarr[count($resarr) - 1], strrpos($resarr[count($resarr) - 1], '.') + 1) == "yml"){
	    		$this->saveResource("languages/" . $resarr[count($resarr) - 1]);
	    	}
	    }
        $this->saveDefaultConfig();
        $this->cfg = $this->getConfig()->getAll();
        $this->getCommand("serverauth")->setExecutor(new Commands\Commands($this));
        $this->getCommand("register")->setExecutor(new Commands\Register($this));
        $this->getCommand("login")->setExecutor(new Commands\Login($this));
        $this->getCommand("logout")->setExecutor(new Commands\Logout($this));
        $this->getCommand("changepassword")->setExecutor(new Commands\ChangePassword($this));
        $this->getCommand("unregister")->setExecutor(new Commands\Unregister($this));
        $this->getServer()->getPluginManager()->registerEvents(new EventListener($this), $this);
        $this->getServer()->getScheduler()->scheduleRepeatingTask(new Tasks\MessageTask($this), 20);
        $this->task = $this->getServer()->getScheduler()->scheduleRepeatingTask(new Tasks\MySQLTask($this), 20);
        $this->mysql = false;
        $this->chlang = ServerAuth::getAPI()->getConfigLanguage()->getAll();
        if($this->cfg["use-mysql"] == true){
        	$check = $this->checkDatabase($this->cfg["mysql"]["host"], $this->cfg["mysql"]["port"], $this->cfg["mysql"]["username"], $this->cfg["mysql"]["password"]);
        	if($check[0]){
        		$this->initializeDatabase($this->cfg["mysql"]["host"], $this->cfg["mysql"]["port"], $this->cfg["mysql"]["username"], $this->cfg["mysql"]["password"], $this->cfg["mysql"]["database"], $this->cfg["mysql"]["table_prefix"]);
        		Server::getInstance()->getLogger()->info($this->translateColors("&", ServerAuth::PREFIX . $this->chlang["mysql-success"]));
        		$this->mysql = true;
        	}else{
        	}
        }
    }
    
    const API_VERSION = "1.1.1";
    
    public function getVersion(){
    	return ServerAuth::VERSION;
    }
    
    public function getAPIVersion(){
    	return ServerAuth::API_VERSION;
    }
    
    public function getDatabase(){
    	if($this->database instanceof \mysqli){
    		return $this->database;
    	}else{
    		return false;
    	}
    }
    
    public function getDatabaseConfig(){
    	return $this->getConfig()->getAll()["mysql"];
    }
    
    public function getDataProvider(){
    	return $this->mysql;
    }
    
    public function areRegisterMessagesEnabled(){
    	return $this->register_message;
    }
    
    public function enableRegisterMessages($bool = true){
    	if(is_bool($bool)){
    		$this->register_message = $bool;
    	}else{
    		$this->register_message = true;
    	}
    }
    
    public function areLoginMessagesEnabled(){
    	return $this->login_message;
    }
    
    public function enableLoginMessages($bool = true){
    	if(is_bool($bool)){
    		$this->login_message = $bool;
    	}else{
    		$this->login_message = true;
    	}
    }
    
    public function getCancelledMessage(){
    	return $this->canc_message;
    }
    
    public function getPlayerData($player){
    	if($this->isPlayerRegistered($player)){
    		if($this->getDataProvider()){
    			if($this->getDatabase() && $this->getDatabase()->ping()){
    				$stmt = $this->getDatabase()->prepare("SELECT user, password, ip, firstlogin, lastlogin FROM " . $this->getDatabaseConfig()["table_prefix"] . "serverauthdata WHERE user=?");
    				$stmt_player = strtolower($player);
    				$stmt->bind_param("s", $stmt_player);
    				if($stmt->execute()){
    					$stmt->bind_result($user, $password, $ip, $firstlogin, $lastlogin);
    					$stmt->fetch();
    					$data = array(
    						"password" => $password,
    						"ip" => $ip,
    						"firstlogin" => $firstlogin,
                            "lastlogin" => $lastlogin
    					);
    					$stmt->close();
    					return $data;
    				}else{
    					$stmt->close();
    					return ServerAuth::ERR_GENERIC;
    				}
    			}else{
    				return ServerAuth::ERR_GENERIC;
    			}
    		}else{
    			$cfg = new Config($this->getDataFolder() . "users/" . strtolower($player . ".yml"), Config::YAML);
    			return $cfg->getAll();
    		}
    	}else{
    		return $this->isPlayerRegistered($player);	
    	}
    }
    
    public function getPasswordHash(){
    	$cfg = $this->getConfig()->getAll();
    	return $cfg["passwordHash"];
    }
    
    public function getLanguage($language){
    	if(file_exists($this->getDataFolder() . "languages/" . $language . ".yml")){
    		return new Config($this->getDataFolder() . "languages/" . $language . ".yml", Config::YAML);
    	}elseif(file_exists($this->getDataFolder() . "languages/EN_en.yml")){
    		return new Config($this->getDataFolder() . "languages/EN_en.yml", Config::YAML);
    	}else{
    		@mkdir($this->getDataFolder() . "languages/");
    		$this->saveResource("languages/EN_en.yml");
    		return new Config($this->getDataFolder() . "languages/EN_en.yml", Config::YAML);
    	}
    }
    
    public function getConfigLanguage(){
    	$cfg = $this->getConfig()->getAll();
    	return $this->getLanguage($cfg["language"]);
    }
    
    public function isPlayerRegistered($player){
    	if($this->getDataProvider()){
    		if($this->getDatabase() && $this->getDatabase()->ping()){
    			$stmt = $this->getDatabase()->prepare("SELECT user, password, ip, firstlogin, lastlogin FROM " . $this->getDatabaseConfig()["table_prefix"] . "serverauthdata WHERE user=?");
    			$stmt_player = strtolower($player);
    			$stmt->bind_param("s", $stmt_player);
    			$stmt->execute();
    			$stmt->store_result();
    			if($stmt->num_rows == 0){
    				if(isset($this->cached_registered_users[strtolower($player)])){
    					unset($this->cached_registered_users[strtolower($player)]);
    				}
    				$stmt->close();
    				return false;
    			}else{
    				if(!isset($this->cached_registered_users[strtolower($player)])){
    					$this->cached_registered_users[strtolower($player)] = "";
    				}
    				$stmt->close();
    				return true;
    			}
    		}else{
    			return ServerAuth::ERR_GENERIC;
    		}
    	}else{
    		$status = file_exists($this->getDataFolder() . "users/" . strtolower($player . ".yml"));
    		if($status){
    			if(!isset($this->cached_registered_users[strtolower($player)])){
    				$this->cached_registered_users[strtolower($player)] = "";
    			}
    		}else{
    			if(isset($this->cached_registered_users[strtolower($player)])){
    				unset($this->cached_registered_users[strtolower($player)]);
    			}
    		}
    		return $status;
    	}
    }
    
    public function isPlayerAuthenticated(Player $player){
    	return isset($this->auth_users[strtolower($player->getName())]);
    }
    
    public function registerPlayer(Player $player, $password){
    	$cfg = $this->getConfig()->getAll();
    	if($this->isPlayerRegistered($player->getName())){
    		return ServerAuth::ERR_USER_ALREADY_REGISTERED;
    	}else{
    		if(strlen($password) <= $cfg["minPasswordLength"]){
    			return ServerAuth::ERR_PASSWORD_TOO_SHORT;
    		}elseif(strlen($password) >= $cfg["maxPasswordLength"]){
    			return ServerAuth::ERR_PASSWORD_TOO_LONG;
    		}else{
    			$this->canc_message = $this->chlang["operation-cancelled"];
    			$this->getServer()->getPluginManager()->callEvent($event = new Events\ServerAuthRegisterEvent($player, $password));
    			if($event->isCancelled()){
    				return ServerAuth::CANCELLED;
    			}
    			if($this->getDataProvider()){
    				if($this->getDatabase() && $this->getDatabase()->ping()){
    					if($cfg["register"]["enable-max-ip"]){
    						$stmt = $this->getDatabase()->prepare("SELECT user, password, ip, firstlogin, lastlogin FROM " . $this->getDatabaseConfig()["table_prefix"] . "serverauthdata WHERE ip=?");
    						$stmt_address = $player->getAddress();
    						$stmt->bind_param("s", $stmt_address);
    						$stmt->execute();
    						$stmt->store_result();
    						if($stmt->num_rows + 1 <= $cfg["register"]["max-ip"]){
    							$stmt = $this->getDatabase()->prepare("INSERT INTO " . $this->getDatabaseConfig()["table_prefix"] . "serverauthdata (user, password, ip, firstlogin, lastlogin) VALUES (?, ?, ?, ?, ?)");
    							$stmt_player = $player->getName();
    							$stmt_password = hash($this->getPasswordHash(), $password);
    							$stmt_address = $player->getAddress();
    							$stmt_firstlogin = $player->getFirstPlayed();
    							$stmt_lastlogin = $player->getLastPlayed();
    							$stmt->bind_param("sssss", $stmt_player, $stmt_password, $stmt_address, $stmt_firstlogin, $stmt_lastlogin);
    							if($stmt->execute()){
    								if(!isset($this->cached_registered_users[strtolower($player->getName())])){
    									$this->cached_registered_users[strtolower($player->getName())] = "";
    								}
    								$stmt->close();
    								return ServerAuth::SUCCESS;
    							}else{
    								$stmt->close();
    								return ServerAuth::ERR_GENERIC;
    							}
    						}else{
    							return ServerAuth::ERR_MAX_IP_REACHED;
    						}
    					}else{
    						$stmt = $this->getDatabase()->prepare("INSERT INTO " . $this->getDatabaseConfig()["table_prefix"] . "serverauthdata (user, password, ip, firstlogin, lastlogin) VALUES (?, ?, ?, ?, ?)");
    						$stmt_player = $player->getName();
    						$stmt_password = hash($this->getPasswordHash(), $password);
    						$stmt_address = $player->getAddress();
    						$stmt_firstlogin = $player->getFirstPlayed();
    						$stmt_lastlogin = $player->getLastPlayed();
    						$stmt->bind_param("sssss", $stmt_player, $stmt_password, $stmt_address, $stmt_firstlogin, $stmt_lastlogin);
    						if($stmt->execute()){
    							if(!isset($this->cached_registered_users[strtolower($player->getName())])){
    								$this->cached_registered_users[strtolower($player->getName())] = "";
    							}
    							$stmt->close();
    							return ServerAuth::SUCCESS;
    						}else{
    							$stmt->close();
    							return ServerAuth::ERR_GENERIC;
    						}
    					}
    				}else{
    					return ServerAuth::ERR_GENERIC;
    				}
    			}else{
    				if($cfg["register"]["enable-max-ip"]){
    					if($this->grep($this->getDataFolder() . "users/", $player->getAddress()) + 1 <= $cfg["register"]["max-ip"]){
    						$data = new Config($this->getDataFolder() . "users/" . strtolower($player->getName() . ".yml"), Config::YAML);
    						$data->set("password", hash($this->getPasswordHash(), $password));
    						$data->set("ip", $player->getAddress());
    						$data->set("firstlogin", $player->getFirstPlayed());
    						$data->set("lastlogin", $player->getLastPlayed());
    						$data->save();
    						if(!isset($this->cached_registered_users[strtolower($player->getName())])){
    							$this->cached_registered_users[strtolower($player->getName())] = "";
    						}
    						return ServerAuth::SUCCESS;
    					}else{
    						return ServerAuth::ERR_MAX_IP_REACHED;
    					}
    				}else{
    					$data = new Config($this->getDataFolder() . "users/" . strtolower($player->getName() . ".yml"), Config::YAML);
    					$data->set("password", hash($this->getPasswordHash(), $password));
    					$data->set("ip", $player->getAddress());
    					$data->set("firstlogin", $player->getFirstPlayed());
    					$data->set("lastlogin", $player->getLastPlayed());
    					$data->save();
    					if(!isset($this->cached_registered_users[strtolower($player->getName())])){
    						$this->cached_registered_users[strtolower($player->getName())] = "";
    					}
    					return ServerAuth::SUCCESS;
    				}
    			}
    		}
    	}
    }
    
    public function unregisterPlayer($player){
    	$pname = $player;
    	if($player instanceof Player || $player instanceof OfflinePlayer){
    		$pname = $player->getName();
    	}
    	if($this->isPlayerRegistered($pname)){
    		$this->canc_message = $this->chlang["operation-cancelled"];
    		$this->getServer()->getPluginManager()->callEvent($event = new Events\ServerAuthUnregisterEvent($player));
    		if($event->isCancelled()){
    			return ServerAuth::CANCELLED;
    		}
    		if($this->getDataProvider()){
    			if($this->getDatabase() && $this->getDatabase()->ping()){
    				$stmt = $this->getDatabase()->prepare("DELETE FROM " . $this->getDatabaseConfig()["table_prefix"] . "serverauthdata WHERE user=?");
    				$stmt_player = strtolower($pname);
    				$stmt->bind_param("s", $stmt_player);
    				if($stmt->execute()){
    					$stmt->close();
    					if(isset($this->cached_registered_users[strtolower($pname)])){
    						unset($this->cached_registered_users[strtolower($pname)]);
    					}
    				    if($player instanceof Player){
    						ServerAuth::getAPI()->deauthenticatePlayer($player);
    					}
    					ServerAuth::getAPI()->enableLoginMessages(true);
    					ServerAuth::getAPI()->enableRegisterMessages(true);
    					return ServerAuth::SUCCESS;
    				}else{
    					$stmt->close();
    					return ServerAuth::ERR_GENERIC;
    				}
    			}else{
    				return ServerAuth::ERR_GENERIC;
    			}
    		}else{
    			@unlink($this->getDataFolder() . "users/" . strtolower($pname . ".yml"));
    			if(isset($this->cached_registered_users[strtolower($pname)])){
    				unset($this->cached_registered_users[strtolower($pname)]);
    			}
    			if($player instanceof Player){
    				ServerAuth::getAPI()->deauthenticatePlayer($player);
    			}
    			ServerAuth::getAPI()->enableLoginMessages(true);
    			ServerAuth::getAPI()->enableRegisterMessages(true);
    			return ServerAuth::SUCCESS;
    		}
    	}else{
    		return ServerAuth::ERR_USER_NOT_REGISTERED;
    	}
    }
    
    public function authenticatePlayer(Player $player, $password, $hash = true){
    	if($hash){
    		$password = hash($this->getPasswordHash(), $password);
    	}
    	if($this->isPlayerRegistered($player->getName())){
    		if(!$this->isPlayerAuthenticated($player)){
    			$this->canc_message = $this->chlang["operation-cancelled"];
    			$this->getServer()->getPluginManager()->callEvent($event = new Events\ServerAuthAuthenticateEvent($player));
    			if($event->isCancelled()){
    				return ServerAuth::CANCELLED;
    			}
    			$cfg = $this->getConfig()->getAll();
    			if($this->getDataProvider()){
    				if($this->getDatabase() && $this->getDatabase()->ping()){
    					$stmt = $this->getDatabase()->prepare("SELECT user, password, ip, firstlogin, lastlogin FROM " . $this->getDatabaseConfig()["table_prefix"] . "serverauthdata WHERE user=?");
    					$stmt_player = strtolower($player->getName());
    					$stmt->bind_param("s", $stmt_player);
    					$stmt->execute();
    					$stmt->bind_result($user, $db_password, $ip, $firstlogin, $lastlogin);
    					$stmt->fetch();
    					$stmt->close();
    					if($db_password){
    						if($password == $db_password){
    							$stmt = $this->getDatabase()->prepare("UPDATE " . $this->getDatabaseConfig()["table_prefix"] . "serverauthdata SET ip=?, lastlogin=? WHERE user=?");
    							$stmt_ip = $player->getAddress();
    							$stmt_lastplayed = $player->getLastPlayed();
    							$stmt_player = strtolower($player->getName());
    							$stmt->bind_param("sss", $stmt_ip, $stmt_lastplayed, $stmt_player);
    							if($stmt->execute()){
    								$this->auth_users[strtolower($player->getName())] = "";
    								if($cfg['login']['enable-failed-logins-kick'] && isset($this->auth_attempts[strtolower($player->getName())])){
    									unset($this->auth_attempts[strtolower($player->getName())]);
    								}
    								$stmt->close();
    								return ServerAuth::SUCCESS;
    							}else{
    								$stmt->close();
    								return ServerAuth::ERR_GENERIC;
    							}
    						}else{
    							if($cfg['login']['enable-failed-logins-kick']){
    								if(isset($this->auth_attempts[strtolower($player->getName())])){
    									$this->auth_attempts[strtolower($player->getName())]++;
    								}else{
    									$this->auth_attempts[strtolower($player->getName())] = 1;
    								}
    								if($this->auth_attempts[strtolower($player->getName())] >= $cfg['login']['max-login-attempts']){
    									$player->close("", $this->translateColors("&", $this->chlang["login"]["too-many-attempts"]));
    									unset($this->auth_attempts[strtolower($player->getName())]);
    									return ServerAuth::TOO_MANY_ATTEMPTS;
    								}
    							}
    							return ServerAuth::ERR_WRONG_PASSWORD;
    						}
    					}else{
    						return ServerAuth::ERR_GENERIC;
    					}
    				}else{
    					return ServerAuth::ERR_GENERIC;
    				}
    			}else{
    				$data = new Config($this->getDataFolder() . "users/" . strtolower($player->getName() . ".yml"), Config::YAML);
    				if($password == $data->get("password")){
    					$data->set("ip", $player->getAddress());
    					$data->set("lastlogin", $player->getLastPlayed());
    					$data->save();
    					$this->auth_users[strtolower($player->getName())] = "";
    					if($cfg['login']['enable-failed-logins-kick'] && isset($this->auth_attempts[strtolower($player->getName())])){
    						unset($this->auth_attempts[strtolower($player->getName())]);
    					}
    					return ServerAuth::SUCCESS;
    				}else{
    					if($cfg['login']['enable-failed-logins-kick']){
    						if(isset($this->auth_attempts[strtolower($player->getName())])){
    							$this->auth_attempts[strtolower($player->getName())]++;
    						}else{
    							$this->auth_attempts[strtolower($player->getName())] = 1;
    						}
    						if($this->auth_attempts[strtolower($player->getName())] >= $cfg['login']['max-login-attempts']){
    							$player->close("", $this->translateColors("&", $this->chlang["login"]["too-many-attempts"]));
    							unset($this->auth_attempts[strtolower($player->getName())]);
    							return ServerAuth::TOO_MANY_ATTEMPTS;
    						}
    					}    					
    					return ServerAuth::ERR_WRONG_PASSWORD;
    				}
    			}
    		}else{
    			return ServerAuth::ERR_USER_ALREADY_AUTHENTICATED;
    		}
    	}else{
    		return $this->isPlayerRegistered($player->getName());
    	}
    }
    
    public function deauthenticatePlayer(Player $player){
    	if($this->isPlayerAuthenticated($player)){
    		$this->canc_message = $this->chlang["operation-cancelled"];
    		$this->getServer()->getPluginManager()->callEvent($event = new Events\ServerAuthDeauthenticateEvent($player));
    		if($event->isCancelled()){
    			return ServerAuth::CANCELLED;
    		}
    		ServerAuth::getAPI()->enableLoginMessages(true);
    		ServerAuth::getAPI()->enableRegisterMessages(true);
    		unset($this->auth_users[strtolower($player->getName())]);
    		return ServerAuth::SUCCESS;
    	}else{
    		return ServerAuth::ERR_USER_NOT_AUTHENTICATED;
    	}
    }
    
    public function changePlayerPassword($player, $new_password){
    	if($player instanceof Player || $player instanceof OfflinePlayer){
	    	$cfg = $this->getConfig()->getAll();
	    	if($this->isPlayerRegistered($player->getName())){
	    		if(strlen($new_password) < $cfg["minPasswordLength"]){
	    			return ServerAuth::ERR_PASSWORD_TOO_SHORT;
	    		}elseif(strlen($new_password) > $cfg["maxPasswordLength"]){
	    			return ServerAuth::ERR_PASSWORD_TOO_LONG;
	    		}else{
	    			$this->canc_message = $this->chlang["operation-cancelled"];
	    			$this->getServer()->getPluginManager()->callEvent($event = new Events\ServerAuthPasswordChangeEvent($player, $new_password));
	    			if($event->isCancelled()){
	    				return ServerAuth::CANCELLED;
	    			}
	    			if($this->getDataProvider()){
	    				if($this->getDatabase() && $this->getDatabase()->ping()){
	    					$stmt = $this->getDatabase()->prepare("UPDATE " . $this->getDatabaseConfig()["table_prefix"] . "serverauthdata SET password=? WHERE user=?");
	    					$stmt_password = hash($this->getPasswordHash(), $new_password);
	    					$stmt_player = strtolower($player->getName());
	    					$stmt->bind_param("ss", $stmt_password, $stmt_player);
	    					if($stmt->execute()){
	    						$stmt->close();
	    						return ServerAuth::SUCCESS;
	    					}else{
	    						$stmt->close();
	    						return ServerAuth::ERR_GENERIC;
	    					}
	    				}else{
	    					return ServerAuth::ERR_GENERIC;
	    				}
	    			}else{
	    				$data = new Config($this->getDataFolder() . "users/" . strtolower($player->getName() . ".yml"), Config::YAML);
	    				$data->set("password", hash($this->getPasswordHash(), $new_password));
	    				$data->save();
	    				return ServerAuth::SUCCESS;
	    			}	
	    		}
	    	}else{
	    		return $this->isPlayerRegistered($player->getName());
	    	}
    	}else{
    		return ServerAuth::ERR_USER_NOT_REGISTERED;
    	}
    }
    
}
?>