public class Utils {
     //private Settings settings = Settings.getInstance();
     private Player player;
     private String currentGroup;
     private static Utils singleton;
     private String unLoggedGroup = Settings.getUnloggedinGroup;
  /*   
  public Utils(Player player) {
      this.player = player;
      
  }
  */
  public void setGroup(Player player, groupType group) {
    if (!player.isOnline())
        return;
    if(!Settings.isPermissionCheckEnabled)
        return;
    
        switch(group) {
            case UNREGISTERED: {
                currentGroup = AuthMe.permission.getPrimaryGroup(player);
                AuthMe.permission.playerRemoveGroup(player, currentGroup);
                AuthMe.permission.playerAddGroup(player, Settings.unRegisteredGroup);
                break;
            }
            case REGISTERED: {
                currentGroup = AuthMe.permission.getPrimaryGroup(player);
                AuthMe.permission.playerRemoveGroup(player, currentGroup);
                AuthMe.permission.playerAddGroup(player, Settings.getRegisteredGroup);
                break;
            }                
        }
        return;
    }
  
    public String removeAll(Player player) {
        if(!Utils.getInstance().useGroupSystem()){
            return null;
        }
        
        /*if (AuthMe.permission.playerAdd(this.player,"-*") ) {
            AuthMe.permission.playerAdd(this.player,"authme.login");
            return true;
        }*/
        
        
        //System.out.println("permissions? "+ hasPerm);
        if( !Settings.getJoinPermissions.isEmpty() ) {
            hasPermOnJoin(player);
        }
        
        this.currentGroup = AuthMe.permission.getPrimaryGroup(player.getWorld(),player.getName().toString());
        //System.out.println("current grop" + currentGroup);
        if(AuthMe.permission.playerRemoveGroup(player.getWorld(),player.getName().toString(), currentGroup) && AuthMe.permission.playerAddGroup(player.getWorld(),player.getName().toString(),this.unLoggedGroup)) {
            
            return currentGroup;
        }
        
        return null;
        
    }
    
    public boolean addNormal(Player player, String group) {
       if(!Utils.getInstance().useGroupSystem()){
            return false;
        }
       // System.out.println("in add normal");
       /* if (AuthMe.permission.playerRemove(this.player, "-*"))
            return true;
       */      
        if(AuthMe.permission.playerRemoveGroup(player.getWorld(),player.getName().toString(),this.unLoggedGroup) && AuthMe.permission.playerAddGroup(player.getWorld(),player.getName().toString(),group)) {
        //System.out.println("vecchio "+this.unLoggedGroup+ "nuovo" + group);
            return true;
        
        }
        return false;
    }    

    private String hasPermOnJoin(Player player) {
       /* if(Settings.getJoinPermissions.isEmpty())
            return null; */
              Iterator<String> iter = Settings.getJoinPermissions.iterator();
                while (iter.hasNext()) {
                    String permission = iter.next();
                 // System.out.println("permissions? "+ permission);
                     
                   if(AuthMe.permission.playerHas(player, permission)){
                     //  System.out.println("player has permissions " +permission);
                       AuthMe.permission.playerAddTransient(player, permission);
                   }
                }
           return null;
    }
    
    public boolean isUnrestricted(Player player) {
        
        
        if(Settings.getUnrestrictedName.isEmpty() || Settings.getUnrestrictedName == null)
            return false;
        
     //   System.out.println("name to escape "+player.getName());
        if(Settings.getUnrestrictedName.contains(player.getName())) {
       //     System.out.println("name to escape correctly"+player.getName());
            return true;
        }
        
        return false;
        
         
    }
     public static Utils getInstance() {
        
            singleton = new Utils();
        
        return singleton;
    } 
    
    private boolean useGroupSystem() {
        
        if(Settings.isPermissionCheckEnabled && !Settings.getUnloggedinGroup.isEmpty()) {
            return true;
        } return false;
            
    }
    
    /*
     * Random Token for passpartu
     * 
     */
    public boolean obtainToken() {
        File file = new File("plugins/AuthMe/passpartu.token");

	if (file.exists())
            file.delete();

		FileWriter writer = null;
		try {
			file.createNewFile();
			writer = new FileWriter(file);
                        String token = generateToken();
                        writer.write(token+":"+System.currentTimeMillis()/1000+"\r\n");
                        writer.flush();
                        System.out.println("[AuthMe] Security passpartu token: "+ token);
                        writer.close();
                        return true;
                } catch(Exception e) {
                    e.printStackTrace(); 
                }
                
        
        return false;
    }
    
    /*
     * Read Toekn
     */
    public boolean readToken(String inputToken) {
        File file = new File("plugins/AuthMe/passpartu.token");
        
	if (!file.exists()) 	
            return false;
        
        if (inputToken.isEmpty() )
            return false;
        
		Scanner reader = null;
		try {
			reader = new Scanner(file);

			while (reader.hasNextLine()) {
				final String line = reader.nextLine();

				if (line.contains(":")) {   
                                   String[] tokenInfo = line.split(":");
                                   //System.err.println("Authme input token "+inputToken+" saved token "+tokenInfo[0]);
                                   //System.err.println("Authme time "+System.currentTimeMillis()/1000+"saved time "+Integer.parseInt(tokenInfo[1]));
                                   if(tokenInfo[0].equals(inputToken) && System.currentTimeMillis()/1000-30 <= Integer.parseInt(tokenInfo[1]) ) { 
                                       file.delete();
                                       reader.close();
                                       return true;
                                   }
                                } 
                        }
                } catch(Exception e) {
                    e.printStackTrace(); 
                }
                
	reader.close();        
        return false;
    }
    /*
     * Generate Random Token
     */
    private String generateToken() {
           // obtain new random token 
           Random rnd = new Random ();
            char[] arr = new char[5];

            for (int i=0; i<5; i++) {
                    int n = rnd.nextInt (36);
                    arr[i] = (char) (n < 10 ? '0'+n : 'a'+n-10);
            }
            
            return new String(arr);        
    }
    public enum groupType {
        UNREGISTERED, REGISTERED, NOTLOGGEDIN, LOGGEDIN
    }
    
}
 public class PlayerAuth {

    private String nickname;
    private String hash;
    private String ip;
    private long lastLogin;
    private int x,y,z;
    private String salt = "";
    private String vBhash = null;
    private int groupId;

    public PlayerAuth(String nickname, String hash, String ip, long lastLogin) {
        this.nickname = nickname;
        this.hash = hash;
        this.ip = ip;
        this.lastLogin = lastLogin;
        
    }
    
    public PlayerAuth(String nickname, int x, int y, int z) {
        this.nickname = nickname;
        this.x = x;
        this.y = y;
        this.z = z;
    }
    
    public PlayerAuth(String nickname, String hash, String ip, long lastLogin, int x, int y, int z) {
        this.nickname = nickname;
        this.hash = hash;
        this.ip = ip;
        this.lastLogin = lastLogin;
        this.x = x;
        this.y = y;
        this.z = z;   
    }
    
    //
    // This constructor is needed for Vbulletin board Auth!
    //
    public PlayerAuth(String nickname, String hash, String salt, int groupId, String ip, long lastLogin, int x, int y, int z) {
        this.nickname = nickname;
        this.hash = hash;
        this.ip = ip;
        this.lastLogin = lastLogin;
        this.x = x;
        this.y = y;
        this.z = z;   
        this.salt = salt;
        this.groupId = groupId;
        //System.out.println("[Authme Debug] password hashed from db"+hash);
        //System.out.println("[Authme Debug] salt from db"+salt);        
    }
    
    public String getIp() {
        return ip;
    }

    public String getNickname() {
        return nickname;
    }

    public String getHash() {
        if(!salt.isEmpty())
            // Compose Vbullettin Hash System!
            return this.vBhash = "$MD5vb$"+salt+"$"+hash;
        else
            return hash;
    }
    
    //
    // GroupId for unactivated User on Vbullettin Board
    //
    public int getGroupId() {
        return groupId;
    }
    
    public int getQuitLocX() {
        return x;
    }
    public int getQuitLocY() {
        return y;
    }
    public int getQuitLocZ() {
        return z;
    }
    public void setQuitLocX(int x) {
        this.x = x;
    }
    public void setQuitLocY(int y) {
        this.y = y;
    }
    public void setQuitLocZ(int z) {
        this.z = z;
    }  
    public long getLastLogin() {
        return lastLogin;
    }

    public void setHash(String hash) {
        this.hash = hash;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public void setLastLogin(long lastLogin) {
        this.lastLogin = lastLogin;
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof PlayerAuth)) {
            return false;
        }
        PlayerAuth other = (PlayerAuth) obj;
        
        return other.getIp().equals(this.ip) && other.getNickname().equals(this.nickname);
    }

    @Override
    public int hashCode() {
        int hashCode = 7;
        hashCode = 71 * hashCode + (this.nickname != null ? this.nickname.hashCode() : 0);
        hashCode = 71 * hashCode + (this.ip != null ? this.ip.hashCode() : 0);
        return hashCode;
    }
}
 public class DataFileCache {


	private ItemStack[] inventory;
	private ItemStack[] armor;	
        private String group;
        private boolean operator;

	public DataFileCache(ItemStack[] inventory, ItemStack[] armor){
		this.inventory = inventory;
		this.armor = armor;
                
	}

	public DataFileCache(ItemStack[] inventory, ItemStack[] armor, String group, boolean operator){
		this.inventory = inventory;
		this.armor = armor;
                this.group = group;
                this.operator = operator;
	}        
	public ItemStack[] getInventory(){
		return inventory;
	}

	public ItemStack[] getArmour(){
		return armor;
	}
        
	public String getGroup(){
		return group;
	}
        
	public Boolean getOperator(){
                return operator;
	}         
}    
 public class FileCache {
        //private HashMap<Enchantment, Integer> ench;
            
        
	public FileCache() {
		final File folder = new File("cache");
		if (!folder.exists()) {
			folder.mkdirs();
		}
	}

	public void createCache(String playername, DataFileCache playerData, String group, boolean operator) {
		final File file = new File("cache/" + playername
				+ ".cache");

		if (file.exists()) {
			return;
		}

		FileWriter writer = null;
		try {
			file.createNewFile();

			writer = new FileWriter(file);
                        
                        // put player group in cache
                        // put if player is an op or not 1: is op 0: isnet op!
                        // line format Group|OperatorStatus
                        
                        if(operator)
                            writer.write(group+";1\r\n");
                        else writer.write(group+";0\r\n");
                        
                        writer.flush();
                        
			ItemStack[] invstack = playerData.getInventory();

			for (int i = 0; i < invstack.length; i++) {

				int itemid = 0;
				int amount = 0;
				int durability = 0;
                                String enchList = "";
                                //ench = new HashMap<Enchantment, Integer>();

				if (invstack[i] != null) {
					itemid = invstack[i].getTypeId();
					amount = invstack[i].getAmount();
					durability = invstack[i].getDurability();
                                                   
                                        
                                                for(Enchantment e : invstack[i].getEnchantments().keySet())
                                                 {
                                                    //System.out.println("enchant "+e.getName()+" bog "+invstack[i].getEnchantmentLevel(e));
                                                    enchList = enchList.concat(e.getName()+":"+invstack[i].getEnchantmentLevel(e)+":");
                                                    //System.out.println(enchList);
                                                    
                                                 }
                                        }
                                    
				writer.write("i" + ":" + itemid + ":" + amount + ":"
						+ durability + ":"+ enchList + "\r\n");
				writer.flush();
			}

			ItemStack[] armorstack = playerData.getArmour();

			for (int i = 0; i < armorstack.length; i++) {
				int itemid = 0;
				int amount = 0;
				int durability = 0;
                                String enchList = "";
                                
				if (armorstack[i] != null) {
					itemid = armorstack[i].getTypeId();
					amount = armorstack[i].getAmount();
					durability = armorstack[i].getDurability();
                                        
                                                for(Enchantment e : armorstack[i].getEnchantments().keySet())
                                                 {
                                                    //System.out.println("enchant "+e.getName()+" bog "+armorstack[i].getEnchantmentLevel(e));
                                                    enchList = enchList.concat(e.getName()+":"+armorstack[i].getEnchantmentLevel(e)+":");
                                                    //System.out.println(enchList);
                                                    
                                                 }                                        
				}

				writer.write("w" + ":" + itemid + ":" + amount + ":"
						+ durability + ":"+ enchList + "\r\n");
				writer.flush();
			}

			writer.close();
		} catch (final Exception e) {
			e.printStackTrace();
		}
	}

	public DataFileCache readCache(String playername) {
		final File file = new File("cache/" + playername
				+ ".cache");

		ItemStack[] stacki = new ItemStack[36];
		ItemStack[] stacka = new ItemStack[4];
                String group = null;
                boolean op = false;
                
		if (!file.exists()) {
			return new DataFileCache(stacki, stacka);
		}

		Scanner reader = null;
		try {
			reader = new Scanner(file);

			int i = 0;
			int a = 0;
			while (reader.hasNextLine()) {
				final String line = reader.nextLine();

				if (!line.contains(":")) {
                                   // the fist line rapresent the player group and operator status
                                    final String[] playerInfo = line.split(";");
                                    group = playerInfo[0];
                                    
                                        if (Integer.parseInt(playerInfo[1]) == 1) {
                                            op = true;
                                        } else op = false;
                                        
                                    continue;
				}

				final String[] in = line.split(":");

				/*if (in.length != 4) {
					continue;
				} */
                                
				if (!in[0].equals("i") && !in[0].equals("w")) {
					continue;
				}
                        // can enchant item? size ofstring in file - 4  all / 2 = number of enchant
				if (in[0].equals("i")) {
                                    Enchantment e = null;  
                                    
					stacki[i] = new ItemStack(Integer.parseInt(in[1]),
							Integer.parseInt(in[2]), Short.parseShort((in[3])));
					// qui c'e' un problema serio!
                                        if(in.length > 4 && !in[4].isEmpty()) {
                                             for(int k=4;k<in.length-1;k++) {
                                                //System.out.println("enchant "+in[k]);
                                                stacki[i].addUnsafeEnchantment(e.getByName(in[k]) ,Integer.parseInt(in[k+1]));
                                                k++;
                                             }
                                        }
                                        i++;
				} else {
                                    Enchantment e = null;  
					stacka[a] = new ItemStack(Integer.parseInt(in[1]),
							Integer.parseInt(in[2]), Short.parseShort((in[3])));
                                        if(in.length > 4 && !in[4].isEmpty()) {
                                           for(int k=4;k<in.length-1;k++) {
                                                //System.out.println("enchant "+in[k]);
                                                stacka[a].addUnsafeEnchantment(e.getByName(in[k]) ,Integer.parseInt(in[k+1]));
                                                k++;
                                           }
                                        }
					a++;
				}

			}
		} catch (final Exception e) {
			e.printStackTrace();
		} finally {
			if (reader != null) {
				reader.close();
			}
		}
		return new DataFileCache(stacki, stacka, group, op);
	}

	public void removeCache(String playername) {
		final File file = new File("cache/" + playername
				+ ".cache");

		if (file.exists()) {
			file.delete();
		}
	}

	public boolean doesCacheExist(String playername) {
		final File file = new File("cache/" + playername
				+ ".cache");

		if (file.exists()) {
			return true;
		}
		return false;
	}

    
}
 public class LimboCache {

    private static LimboCache singleton = null;
    private HashMap<String, LimboPlayer> cache;
   //private Settings settings = Settings.getInstance();
    private FileCache playerData = new FileCache();
    
    private LimboCache() {
        this.cache = new HashMap<String, LimboPlayer>();
    }

    public void addLimboPlayer(Player player) {
        String name = player.getName().toLowerCase();
        Location loc = player.getLocation();
        int gameMode = player.getGameMode().getValue();
        ItemStack[] arm;
        ItemStack[] inv;
        boolean operator;
        String playerGroup = "";
        
        if (playerData.doesCacheExist(name)) {
            //DataFileCache playerInvArmor =  playerData.readCache(name);    
             inv =  playerData.readCache(name).getInventory();
             arm =  playerData.readCache(name).getArmour();
             playerGroup = playerData.readCache(name).getGroup();
             operator = playerData.readCache(name).getOperator();
        } else {
        inv =  player.getInventory().getContents();
        arm =  player.getInventory().getArmorContents();
            
        // check if player is an operator, then save it to ram if cache dosent exist!
        
            if(player.isOp() ) {
                //System.out.println("player is an operator in limboCache");
                operator = true;
                }
                   else operator = false;      
        }

       
        
        if(Settings.isForceSurvivalModeEnabled) {
            if(Settings.isResetInventoryIfCreative && gameMode != 0 ) {
               player.sendMessage("Your inventory has been cleaned!");
               inv = new ItemStack[36];
               arm = new ItemStack[4];
            }
            gameMode = 0;
        } 
        if(player.isDead()) {
        	loc = player.getWorld().getSpawnLocation();
        }
        
        if(cache.containsKey(name) && playerGroup.isEmpty()) {
            //System.out.println("contiene il player "+name);
            LimboPlayer groupLimbo = cache.get(name);
            playerGroup = groupLimbo.getGroup();
        }
        
        cache.put(player.getName().toLowerCase(), new LimboPlayer(name, loc, inv, arm, gameMode, operator, playerGroup));
    //System.out.println("il gruppo in limboChace "+playerGroup);
    }
    
    public void addLimboPlayer(Player player, String group) {
        
        cache.put(player.getName().toLowerCase(), new LimboPlayer(player.getName().toLowerCase(), group));
   //System.out.println("il gruppo in limboChace "+group);
    }
    
    public void deleteLimboPlayer(String name) {
        cache.remove(name);
    }

    public LimboPlayer getLimboPlayer(String name) {
        return cache.get(name);
    }

    public boolean hasLimboPlayer(String name) {
        return cache.containsKey(name);
    }
    
    
    public static LimboCache getInstance() {
        if (singleton == null) {
            singleton = new LimboCache();
        }
        return singleton;
    }
}
 public interface DataSource {

    public enum DataSourceType {

        MYSQL, FILE, SQLITE
    }

    boolean isAuthAvailable(String user);

    PlayerAuth getAuth(String user);

    boolean saveAuth(PlayerAuth auth);

    boolean updateSession(PlayerAuth auth);

    boolean updatePassword(PlayerAuth auth);

    int purgeDatabase(long until);

    boolean removeAuth(String user);
   
    boolean updateQuitLoc(PlayerAuth auth);
    
    int getIps(String ip);
    
    void close();

    void reload();
}
 public class LoginScreen extends GenericPopup implements Clickable{

	private SpoutPlayer splayer;
	private AuthMe plugin = AuthMe.getInstance();
	private SpoutCfg spoutCfg = SpoutCfg.getInstance();
	
	private CustomButton exitBtn;
	private CustomButton loginBtn;
	private GenericTextField passBox;
	private GenericLabel titleLbl;
	private GenericLabel textLbl;
	private GenericLabel errorLbl;
	
	String exitTxt = spoutCfg.getString("LoginScreen.exit button"); //"Quit";
	String loginTxt = spoutCfg.getString("LoginScreen.login button"); //"Login";
	String exitMsg = spoutCfg.getString("LoginScreen.exit message"); //"Good Bye";
	String title = spoutCfg.getString("LoginScreen.title"); //"LOGIN"
	List<String> textlines = spoutCfg.getStringList("LoginScreen.text");
	
	public LoginScreen(SpoutPlayer player) {
		this.splayer = player;
		
		createScreen();
	}

	private void createScreen() {
		int objects = textlines.size() + 4;
		int part = !(textlines.size() <= 5) ? 195 / objects : 20;
		int h = 3*part/4, w = 8*part;
		
		titleLbl = new GenericLabel();
		titleLbl
			.setText(title)
			.setTextColor(new Color(1.0F, 0, 0, 1.0F))
			.setAlign(WidgetAnchor.TOP_CENTER)
			.setHeight(h)
			.setWidth(w)
			.setX(maxWidth / 2 )
			.setY(25);
		this.attachWidget(plugin, titleLbl);
		
		int ystart = 25 + h + part/2;
		for (int x=0; x<textlines.size();x++)
		{
			textLbl = new GenericLabel();
			textLbl
				.setText(textlines.get(x))
				.setAlign(WidgetAnchor.TOP_CENTER)
				.setHeight(h)
				.setWidth(w)
				.setX(maxWidth / 2)
				.setY(ystart + x*part);
			this.attachWidget(plugin, textLbl);
		}
		
		passBox = new GenericTextField();
		passBox
			.setMaximumCharacters(18)
			.setMaximumLines(1)
			.setHeight(h-2)
			.setWidth(w-2)
			.setY(220-h - 2*part);
		passBox.setPasswordField(true);
		setXToMid(passBox);
		this.attachWidget(plugin, passBox);
		
		errorLbl = new GenericLabel();
		errorLbl
			.setText("")
			.setTextColor(new Color(1.0F, 0, 0, 1.0F))
			.setHeight(h)
			.setWidth(w)
			.setX(passBox.getX() + passBox.getWidth() + 2)
			.setY(passBox.getY());
		this.attachWidget(plugin, errorLbl);
		
		loginBtn = new CustomButton(this);
		loginBtn
			.setText(loginTxt)
			.setHeight(h)
			.setWidth(w)
			.setY(220-h-part);
		setXToMid(loginBtn);
		this.attachWidget(plugin, loginBtn);
		
		exitBtn = new CustomButton(this);
		exitBtn
			.setText(exitTxt)
			.setHeight(h)
			.setWidth(w)
			.setY(220-h);
		setXToMid(exitBtn);
		this.attachWidget(plugin, exitBtn);
		
	}

	public void handleClick(ButtonClickEvent event) {
		Button b = event.getButton();
		if (b.equals(loginBtn))
		{
			//System.out.println("player: " + event.getPlayer().getName() + ", Password: " + passBox.getText() + ", Management: " + plugin.management + ", Plugin: " + plugin);
			String result = plugin.management.performLogin(event.getPlayer(), passBox.getText());
			if(result == "") event.getPlayer().closeActiveWindow();
			else
			{
				errorLbl.setText(result);
				passBox.setText("");
			}
		}else if(b.equals(exitBtn))
		{
			event.getPlayer().kickPlayer(exitMsg);
		}
	}

	private void setXToMid(Widget w) {
		w.setX( (maxWidth - w.getWidth()) / 2);
	}
	

}
 public class Messages extends CustomConfiguration {

    private static Messages singleton = null;
    private HashMap<String, String> map;
    

    public Messages() {
        
        super(new File(Settings.MESSAGE_FILE+"_"+Settings.messagesLanguage+".yml"));
        loadDefaults();
        loadFile();
        singleton = this;
        
    }
    
    private void loadDefaults() {
        this.set("logged_in", "&cAlready logged in!");
        this.set("not_logged_in", "&cNot logged in!");
        this.set("reg_disabled", "&cRegistration is disabled");
        this.set("user_regged", "&cUsername already registered");
        this.set("usage_reg", "&cUsage: /register password ConfirmPassword");
        this.set("usage_log", "&cUsage: /login password");
        this.set("user_unknown", "&cUsername not registered");
        this.set("pwd_changed", "&cPassword changed!");
        this.set("reg_only", "Registered players only! Please visit http://example.com to register");
        this.set("valid_session", "&cSession login");
        this.set("login_msg", "&cPlease login with \"/login password\"");
        this.set("reg_msg", "&cPlease register with \"/register password ConfirmPassword\"");
        this.set("timeout", "Login Timeout");
        this.set("wrong_pwd", "&cWrong password");
        this.set("logout", "&cSuccessful logout");
        this.set("usage_unreg", "&cUsage: /unregister password");
        this.set("registered", "&cSuccessfully registered!");
        this.set("unregistered", "&cSuccessfully unregistered!");
        this.set("login", "&cSuccessful login!");
        this.set("no_perm", "&cNo Permission");
        this.set("same_nick", "Same nick is already playing");
        this.set("reg_voluntarily", "You can register your nickname with the server with the command \"/register password ConfirmPassword\"");
        this.set("reload", "Configuration and database has been reloaded");
        this.set("error", "An error ocurred; Please contact the admin");
        this.set("unknown_user", "User is not in database");
        this.set("unsafe_spawn","Your Quit location was unsafe, teleporting you to World Spawn");
        this.set("unvalid_session","Session Dataes doesnt corrispond Plaese wait the end of session");
        this.set("max_reg","You have Exeded the max number of Registration for your Account"); 
        this.set("password_error","Password doesnt match");
        this.set("pass_len","Your password dind't reach the minimum length or exeded the max length");
        this.set("vb_nonActiv","Your Account isent Activated yet check your Emails!");
        this.set("usage_changepassword", "Usage: /changepassword oldPassword newPassword");
        
    }

	private void loadFile() {
        this.load();
        this.save();
       
    }

    public String _(String msg) {
        String loc = this.getString(msg);
        if (loc != null) {
            return loc.replace("&", "\u00a7");
        }
        return msg;
    }
    
    
    public static Messages getInstance() {
        if (singleton == null) {
            singleton = new Messages();
        }        
        return singleton;
    }
       
}
 public final class Settings extends YamlConfiguration {

    public static final String PLUGIN_FOLDER = "./plugins/AuthMe";
    public static final String CACHE_FOLDER = Settings.PLUGIN_FOLDER + "/cache";
    public static final String AUTH_FILE = Settings.PLUGIN_FOLDER + "/auths.db";
    public static final String MESSAGE_FILE = Settings.PLUGIN_FOLDER + "/messages";
    public static final String SETTINGS_FILE = Settings.PLUGIN_FOLDER + "/config.yml";
    public static List<String> getJoinPermissions = null;
    public static List<String> getUnrestrictedName = null;
    private static List<String> getRestrictedIp;
   
    private int numSettings = 59;
    public final Plugin plugin;
    private final File file;    
    
    public static DataSourceType getDataSource;
    public static HashAlgorithm getPasswordHash;
    
    public static Boolean isPermissionCheckEnabled, isRegistrationEnabled, isForcedRegistrationEnabled,
            isTeleportToSpawnEnabled, isSessionsEnabled, isChatAllowed, isAllowRestrictedIp, 
            isMovementAllowed, isKickNonRegisteredEnabled, isForceSingleSessionEnabled,
            isForceSpawnLocOnJoinEnabled, isForceExactSpawnEnabled, isSaveQuitLocationEnabled,
            isForceSurvivalModeEnabled, isResetInventoryIfCreative, isCachingEnabled, isKickOnWrongPasswordEnabled,
            getEnablePasswordVerifier, protectInventoryBeforeLogInEnabled, isBackupActivated, isBackupOnStart,
            isBackupOnStop, enablePasspartu;
            
            
    public static String getNickRegex, getUnloggedinGroup, getMySQLHost, getMySQLPort, 
            getMySQLUsername, getMySQLPassword, getMySQLDatabase, getMySQLTablename, 
            getMySQLColumnName, getMySQLColumnPassword, getMySQLColumnIp, getMySQLColumnLastLogin,
            getMySQLColumnSalt, getMySQLColumnGroup, unRegisteredGroup, backupWindowsPath,
            getcUnrestrictedName, getRegisteredGroup, messagesLanguage;
            
    
    public static int getWarnMessageInterval, getSessionTimeout, getRegistrationTimeout, getMaxNickLength,
            getMinNickLength, getPasswordMinLen, getMovementRadius, getmaxRegPerIp, getNonActivatedGroup,
            passwordMaxLength;
                    
    protected static YamlConfiguration configFile;
    
   public Settings(Plugin plugin) {
        //super(new File(Settings.PLUGIN_FOLDER + "/config.yml"), this.plugin);
        this.file = new File(plugin.getDataFolder(),"config.yml");
        
        this.plugin = plugin;

              

        //options().indent(4); 
        // Override to always indent 4 spaces
        if(exists()) {
            load();         
         }
        else {
            loadDefaults(file.getName());
            load();
        }
        
        configFile = (YamlConfiguration) plugin.getConfig();
        
        //saveDefaults();
        
    }
   
   public void loadConfigOptions() {
       
        plugin.getLogger().info("Loading Configuration File...");
        
        mergeConfig();
        
        messagesLanguage = checkLang(configFile.getString("settings.messagesLanguage","en"));
        isPermissionCheckEnabled = configFile.getBoolean("permission.EnablePermissionCheck", false);
        isForcedRegistrationEnabled  = configFile.getBoolean("settings.registration.force", true);
        isRegistrationEnabled = configFile.getBoolean("settings.registration.enabled", true);
        isTeleportToSpawnEnabled = configFile.getBoolean("settings.restrictions.teleportUnAuthedToSpawn",false);
        getWarnMessageInterval = configFile.getInt("settings.registration.messageInterval",5);
        isSessionsEnabled = configFile.getBoolean("settings.sessions.enabled",false);
        getSessionTimeout = configFile.getInt("settings.sessions.timeout",10);
        getRegistrationTimeout = configFile.getInt("settings.restrictions.timeout",30);
        isChatAllowed = configFile.getBoolean("settings.restrictions.allowChat",false);
        getMaxNickLength = configFile.getInt("settings.restrictions.maxNicknameLength",20);
        getMinNickLength = configFile.getInt("settings.restrictions.minNicknameLength",3);
        getPasswordMinLen = configFile.getInt("settings.security.minPasswordLength",4);
        getNickRegex = configFile.getString("settings.restrictions.allowedNicknameCharacters","[a-zA-Z0-9_?]*");
        isAllowRestrictedIp = configFile.getBoolean("settings.restrictions.AllowRestrictedUser",false);
        getRestrictedIp = configFile.getStringList("settings.restrictions.AllowedRestrictedUser");
        isMovementAllowed = configFile.getBoolean("settings.restrictions.allowMovement",false);
        getMovementRadius = configFile.getInt("settings.restrictions.allowedMovementRadius",100);
        getJoinPermissions = configFile.getStringList("GroupOptions.Permissions.PermissionsOnJoin");
        isKickOnWrongPasswordEnabled = configFile.getBoolean("settings.restrictions.kickOnWrongPassword",false);
        isKickNonRegisteredEnabled = configFile.getBoolean("settings.restrictions.kickNonRegistered",false);
        isForceSingleSessionEnabled = configFile.getBoolean("settings.restrictions.ForceSingleSession",true);
        isForceSpawnLocOnJoinEnabled = configFile.getBoolean("settings.restrictions.ForceSpawnLocOnJoinEnabled",false);
        isSaveQuitLocationEnabled = configFile.getBoolean("settings.restrictions.SaveQuitLocation", false);
        isForceSurvivalModeEnabled = configFile.getBoolean("settings.GameMode.ForceSurvivalMode", false);
        isResetInventoryIfCreative = configFile.getBoolean("settings.GameMode.ResetInventotyIfCreative",false);
        getmaxRegPerIp = configFile.getInt("settings.restrictions.maxRegPerIp",1);
        getPasswordHash = getPasswordHash();
        getUnloggedinGroup = configFile.getString("settings.security.unLoggedinGroup","unLoggedInGroup");
        getDataSource = getDataSource();
        isCachingEnabled = configFile.getBoolean("DataSource.caching",true);
        getMySQLHost = configFile.getString("DataSource.mySQLHost","127.0.0.1");
        getMySQLPort = configFile.getString("DataSource.mySQLPort","3306");
        getMySQLUsername = configFile.getString("DataSource.mySQLUsername","authme");
        getMySQLPassword = configFile.getString("DataSource.mySQLPassword","12345");
        getMySQLDatabase = configFile.getString("DataSource.mySQLDatabase","authme");
        getMySQLTablename = configFile.getString("DataSource.mySQLTablename","authme");
        getMySQLColumnName = configFile.getString("DataSource.mySQLColumnName","username");
        getMySQLColumnPassword = configFile.getString("DataSource.mySQLColumnPassword","password");
        getMySQLColumnIp = configFile.getString("DataSource.mySQLColumnIp","ip");
        getMySQLColumnLastLogin = configFile.getString("DataSource.mySQLColumnLastLogin","lastlogin");
        getMySQLColumnSalt = configFile.getString("ExternalBoardOptions.mySQLColumnSalt");
        getMySQLColumnGroup = configFile.getString("ExternalBoardOptions.mySQLColumnGroup","");
        getNonActivatedGroup = configFile.getInt("ExternalBoardOptions.nonActivedUserGroup", -1);
        unRegisteredGroup = configFile.getString("GroupOptions.UnregisteredPlayerGroup","");
        getUnrestrictedName = configFile.getStringList("settings.unrestrictions.UnrestrictedName");
        getRegisteredGroup = configFile.getString("GroupOptions.RegisteredPlayerGroup","");
        getEnablePasswordVerifier = configFile.getBoolean("settings.restrictions.enablePasswordVerifier" , true);
        protectInventoryBeforeLogInEnabled = configFile.getBoolean("settings.restrictions.ProtectInventoryBeforeLogIn", true);
        passwordMaxLength = configFile.getInt("settings.security.passwordMaxLength", 20);
        isBackupActivated = configFile.getBoolean("BackupSystem.ActivateBackup",false);
        isBackupOnStart = configFile.getBoolean("BackupSystem.OnServerStart",false);
        isBackupOnStop = configFile.getBoolean("BackupSystem.OnServeStop",false);
        backupWindowsPath = configFile.getString("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\");
        enablePasspartu = configFile.getBoolean("Passpartu.enablePasspartu",false);


        saveDefaults();
            
            //System.out.println("[AuthMe debug] Config " + getEnablePasswordVerifier.toString());
            //System.out.println("[AuthMe debug] Config " + getEnablePasswordVerifier.toString());

 
   }
   
   public static void reloadConfigOptions(YamlConfiguration newConfig) {
       configFile = newConfig;
              
       //plugin.getLogger().info("RELoading Configuration File...");
        messagesLanguage = checkLang(configFile.getString("settings.messagesLanguage","en"));
        isPermissionCheckEnabled = configFile.getBoolean("permission.EnablePermissionCheck", false);
        isForcedRegistrationEnabled = configFile.getBoolean("settings.registration.force", true);
        isRegistrationEnabled = configFile.getBoolean("settings.registration.enabled", true);
        isTeleportToSpawnEnabled = configFile.getBoolean("settings.restrictions.teleportUnAuthedToSpawn",false);
        getWarnMessageInterval = configFile.getInt("settings.registration.messageInterval",5);
        isSessionsEnabled = configFile.getBoolean("settings.sessions.enabled",false);
        getSessionTimeout = configFile.getInt("settings.sessions.timeout",10);
        getRegistrationTimeout = configFile.getInt("settings.restrictions.timeout",30);
        isChatAllowed = configFile.getBoolean("settings.restrictions.allowChat",false);
        getMaxNickLength = configFile.getInt("settings.restrictions.maxNicknameLength",20);
        getMinNickLength = configFile.getInt("settings.restrictions.minNicknameLength",3);
        getPasswordMinLen = configFile.getInt("settings.security.minPasswordLength",4);
        getNickRegex = configFile.getString("settings.restrictions.allowedNicknameCharacters","[a-zA-Z0-9_?]*");
        isAllowRestrictedIp = configFile.getBoolean("settings.restrictions.AllowRestrictedUser",false);
        getRestrictedIp = configFile.getStringList("settings.restrictions.AllowedRestrictedUser");
        isMovementAllowed = configFile.getBoolean("settings.restrictions.allowMovement",false);
        getMovementRadius = configFile.getInt("settings.restrictions.allowedMovementRadius",100);
        getJoinPermissions = configFile.getStringList("GroupOptions.Permissions.PermissionsOnJoin");
        isKickOnWrongPasswordEnabled = configFile.getBoolean("settings.restrictions.kickOnWrongPassword",false);
        isKickNonRegisteredEnabled = configFile.getBoolean("settings.restrictions.kickNonRegistered",false);
        isForceSingleSessionEnabled = configFile.getBoolean("settings.restrictions.ForceSingleSession",true);
        isForceSpawnLocOnJoinEnabled = configFile.getBoolean("settings.restrictions.ForceSpawnLocOnJoinEnabled",false);     
        isSaveQuitLocationEnabled = configFile.getBoolean("settings.restrictions.SaveQuitLocation",false);
        isForceSurvivalModeEnabled = configFile.getBoolean("settings.GameMode.ForceSurvivalMode",false);
        isResetInventoryIfCreative = configFile.getBoolean("settings.GameMode.ResetInventotyIfCreative",false);
        getmaxRegPerIp = configFile.getInt("settings.restrictions.maxRegPerIp",1);
        getPasswordHash = getPasswordHash();
        getUnloggedinGroup = configFile.getString("settings.security.unLoggedinGroup","unLoggedInGroup");
        getDataSource = getDataSource();
        isCachingEnabled = configFile.getBoolean("DataSource.caching",true);
        getMySQLHost = configFile.getString("DataSource.mySQLHost","127.0.0.1");
        getMySQLPort = configFile.getString("DataSource.mySQLPort","3306");
        getMySQLUsername = configFile.getString("DataSource.mySQLUsername","authme");
        getMySQLPassword = configFile.getString("DataSource.mySQLPassword","12345");
        getMySQLDatabase = configFile.getString("DataSource.mySQLDatabase","authme");
        getMySQLTablename = configFile.getString("DataSource.mySQLTablename","authme");
        getMySQLColumnName = configFile.getString("DataSource.mySQLColumnName","username");
        getMySQLColumnPassword = configFile.getString("DataSource.mySQLColumnPassword","password");
        getMySQLColumnIp = configFile.getString("DataSource.mySQLColumnIp","ip");
        getMySQLColumnLastLogin = configFile.getString("DataSource.mySQLColumnLastLogin","lastlogin");
        getMySQLColumnSalt = configFile.getString("ExternalBoardOptions.mySQLColumnSalt","");
        getMySQLColumnGroup = configFile.getString("ExternalBoardOptions.mySQLColumnGroup","");
        getNonActivatedGroup = configFile.getInt("ExternalBoardOptions.nonActivedUserGroup", -1);
        unRegisteredGroup = configFile.getString("GroupOptions.UnregisteredPlayerGroup","");
        getUnrestrictedName = configFile.getStringList("settings.unrestrictions.UnrestrictedName");
        getRegisteredGroup = configFile.getString("GroupOptions.RegisteredPlayerGroup",""); 
        getEnablePasswordVerifier = configFile.getBoolean("settings.restrictions.enablePasswordVerifier" , true);
        protectInventoryBeforeLogInEnabled = configFile.getBoolean("settings.restrictions.ProtectInventoryBeforeLogIn", true);
        passwordMaxLength = configFile.getInt("settings.security.passwordMaxLength", 20);
        isBackupActivated = configFile.getBoolean("BackupSystem.ActivateBackup",false);
        isBackupOnStart = configFile.getBoolean("BackupSystem.OnServerStart",false);
        isBackupOnStop = configFile.getBoolean("BackupSystem.OnServeStop",false);     
        backupWindowsPath = configFile.getString("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\");
        enablePasspartu = configFile.getBoolean("Passpartu.enablePasspartu",false);
       
        //System.out.println(getMySQLDatabase);
        
         
   }
   
   public void mergeConfig() {
      
       //options().copyDefaults(false);
       //System.out.println("merging config?"+contains("settings.restrictions.ProtectInventoryBeforeLogIn")+checkDefaults());
       if(!contains("settings.restrictions.ProtectInventoryBeforeLogIn")) {
           set("settings.restrictions.enablePasswordVerifier", true);
           set("settings.restrictions.ProtectInventoryBeforeLogIn", true);
       } 
       
       if(!contains("settings.security.passwordMaxLength")) {
           set("settings.security.passwordMaxLength", 20);
       }
       
       if(!contains("BackupSystem.ActivateBackup")) {
           set("BackupSystem.ActivateBackup",false);
           set("BackupSystem.OnServerStart",false);
           set("BackupSystem.OnServeStop",false);
       }
       
       
       if(!contains("BackupSystem.MysqlWindowsPath")) {
           set("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\");
       }
       
       if(!contains("settings.messagesLanguage")) {
           set("settings.messagesLanguage","en");
       }
       
       if(!contains("passpartu.enablePasspartu")) {
           set("Passpartu.enablePasspartu",false);
       } else return;
       
       plugin.getLogger().info("Merge new Config Options..");
       plugin.saveConfig();
       
       return;
   }
   /** 
    * 
    * 
    * 
    */   
    private static HashAlgorithm getPasswordHash() {
        String key = "settings.security.passwordHash";

        try {
            return PasswordSecurity.HashAlgorithm.valueOf(configFile.getString(key,"SHA256").toUpperCase());
        } catch (IllegalArgumentException ex) {
            ConsoleLogger.showError("Unknown Hash Algorithm; defaulting to SHA256");
            return PasswordSecurity.HashAlgorithm.SHA256;
        }
    }
    
   /** 
    * 
    * 
    * 
    */
    private static DataSourceType getDataSource() {
        String key = "DataSource.backend";

        try {
            return DataSource.DataSourceType.valueOf(configFile.getString(key).toUpperCase());
        } catch (IllegalArgumentException ex) {
            ConsoleLogger.showError("Unknown database backend; defaulting to file database");
            return DataSource.DataSourceType.FILE;
        }
    }

    /**
     * Config option for setting and check restricted user by
     * username;ip , return false if ip and name doesnt amtch with
     * player that join the server, so player has a restricted access
    */   
    public static Boolean getRestrictedIp(String name, String ip) {
                 
              Iterator<String> iter = getRestrictedIp.iterator();
                while (iter.hasNext()) {
                   String[] args =  iter.next().split(";");
                  //System.out.println("name restricted "+args[0]+"name 2:"+name+"ip"+args[1]+"ip2"+ip);
                   if(args[0].equalsIgnoreCase(name) ) {
                           if(args[1].equalsIgnoreCase(ip)) {
                       //System.out.println("name restricted "+args[0]+"name 2:"+name+"ip"+args[1]+"ip2"+ip);
                           return true;
                            } else return false;
                        } 
                }
            return true;
    }

    
    /**
     * Loads the configuration from disk
     *
     * @return True if loaded successfully
     */
    public final boolean load() {
        try {
            load(file);
            return true;
        } catch (Exception ex) {
            return false;
        }
    }
    
    public final void reload() {
        load();
        loadDefaults(file.getName());
    }

    /**
     * Saves the configuration to disk
     *
     * @return True if saved successfully
     */
    public final boolean save() {
        try {
            save(file);
            return true;
        } catch (Exception ex) {
            return false;
        }
    }

    /**
     * Simple function for if the Configuration file exists
     *
     * @return True if configuration exists on disk
     */
    public final boolean exists() {
        return file.exists();
    }

    /**
     * Loads a file from the plugin jar and sets as default
     *
     * @param filename The filename to open
     */
    public final void loadDefaults(String filename) {
        InputStream stream = plugin.getResource(filename);
        if(stream == null) return;

        setDefaults(YamlConfiguration.loadConfiguration(stream));
    }

    /**
     * Saves current configuration (plus defaults) to disk.
     *
     * If defaults and configuration are empty, saves blank file.
     *
     * @return True if saved successfully
     */
    public final boolean saveDefaults() {
        options().copyDefaults(true);
        options().copyHeader(true);
        boolean success = save();
        options().copyDefaults(false);
        options().copyHeader(false);

        return success;
    }


    /**
     * Clears current configuration defaults
     */
    public final void clearDefaults() {
        setDefaults(new MemoryConfiguration());
    }

    /**
* Check loaded defaults against current configuration
*
* @return false When all defaults aren't present in config
*/
    public boolean checkDefaults() {
        if (getDefaults() == null) {
            return true;
        }
        return getKeys(true).containsAll(getDefaults().getKeys(true));
    }
 /*   
    public static Settings getInstance() {
        if (singleton == null) {
            singleton = new Settings();
        }
        return singleton;
    }
*/
    public static String checkLang(String lang) {
        for(messagesLang language: messagesLang.values()) {
            //System.out.println(language.toString());
            if(lang.toLowerCase().contains(language.toString())) {
                ConsoleLogger.info("Set Language: "+lang);
                return lang;
            }    
        }
        ConsoleLogger.info("Set Default Language: En ");
        return "en";
    }
    
    public enum messagesLang {
        en, de, br, cz
    } 
}
 public class TimeoutTask implements Runnable {

    private JavaPlugin plugin;
    private String name;
    private Messages m = Messages.getInstance();
    private Utils utils = Utils.getInstance();
    private FileCache playerCache = new FileCache();

    public TimeoutTask(JavaPlugin plugin, String name) {
        this.plugin = plugin;
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public void run() {
        if (PlayerCache.getInstance().isAuthenticated(name)) {
            return;
        }

        for (Player player : plugin.getServer().getOnlinePlayers()) {
            if (player.getName().toLowerCase().equals(name)) {
                if (LimboCache.getInstance().hasLimboPlayer(name)) {
                    LimboPlayer inv = LimboCache.getInstance().getLimboPlayer(name);
                    player.getServer().getScheduler().cancelTask(inv.getTimeoutTaskId());
                    /*
                    player.getInventory().setArmorContents(inv.getArmour());
                    player.getInventory().setContents(inv.getInventory());
                    utils.addNormal(player, inv.getGroup());
                    player.setOp(inv.getOperator());
                    //System.out.println("debug timout group reset "+inv.getGroup());
                    LimboCache.getInstance().deleteLimboPlayer(name); */
                    if(playerCache.doesCacheExist(name)) {
                        playerCache.removeCache(name);
                    }   
                } 

                player.kickPlayer(m._("timeout"));
                break;
            }
        }
    }
}

import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitScheduler;
import uk.org.whoami.authme.Utils;
import uk.org.whoami.authme.ConsoleLogger;
import uk.org.whoami.authme.cache.auth.PlayerAuth;
import uk.org.whoami.authme.cache.auth.PlayerCache;
import uk.org.whoami.authme.cache.backup.DataFileCache;
import uk.org.whoami.authme.cache.backup.FileCache;
import uk.org.whoami.authme.cache.limbo.LimboCache;
import uk.org.whoami.authme.datasource.DataSource;
import uk.org.whoami.authme.gui.screens.LoginScreen;
import uk.org.whoami.authme.settings.Messages;
import uk.org.whoami.authme.settings.Settings;
import uk.org.whoami.authme.task.MessageTask;
import uk.org.whoami.authme.task.TimeoutTask;

/*
 * Copyright 2011 Sebastian Köhler <sebkoehler@whoami.org.uk>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package uk.org.whoami.authme.commands;



public class LogoutCommand implements CommandExecutor {

    private Messages m = Messages.getInstance();
    //private Settings settings = Settings.getInstance();
    private JavaPlugin plugin;
    private DataSource database;
    private Utils utils = Utils.getInstance();
    private FileCache playerBackup = new FileCache();
    
    public LogoutCommand(JavaPlugin plugin, DataSource database) {
        this.plugin = plugin;
        this.database = database;
    }

    @Override
    public boolean onCommand(CommandSender sender, Command cmnd, String label, String[] args) {
        if (!(sender instanceof Player)) {
            return true;
        }

        if (!sender.hasPermission("authme." + label.toLowerCase())) {
            sender.sendMessage(m._("no_perm"));
            return true;
        }

        Player player = (Player) sender;
        String name = player.getName().toLowerCase();

        if (!PlayerCache.getInstance().isAuthenticated(name)) {
            player.sendMessage(m._("not_logged_in"));
            return true;
        }

        //clear session

        PlayerAuth auth = PlayerCache.getInstance().getAuth(name);
