<commit_before>package com.gamingmesh.jobs.dao;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.entity.Player;

import com.gamingmesh.jobs.Jobs;
import com.gamingmesh.jobs.container.ArchivedJobs;
import com.gamingmesh.jobs.container.BlockProtection;
import com.gamingmesh.jobs.container.Convert;
import com.gamingmesh.jobs.container.CurrencyType;
import com.gamingmesh.jobs.container.DBAction;
import com.gamingmesh.jobs.container.ExploreChunk;
import com.gamingmesh.jobs.container.ExploreRegion;
import com.gamingmesh.jobs.container.Job;
import com.gamingmesh.jobs.container.JobProgression;
import com.gamingmesh.jobs.container.JobsPlayer;
import com.gamingmesh.jobs.container.JobsWorld;
import com.gamingmesh.jobs.container.Log;
import com.gamingmesh.jobs.container.LogAmounts;
import com.gamingmesh.jobs.container.PlayerInfo;
import com.gamingmesh.jobs.container.PlayerPoints;
import com.gamingmesh.jobs.container.TopList;
import com.gamingmesh.jobs.dao.JobsManager.DataBaseType;
import com.gamingmesh.jobs.economy.PaymentData;
import com.gamingmesh.jobs.stuff.TimeManage;
import com.gamingmesh.jobs.stuff.Util;

public abstract class JobsDAO {

    private JobsConnectionPool pool;
    private static String prefix;
    private Jobs plugin;

    private static DataBaseType dbType = DataBaseType.SqLite;

    // Not in use currently
    public enum TablesFieldsType {
	decimal, number, text, varchar, stringList, stringLongMap, stringIntMap, locationMap, state, location, longNumber;
    }

    public enum worldsTableFields implements JobsTableInterface {
	name("varchar(36)", true);

	private String type;

	private boolean unique = false;

	worldsTableFields(String type) {
	    this(type, false);
	}

	worldsTableFields(String type, boolean unique) {
	    this.type = type;
	    this.unique = unique;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return unique;
	}
    }

    public enum jobsNameTableFields implements JobsTableInterface {
	name("varchar(36)", true);

	private String type;

	private boolean unique = false;

	jobsNameTableFields(String type) {
	    this(type, false);
	}

	jobsNameTableFields(String type, boolean unique) {
	    this.type = type;
	    this.unique = unique;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return unique;
	}
    }

    public enum UserTableFields implements JobsTableInterface {
	player_uuid("varchar(36)"),
	username("text"),
	seen("bigint"),
	donequests("int"),
	quests("text");

	private String type;

	UserTableFields(String type) {
	    this.type = type;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum JobsTableFields implements JobsTableInterface {
	userid("int"),
	job("text"),
	experience("double"),
	level("int"),
	jobid("int");

	private String type;

	JobsTableFields(String type) {
	    this.type = type;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum ArchiveTableFields implements JobsTableInterface {
	userid("int"),
	job("text"),
	experience("int"),
	level("int"),
	left("bigint"),
	jobid("int");

	private String type;

	ArchiveTableFields(String type) {
	    this.type = type;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum BlockTableFields implements JobsTableInterface {
	world("varchar(36)"),
	x("int"),
	y("int"),
	z("int"),
	recorded("bigint"),
	resets("bigint"),
	worldid("int");

	private String type;

	BlockTableFields(String type) {
	    this.type = type;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum LimitTableFields implements JobsTableInterface {
	userid("int"),
	type("varchar(36)"),
	collected("double"),
	started("bigint"),
	typeid("int");

	private String ttype;

	LimitTableFields(String type) {
	    this.ttype = type;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return ttype;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum LogTableFields implements JobsTableInterface {
	userid("int"),
	time("bigint"),
	action("varchar(20)"),
	itemname("text"),
	count("int"),
	money("double"),
	exp("double"),
	points("double");

	private String type;

	LogTableFields(String type) {
	    this.type = type;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum PointsTableFields implements JobsTableInterface {
	userid("int"),
	totalpoints("double"),
	currentpoints("double");

	private String type;

	PointsTableFields(String type) {
	    this.type = type;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum ExploreDataTableFields implements JobsTableInterface {
	worldname("varchar(64)"),
	chunkX("int"),
	chunkZ("int"),
	playerNames("text"),
	worldid("int");

	private String type;

	ExploreDataTableFields(String type) {
	    this.type = type;

	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum DBTables {
	JobNameTable("jobNames",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", jobsNameTableFields.class),
	WorldTable("worlds",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", worldsTableFields.class),
	UsersTable("users",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", UserTableFields.class),
	JobsTable("jobs",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", JobsTableFields.class),
	ArchiveTable("archive",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", ArchiveTableFields.class),
	BlocksTable("blocks",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", BlockTableFields.class),
	LimitsTable("limits",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", LimitTableFields.class),
	LogTable("log",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", LogTableFields.class),
	ExploreDataTable("exploreData",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", ExploreDataTableFields.class),
	PointsTable("points",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", PointsTableFields.class);

	private String mySQL;
	private String sQlite;
	private String tableName;
	private JobsTableInterface[] c;

	DBTables(String tableName, String MySQL, String SQlite, Class<?> cc) {
	    this.tableName = tableName;
	    this.mySQL = MySQL;
	    this.sQlite = SQlite;
	    this.c = (JobsTableInterface[]) cc.getEnumConstants();
	}

	private String getQR() {
	    switch (dbType) {
	    case MySQL:
		return this.mySQL.replace("[tableName]", prefix + this.tableName);
	    case SqLite:
		return this.sQlite.replace("[tableName]", this.tableName);
	    default:
		break;
	    }
	    return "";
	}

	public String getQuery() {
	    String rp = "";
	    List<JobsTableInterface> uniques = new ArrayList<JobsTableInterface>();
	    for (JobsTableInterface one : this.getInterface()) {
		if (one.isUnique()) {
		    uniques.add(one);
		}

		rp += " , `" + one.getCollumn() + "` " + one.getType();
	    }

	    String unique = "";

	    for (JobsTableInterface one : uniques) {
		if (!unique.isEmpty()) {
		    unique += " ,";
		}
		unique += "`" + one.getCollumn() + "`";
	    }

	    if (!unique.isEmpty()) {
		switch (dbType) {
		case MySQL:
		    unique = " , UNIQUE KEY template_" + tableName + " (" + unique + ")";
		    break;
		case SqLite:
		    unique = " , UNIQUE (" + unique + ")";
		    break;
		default:
		    break;
		}
	    }

	    return getQR().replace("[fields]", rp + unique);
	}

	public JobsTableInterface[] getInterface() {
	    return this.c;
	}

	public String getTableName() {
	    return prefix + tableName;
	}
    }

    protected JobsDAO(Jobs plugin, String driverName, String url, String username, String password, String pr) {
	this.plugin = plugin;
	prefix = pr;
	try {
	    pool = new JobsConnectionPool(driverName, url, username, password);
	} catch (Exception e) {
	    e.printStackTrace();
	}
    }

    public final synchronized void setUp() throws SQLException {
	if (getConnection() == null)
	    return;

	vacuum();
	setupConfig();

	try {
	    for (DBTables one : DBTables.values()) {
		createDefaultTable(one);
	    }
	    checkDefaultCollumns();
	} finally {
	}
    }

    protected abstract void setupConfig() throws SQLException;

    protected abstract void checkUpdate() throws SQLException;

    public abstract Statement prepareStatement(String query) throws SQLException;

    public abstract boolean createTable(String query) throws SQLException;

    public abstract boolean isTable(String table);

    public abstract boolean isCollumn(String table, String collumn);

    public abstract boolean truncate(String table);

    public abstract boolean addCollumn(String table, String collumn, String type);

    public abstract boolean drop(String table);

    public boolean isConnected() {
	try {
	    return pool != null && pool.getConnection() != null && !pool.getConnection().isClosed();
	} catch (SQLException e) {
	    return false;
	}
    }

    public void setAutoCommit(boolean state) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	try {
	    conn.setAutoCommit(state);
	} catch (SQLException e) {
	    e.printStackTrace();
	}
    }

    public void commit() {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;

	try {
	    conn.commit();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
    }

    private boolean createDefaultTable(DBTables table) {
	if (this.isTable(table.getTableName()))
	    return true;
	try {
	    this.createTable(table.getQuery());
	    return true;
	} catch (SQLException e) {
	    e.printStackTrace();
	}
	return false;
    }

    private boolean checkDefaultCollumns() {
	for (DBTables one : DBTables.values()) {
	    for (JobsTableInterface oneT : one.getInterface()) {
		if (this.isCollumn(one.getTableName(), oneT.getCollumn()))
		    continue;
		this.addCollumn(one.getTableName(), oneT.getCollumn(), oneT.getType());
	    }
	}

	return true;
    }

    public void truncateAllTables() {
	for (DBTables one : DBTables.values()) {
	    this.truncate(one.getTableName());
	}
    }

    public DataBaseType getDbType() {
	return dbType;
    }

    public void setDbType(DataBaseType dabType) {
	dbType = dabType;
    }

    /**
     * Gets the database prefix
     * @return the prefix
     */
    protected String getPrefix() {
	return prefix;
    }

    public List<JobsDAOData> getAllJobs(OfflinePlayer player) {
	return getAllJobs(player.getName(), player.getUniqueId());
    }

    /**
     * Get all jobs the player is part of.
     * @param playerUUID - the player being searched for
     * @return list of all of the names of the jobs the players are part of.
     */

    public List<JobsDAOData> getAllJobs(String playerName, UUID uuid) {

	int id = -1;
	PlayerInfo userData = null;

	if (Jobs.getGCManager().MultiServerCompatability())
	    userData = loadPlayerData(uuid);
	else
	    userData = Jobs.getPlayerManager().getPlayerInfo(uuid);

	ArrayList<JobsDAOData> jobs = new ArrayList<>();

	if (userData == null) {
	    recordNewPlayer(playerName, uuid);
	    return jobs;
	}
	id = userData.getID();

	JobsConnection conn = getConnection();
	if (conn == null)
	    return jobs;

	PreparedStatement prest = null;
	ResultSet res = null;
	try {
	    prest = conn.prepareStatement("SELECT * FROM `" + getJobsTableName() + "` WHERE `" + JobsTableFields.userid.getCollumn() + "` = ?;");
	    prest.setInt(1, id);
	    res = prest.executeQuery();
	    while (res.next()) {
		int jobId = res.getInt(JobsTableFields.jobid.getCollumn());
		if (jobId == 0) {
		    jobs.add(new JobsDAOData(res.getString(JobsTableFields.job.getCollumn()), res.getInt(JobsTableFields.level.getCollumn()), res.getDouble(JobsTableFields.experience.getCollumn())));
		} else {
		    Job job = Jobs.getJob(jobId);
		    if (job != null)
		    jobs.add(new JobsDAOData(job.getName(), res.getInt(JobsTableFields.level.getCollumn()), res.getDouble(JobsTableFields.experience.getCollumn())));
		}
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(res);
	    close(prest);
	}
	return jobs;
    }

    public HashMap<Integer, List<JobsDAOData>> getAllJobs() {
	HashMap<Integer, List<JobsDAOData>> map = new HashMap<>();
	JobsConnection conn = getConnection();
	if (conn == null)
	    return map;
	PreparedStatement prest = null;
	ResultSet res = null;
	try {
	    prest = conn.prepareStatement("SELECT * FROM `" + getJobsTableName() + "`;");
	    res = prest.executeQuery();
	    while (res.next()) {
		int id = res.getInt(JobsTableFields.userid.getCollumn());
		List<JobsDAOData> ls = map.get(id);
		if (ls == null)
		    ls = new ArrayList<>();

		int jobId = res.getInt(JobsTableFields.jobid.getCollumn());
		if (jobId == 0) {
		    ls.add(new JobsDAOData(res.getString(JobsTableFields.job.getCollumn()), res.getInt(JobsTableFields.level.getCollumn()), res.getDouble(JobsTableFields.experience.getCollumn())));
		    converted = false;
		} else {
		    // This should be removed when we switch over to id only method
		    if (converted)
			if (res.getString(JobsTableFields.job.getCollumn()) == null || res.getString(JobsTableFields.job.getCollumn()).isEmpty())
			    converted = false;

		    Job job = Jobs.getJob(jobId);
		    if (job != null)
			ls.add(new JobsDAOData(job.getName(), res.getInt(JobsTableFields.level.getCollumn()), res.getDouble(JobsTableFields.experience.getCollumn())));
		}

		map.put(id, ls);
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(res);
	    close(prest);
	}
	return map;
    }

    public HashMap<Integer, PlayerPoints> getAllPoints() {
	HashMap<Integer, PlayerPoints> map = new HashMap<>();
	JobsConnection conn = getConnection();
	if (conn == null)
	    return map;
	PreparedStatement prest = null;
	ResultSet res = null;
	try {
	    prest = conn.prepareStatement("SELECT * FROM `" + DBTables.PointsTable.getTableName() + "`;");
	    res = prest.executeQuery();
	    while (res.next()) {
		map.put(res.getInt(PointsTableFields.userid.getCollumn()), new PlayerPoints(res.getDouble(PointsTableFields.currentpoints.getCollumn()), res.getDouble(PointsTableFields.totalpoints
		    .getCollumn())));
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(res);
	    close(prest);
	}
	return map;
    }

    public HashMap<Integer, ArchivedJobs> getAllArchivedJobs() {
	HashMap<Integer, ArchivedJobs> map = new HashMap<>();
	JobsConnection conn = getConnection();
	if (conn == null)
	    return map;
	PreparedStatement prest = null;
	ResultSet res = null;
	try {
	    prest = conn.prepareStatement("SELECT * FROM `" + DBTables.ArchiveTable.getTableName() + "`;");
	    res = prest.executeQuery();
	    while (res.next()) {

		int id = res.getInt(ArchiveTableFields.userid.getCollumn());
		String jobName = res.getString(ArchiveTableFields.job.getCollumn());
		Double exp = res.getDouble(ArchiveTableFields.experience.getCollumn());
		int lvl = res.getInt(ArchiveTableFields.level.getCollumn());
		Long left = res.getLong(ArchiveTableFields.left.getCollumn());
		int jobid = res.getInt(ArchiveTableFields.jobid.getCollumn());

		Job job = null;
		if (jobid != 0) {
		    job = Jobs.getJob(jobid);
		} else {
		    job = Jobs.getJob(jobName);
		    converted = false;
		}

		if (job == null)
		    continue;

		ArchivedJobs m = map.get(id);
		if (m == null)
		    m = new ArchivedJobs();
		JobProgression jp = new JobProgression(job, null, lvl, exp);
		if (left != 0L)
		    jp.setLeftOn(left);
		m.addArchivedJob(jp);
		map.put(id, m);
	    }
	} catch (Exception e) {
	    close(res);
	    close(prest);
	} finally {
	    close(res);
	    close(prest);
	}
	return map;
    }

    public HashMap<Integer, HashMap<String, Log>> getAllLogs() {
	HashMap<Integer, HashMap<String, Log>> map = new HashMap<>();
	JobsConnection conn = getConnection();
	if (conn == null)
	    return map;
	PreparedStatement prest = null;
	ResultSet res = null;
	try {
	    int time = TimeManage.timeInInt();
	    prest = conn.prepareStatement("SELECT * FROM `" + DBTables.LogTable.getTableName() + "` WHERE `" + LogTableFields.time.getCollumn() + "` = ? ;");
	    prest.setInt(1, time);
	    res = prest.executeQuery();
	    while (res.next()) {
		int id = res.getInt(LogTableFields.userid.getCollumn());

		HashMap<String, Log> m = map.get(id);
		if (m == null)
		    m = new HashMap<>();
		String action = res.getString(LogTableFields.action.getCollumn());
		Log log = m.get(action);

		if (log == null)
		    log = new Log(action);

		HashMap<CurrencyType, Double> amounts = new HashMap<>();
		amounts.put(CurrencyType.MONEY, res.getDouble(LogTableFields.money.getCollumn()));
		amounts.put(CurrencyType.EXP, res.getDouble(LogTableFields.exp.getCollumn()));
		amounts.put(CurrencyType.POINTS, res.getDouble(LogTableFields.points.getCollumn()));

		log.add(res.getString(LogTableFields.itemname.getCollumn()), res.getInt(LogTableFields.count.getCollumn()), amounts);

		m.put(action, log);
		map.put(id, m);

//		Jobs.getLoging().loadToLog(player, res.getString("action"), res.getString("itemname"), res.getInt("count"), res.getDouble("money"), res.getDouble("exp"));
	    }
	} catch (Exception e) {
	    close(res);
	    close(prest);
	} finally {
	    close(res);
	    close(prest);
	}
	return map;
    }

    private HashMap<Integer, ArrayList<JobsDAOData>> map = new HashMap<>();

    public List<JobsDAOData> getAllJobs(PlayerInfo pInfo) {
	return map.getOrDefault(pInfo.getID(), new ArrayList<JobsDAOData>());
    }

    public void cleanUsers() {
	if (!Jobs.getGCManager().DBCleaningUsersUse)
	    return;
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	long mark = System.currentTimeMillis() - (Jobs.getGCManager().DBCleaningUsersDays * 24 * 60 * 60 * 1000);
	PreparedStatement prest = null;
	try {
	    prest = conn.prepareStatement("DELETE FROM `" + DBTables.UsersTable.getTableName() + "` WHERE `" + UserTableFields.seen.getCollumn() + "` < ?;");
	    prest.setLong(1, mark);
	    prest.execute();
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(prest);
	}
    }

    public void cleanJobs() {
	if (!Jobs.getGCManager().DBCleaningJobsUse)
	    return;
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	PreparedStatement prest = null;
	try {
	    prest = conn.prepareStatement("DELETE FROM `" + getJobsTableName() + "` WHERE `" + JobsTableFields.level.getCollumn() + "` <= ?;");
	    prest.setInt(1, Jobs.getGCManager().DBCleaningJobsLvl);
	    prest.execute();
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(prest);
	}
    }

    public void recordNewPlayer(Player player) {
	recordNewPlayer((OfflinePlayer) player);
    }

    public void recordNewPlayer(OfflinePlayer player) {
	recordNewPlayer(player.getName(), player.getUniqueId());
    }

    public void recordNewPlayer(String playerName, UUID uuid) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	PreparedStatement prestt = null;
	ResultSet res2 = null;
	try {
	    prestt = conn.prepareStatement("INSERT INTO `" + DBTables.UsersTable.getTableName() + "` (`" + UserTableFields.player_uuid.getCollumn()
		+ "`, `" + UserTableFields.username.getCollumn()
		+ "`, `" + UserTableFields.seen.getCollumn()
		+ "`, `" + UserTableFields.donequests.getCollumn()
		+ "`) VALUES (?, ?, ?, ?);",
		Statement.RETURN_GENERATED_KEYS);
	    prestt.setString(1, uuid.toString());
	    prestt.setString(2, playerName);
	    prestt.setLong(3, System.currentTimeMillis());
	    prestt.setInt(4, 0);
	    prestt.executeUpdate();

	    res2 = prestt.getGeneratedKeys();
	    int id = 0;
	    if (res2.next())
		id = res2.getInt(1);

	    Jobs.getPlayerManager().addPlayerToMap(new PlayerInfo(playerName, id, uuid, System.currentTimeMillis(), 0));
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(prestt);
	    close(res2);
	}
    }

    int convertSchedId = -1;
    boolean converted = true;

    public void recordNewWorld(String worldName) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	PreparedStatement prestt = null;
	ResultSet res2 = null;
	try {
	    prestt = conn.prepareStatement("INSERT INTO `" + DBTables.WorldTable.getTableName() + "` (`" + worldsTableFields.name.getCollumn() + "`) VALUES (?);",
		Statement.RETURN_GENERATED_KEYS);
	    prestt.setString(1, worldName);
	    prestt.executeUpdate();

	    res2 = prestt.getGeneratedKeys();
	    int id = 0;
	    if (res2.next())
		id = res2.getInt(1);

	    Util.addJobsWorld(new JobsWorld(worldName, id));

	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(prestt);
	    close(res2);
	}
    }

    public synchronized void loadAllJobsWorlds() {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;

	PreparedStatement prest = null;
	ResultSet res = null;
	try {
	    prest = conn.prepareStatement("SELECT * FROM `" + DBTables.WorldTable.getTableName() + "`;");
	    res = prest.executeQuery();
	    while (res.next()) {
		int id = res.getInt("id");
		String name = res.getString(worldsTableFields.name.getCollumn());
		Util.addJobsWorld(new JobsWorld(name, id));
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(res);
	    close(prest);
	}

	for (World one : Bukkit.getWorlds()) {
	    if (Util.getJobsWorld(one.getName()) != null)
		continue;
	    this.recordNewWorld(one.getName());
	}

	return;
    }

    public void triggerTableIdUpdate() {
	// Lets convert old fields
	if (convertSchedId > 0)
	    Bukkit.getServer().getScheduler().cancelTask(convertSchedId);
	if (!converted) {
	    convertSchedId = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
		@Override
		public void run() {
		    Jobs.consoleMsg("&6[Jobs] Converting to new database format");
		    convertID();
		    Jobs.consoleMsg("&6[Jobs] Converted to new database format");
		    converted = true;
		    return;
		}
	    }, 60L);
	}
    }

    private void convertID() {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	PreparedStatement exploreStatement = null;
	try {
	    exploreStatement = conn.prepareStatement("UPDATE `" + DBTables.ExploreDataTable.getTableName() + "` SET `" + ExploreDataTableFields.worldid.getCollumn() + "` = ? WHERE `"
		+ ExploreDataTableFields.worldname.getCollumn() + "` = ?;");
	    for (Entry<String, JobsWorld> jobsWorld : Util.getJobsWorlds().entrySet()) {
		exploreStatement.setInt(1, jobsWorld.getValue().getId());
		exploreStatement.setString(2, jobsWorld.getValue().getName());
		exploreStatement.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(exploreStatement);
	}

	PreparedStatement exploreStatementBack = null;
	try {
	    exploreStatementBack = conn.prepareStatement("UPDATE `" + DBTables.ExploreDataTable.getTableName() + "` SET `" + ExploreDataTableFields.worldname.getCollumn() + "` = ? WHERE `"
		+ ExploreDataTableFields.worldid.getCollumn() + "` = ?;");
	    for (Entry<String, JobsWorld> jobsWorld : Util.getJobsWorlds().entrySet()) {
		exploreStatementBack.setString(1, jobsWorld.getValue().getName());
		exploreStatementBack.setInt(2, jobsWorld.getValue().getId());
		exploreStatementBack.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(exploreStatementBack);
	}

	PreparedStatement bpStatement = null;
	try {
	    bpStatement = conn.prepareStatement("UPDATE `" + DBTables.BlocksTable.getTableName() + "` SET `" + BlockTableFields.worldid.getCollumn() + "` = ?  WHERE `" + BlockTableFields.world
		.getCollumn() + "` = ?;");
	    for (Entry<String, JobsWorld> jobsWorld : Util.getJobsWorlds().entrySet()) {
		bpStatement.setInt(1, jobsWorld.getValue().getId());
		bpStatement.setString(2, jobsWorld.getValue().getName());
		bpStatement.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(bpStatement);
	}

	PreparedStatement bpStatementback = null;
	try {
	    bpStatementback = conn.prepareStatement("UPDATE `" + DBTables.BlocksTable.getTableName() + "` SET `" + BlockTableFields.world.getCollumn() + "` = ?  WHERE `" + BlockTableFields.worldid
		.getCollumn() + "` = ?;");
	    for (Entry<String, JobsWorld> jobsWorld : Util.getJobsWorlds().entrySet()) {
		bpStatementback.setString(1, jobsWorld.getValue().getName());
		bpStatementback.setInt(2, jobsWorld.getValue().getId());
		bpStatementback.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(bpStatementback);
	}

	PreparedStatement archiveStatement = null;
	try {
	    archiveStatement = conn.prepareStatement("UPDATE `" + DBTables.ArchiveTable.getTableName() + "` SET `" + ArchiveTableFields.jobid.getCollumn() + "` = ? WHERE `" + ArchiveTableFields.job
		.getCollumn() + "` = ?;");
	    for (Job job : Jobs.getJobs()) {
		archiveStatement.setInt(1, job.getId());
		archiveStatement.setString(2, job.getName());
		archiveStatement.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(archiveStatement);
	}
	PreparedStatement archiveStatementBack = null;
	try {
	    archiveStatementBack = conn.prepareStatement("UPDATE `" + DBTables.ArchiveTable.getTableName() + "` SET `" + ArchiveTableFields.job.getCollumn() + "` = ? WHERE `" + ArchiveTableFields.jobid
		.getCollumn() + "` = ?;");
	    for (Job job : Jobs.getJobs()) {
		archiveStatementBack.setString(1, job.getName());
		archiveStatementBack.setInt(2, job.getId());
		archiveStatementBack.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(archiveStatementBack);
	}

	PreparedStatement usersStatement = null;
	try {
	    usersStatement = conn.prepareStatement("UPDATE `" + getJobsTableName() + "` SET `" + JobsTableFields.jobid.getCollumn() + "` = ? WHERE `" + JobsTableFields.job.getCollumn() + "` = ?;");
	    for (Job job : Jobs.getJobs()) {
		usersStatement.setInt(1, job.getId());
		usersStatement.setString(2, job.getName());
		usersStatement.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(usersStatement);
	}
	PreparedStatement usersStatementBack = null;
	try {
	    usersStatementBack = conn.prepareStatement("UPDATE `" + getJobsTableName() + "` SET `" + JobsTableFields.job.getCollumn() + "` = ? WHERE `" + JobsTableFields.jobid.getCollumn() + "` = ?;");
	    for (Job job : Jobs.getJobs()) {
		usersStatementBack.setString(1, job.getName());
		usersStatementBack.setInt(2, job.getId());
		usersStatementBack.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(usersStatementBack);
	}

	PreparedStatement limitsStatement = null;
	try {
	    limitsStatement = conn.prepareStatement("UPDATE `" + DBTables.LimitsTable.getTableName() + "` SET `" + LimitTableFields.typeid.getCollumn() + "` = ? WHERE `" + LimitTableFields.type
		.getCollumn() + "` = ?;");
	    for (CurrencyType type : CurrencyType.values()) {
		limitsStatement.setInt(1, type.getId());
		limitsStatement.setString(2, type.getName());
		limitsStatement.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(limitsStatement);
	}

	PreparedStatement limitsStatementBack = null;
	try {
	    limitsStatementBack = conn.prepareStatement("UPDATE `" + DBTables.LimitsTable.getTableName() + "` SET `" + LimitTableFields.type.getCollumn() + "` = ? WHERE `" + LimitTableFields.typeid
		.getCollumn() + "` = ?;");
	    for (CurrencyType type : CurrencyType.values()) {
		limitsStatementBack.setString(1, type.getName());
		limitsStatementBack.setInt(2, type.getId());
		limitsStatementBack.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(limitsStatementBack);
	}
    }

    public void recordNewJobName(Job job) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	PreparedStatement prestt = null;
	ResultSet res2 = null;
	try {
	    prestt = conn.prepareStatement("INSERT INTO `" + DBTables.JobNameTable.getTableName() + "` (`" + jobsNameTableFields.name.getCollumn() + "`) VALUES (?);",
		Statement.RETURN_GENERATED_KEYS);
	    prestt.setString(1, job.getName());
	    prestt.executeUpdate();

	    res2 = prestt.getGeneratedKeys();
	    int id = 0;
	    if (res2.next())<commit_msg>Delete a column from jobNames before inserting to prevent errors<commit_after>package com.gamingmesh.jobs.dao;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.entity.Player;

import com.gamingmesh.jobs.Jobs;
import com.gamingmesh.jobs.container.ArchivedJobs;
import com.gamingmesh.jobs.container.BlockProtection;
import com.gamingmesh.jobs.container.Convert;
import com.gamingmesh.jobs.container.CurrencyType;
import com.gamingmesh.jobs.container.DBAction;
import com.gamingmesh.jobs.container.ExploreChunk;
import com.gamingmesh.jobs.container.ExploreRegion;
import com.gamingmesh.jobs.container.Job;
import com.gamingmesh.jobs.container.JobProgression;
import com.gamingmesh.jobs.container.JobsPlayer;
import com.gamingmesh.jobs.container.JobsWorld;
import com.gamingmesh.jobs.container.Log;
import com.gamingmesh.jobs.container.LogAmounts;
import com.gamingmesh.jobs.container.PlayerInfo;
import com.gamingmesh.jobs.container.PlayerPoints;
import com.gamingmesh.jobs.container.TopList;
import com.gamingmesh.jobs.dao.JobsManager.DataBaseType;
import com.gamingmesh.jobs.economy.PaymentData;
import com.gamingmesh.jobs.stuff.TimeManage;
import com.gamingmesh.jobs.stuff.Util;

public abstract class JobsDAO {

    private JobsConnectionPool pool;
    private static String prefix;
    private Jobs plugin;

    private static DataBaseType dbType = DataBaseType.SqLite;

    // Not in use currently
    public enum TablesFieldsType {
	decimal, number, text, varchar, stringList, stringLongMap, stringIntMap, locationMap, state, location, longNumber;
    }

    public enum worldsTableFields implements JobsTableInterface {
	name("varchar(36)", true);

	private String type;

	private boolean unique = false;

	worldsTableFields(String type) {
	    this(type, false);
	}

	worldsTableFields(String type, boolean unique) {
	    this.type = type;
	    this.unique = unique;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return unique;
	}
    }

    public enum jobsNameTableFields implements JobsTableInterface {
	name("varchar(36)", true);

	private String type;

	private boolean unique = false;

	jobsNameTableFields(String type) {
	    this(type, false);
	}

	jobsNameTableFields(String type, boolean unique) {
	    this.type = type;
	    this.unique = unique;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return unique;
	}
    }

    public enum UserTableFields implements JobsTableInterface {
	player_uuid("varchar(36)"),
	username("text"),
	seen("bigint"),
	donequests("int"),
	quests("text");

	private String type;

	UserTableFields(String type) {
	    this.type = type;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum JobsTableFields implements JobsTableInterface {
	userid("int"),
	job("text"),
	experience("double"),
	level("int"),
	jobid("int");

	private String type;

	JobsTableFields(String type) {
	    this.type = type;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum ArchiveTableFields implements JobsTableInterface {
	userid("int"),
	job("text"),
	experience("int"),
	level("int"),
	left("bigint"),
	jobid("int");

	private String type;

	ArchiveTableFields(String type) {
	    this.type = type;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum BlockTableFields implements JobsTableInterface {
	world("varchar(36)"),
	x("int"),
	y("int"),
	z("int"),
	recorded("bigint"),
	resets("bigint"),
	worldid("int");

	private String type;

	BlockTableFields(String type) {
	    this.type = type;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum LimitTableFields implements JobsTableInterface {
	userid("int"),
	type("varchar(36)"),
	collected("double"),
	started("bigint"),
	typeid("int");

	private String ttype;

	LimitTableFields(String type) {
	    this.ttype = type;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return ttype;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum LogTableFields implements JobsTableInterface {
	userid("int"),
	time("bigint"),
	action("varchar(20)"),
	itemname("text"),
	count("int"),
	money("double"),
	exp("double"),
	points("double");

	private String type;

	LogTableFields(String type) {
	    this.type = type;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum PointsTableFields implements JobsTableInterface {
	userid("int"),
	totalpoints("double"),
	currentpoints("double");

	private String type;

	PointsTableFields(String type) {
	    this.type = type;
	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum ExploreDataTableFields implements JobsTableInterface {
	worldname("varchar(64)"),
	chunkX("int"),
	chunkZ("int"),
	playerNames("text"),
	worldid("int");

	private String type;

	ExploreDataTableFields(String type) {
	    this.type = type;

	}

	@Override
	public String getCollumn() {
	    return this.name();
	}

	@Override
	public String getType() {
	    return type;
	}

	@Override
	public boolean isUnique() {
	    return false;
	}
    }

    public enum DBTables {
	JobNameTable("jobNames",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", jobsNameTableFields.class),
	WorldTable("worlds",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", worldsTableFields.class),
	UsersTable("users",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", UserTableFields.class),
	JobsTable("jobs",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", JobsTableFields.class),
	ArchiveTable("archive",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", ArchiveTableFields.class),
	BlocksTable("blocks",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", BlockTableFields.class),
	LimitsTable("limits",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", LimitTableFields.class),
	LogTable("log",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", LogTableFields.class),
	ExploreDataTable("exploreData",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", ExploreDataTableFields.class),
	PointsTable("points",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY[fields]);",
	    "CREATE TABLE IF NOT EXISTS `[tableName]` (`id` INTEGER PRIMARY KEY AUTOINCREMENT[fields]);", PointsTableFields.class);

	private String mySQL;
	private String sQlite;
	private String tableName;
	private JobsTableInterface[] c;

	DBTables(String tableName, String MySQL, String SQlite, Class<?> cc) {
	    this.tableName = tableName;
	    this.mySQL = MySQL;
	    this.sQlite = SQlite;
	    this.c = (JobsTableInterface[]) cc.getEnumConstants();
	}

	private String getQR() {
	    switch (dbType) {
	    case MySQL:
		return this.mySQL.replace("[tableName]", prefix + this.tableName);
	    case SqLite:
		return this.sQlite.replace("[tableName]", this.tableName);
	    default:
		break;
	    }
	    return "";
	}

	public String getQuery() {
	    String rp = "";
	    List<JobsTableInterface> uniques = new ArrayList<JobsTableInterface>();
	    for (JobsTableInterface one : this.getInterface()) {
		if (one.isUnique()) {
		    uniques.add(one);
		}

		rp += " , `" + one.getCollumn() + "` " + one.getType();
	    }

	    String unique = "";

	    for (JobsTableInterface one : uniques) {
		if (!unique.isEmpty()) {
		    unique += " ,";
		}
		unique += "`" + one.getCollumn() + "`";
	    }

	    if (!unique.isEmpty()) {
		switch (dbType) {
		case MySQL:
		    unique = " , UNIQUE KEY template_" + tableName + " (" + unique + ")";
		    break;
		case SqLite:
		    unique = " , UNIQUE (" + unique + ")";
		    break;
		default:
		    break;
		}
	    }

	    return getQR().replace("[fields]", rp + unique);
	}

	public JobsTableInterface[] getInterface() {
	    return this.c;
	}

	public String getTableName() {
	    return prefix + tableName;
	}
    }

    protected JobsDAO(Jobs plugin, String driverName, String url, String username, String password, String pr) {
	this.plugin = plugin;
	prefix = pr;
	try {
	    pool = new JobsConnectionPool(driverName, url, username, password);
	} catch (Exception e) {
	    e.printStackTrace();
	}
    }

    public final synchronized void setUp() throws SQLException {
	if (getConnection() == null)
	    return;

	vacuum();
	setupConfig();

	try {
	    for (DBTables one : DBTables.values()) {
		createDefaultTable(one);
	    }
	    checkDefaultCollumns();
	} finally {
	}
    }

    protected abstract void setupConfig() throws SQLException;

    protected abstract void checkUpdate() throws SQLException;

    public abstract Statement prepareStatement(String query) throws SQLException;

    public abstract boolean createTable(String query) throws SQLException;

    public abstract boolean isTable(String table);

    public abstract boolean isCollumn(String table, String collumn);

    public abstract boolean truncate(String table);

    public abstract boolean addCollumn(String table, String collumn, String type);

    public abstract boolean drop(String table);

    public boolean isConnected() {
	try {
	    return pool != null && pool.getConnection() != null && !pool.getConnection().isClosed();
	} catch (SQLException e) {
	    return false;
	}
    }

    public void setAutoCommit(boolean state) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	try {
	    conn.setAutoCommit(state);
	} catch (SQLException e) {
	    e.printStackTrace();
	}
    }

    public void commit() {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;

	try {
	    conn.commit();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
    }

    private boolean createDefaultTable(DBTables table) {
	if (this.isTable(table.getTableName()))
	    return true;
	try {
	    this.createTable(table.getQuery());
	    return true;
	} catch (SQLException e) {
	    e.printStackTrace();
	}
	return false;
    }

    private boolean checkDefaultCollumns() {
	for (DBTables one : DBTables.values()) {
	    for (JobsTableInterface oneT : one.getInterface()) {
		if (this.isCollumn(one.getTableName(), oneT.getCollumn()))
		    continue;
		this.addCollumn(one.getTableName(), oneT.getCollumn(), oneT.getType());
	    }
	}

	return true;
    }

    public void truncateAllTables() {
	for (DBTables one : DBTables.values()) {
	    this.truncate(one.getTableName());
	}
    }

    public DataBaseType getDbType() {
	return dbType;
    }

    public void setDbType(DataBaseType dabType) {
	dbType = dabType;
    }

    /**
     * Gets the database prefix
     * @return the prefix
     */
    protected String getPrefix() {
	return prefix;
    }

    public List<JobsDAOData> getAllJobs(OfflinePlayer player) {
	return getAllJobs(player.getName(), player.getUniqueId());
    }

    /**
     * Get all jobs the player is part of.
     * @param playerUUID - the player being searched for
     * @return list of all of the names of the jobs the players are part of.
     */

    public List<JobsDAOData> getAllJobs(String playerName, UUID uuid) {

	int id = -1;
	PlayerInfo userData = null;

	if (Jobs.getGCManager().MultiServerCompatability())
	    userData = loadPlayerData(uuid);
	else
	    userData = Jobs.getPlayerManager().getPlayerInfo(uuid);

	ArrayList<JobsDAOData> jobs = new ArrayList<>();

	if (userData == null) {
	    recordNewPlayer(playerName, uuid);
	    return jobs;
	}
	id = userData.getID();

	JobsConnection conn = getConnection();
	if (conn == null)
	    return jobs;

	PreparedStatement prest = null;
	ResultSet res = null;
	try {
	    prest = conn.prepareStatement("SELECT * FROM `" + getJobsTableName() + "` WHERE `" + JobsTableFields.userid.getCollumn() + "` = ?;");
	    prest.setInt(1, id);
	    res = prest.executeQuery();
	    while (res.next()) {
		int jobId = res.getInt(JobsTableFields.jobid.getCollumn());
		if (jobId == 0) {
		    jobs.add(new JobsDAOData(res.getString(JobsTableFields.job.getCollumn()), res.getInt(JobsTableFields.level.getCollumn()), res.getDouble(JobsTableFields.experience.getCollumn())));
		} else {
		    Job job = Jobs.getJob(jobId);
		    if (job != null)
		    jobs.add(new JobsDAOData(job.getName(), res.getInt(JobsTableFields.level.getCollumn()), res.getDouble(JobsTableFields.experience.getCollumn())));
		}
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(res);
	    close(prest);
	}
	return jobs;
    }

    public HashMap<Integer, List<JobsDAOData>> getAllJobs() {
	HashMap<Integer, List<JobsDAOData>> map = new HashMap<>();
	JobsConnection conn = getConnection();
	if (conn == null)
	    return map;
	PreparedStatement prest = null;
	ResultSet res = null;
	try {
	    prest = conn.prepareStatement("SELECT * FROM `" + getJobsTableName() + "`;");
	    res = prest.executeQuery();
	    while (res.next()) {
		int id = res.getInt(JobsTableFields.userid.getCollumn());
		List<JobsDAOData> ls = map.get(id);
		if (ls == null)
		    ls = new ArrayList<>();

		int jobId = res.getInt(JobsTableFields.jobid.getCollumn());
		if (jobId == 0) {
		    ls.add(new JobsDAOData(res.getString(JobsTableFields.job.getCollumn()), res.getInt(JobsTableFields.level.getCollumn()), res.getDouble(JobsTableFields.experience.getCollumn())));
		    converted = false;
		} else {
		    // This should be removed when we switch over to id only method
		    if (converted)
			if (res.getString(JobsTableFields.job.getCollumn()) == null || res.getString(JobsTableFields.job.getCollumn()).isEmpty())
			    converted = false;

		    Job job = Jobs.getJob(jobId);
		    if (job != null)
			ls.add(new JobsDAOData(job.getName(), res.getInt(JobsTableFields.level.getCollumn()), res.getDouble(JobsTableFields.experience.getCollumn())));
		}

		map.put(id, ls);
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(res);
	    close(prest);
	}
	return map;
    }

    public HashMap<Integer, PlayerPoints> getAllPoints() {
	HashMap<Integer, PlayerPoints> map = new HashMap<>();
	JobsConnection conn = getConnection();
	if (conn == null)
	    return map;
	PreparedStatement prest = null;
	ResultSet res = null;
	try {
	    prest = conn.prepareStatement("SELECT * FROM `" + DBTables.PointsTable.getTableName() + "`;");
	    res = prest.executeQuery();
	    while (res.next()) {
		map.put(res.getInt(PointsTableFields.userid.getCollumn()), new PlayerPoints(res.getDouble(PointsTableFields.currentpoints.getCollumn()), res.getDouble(PointsTableFields.totalpoints
		    .getCollumn())));
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(res);
	    close(prest);
	}
	return map;
    }

    public HashMap<Integer, ArchivedJobs> getAllArchivedJobs() {
	HashMap<Integer, ArchivedJobs> map = new HashMap<>();
	JobsConnection conn = getConnection();
	if (conn == null)
	    return map;
	PreparedStatement prest = null;
	ResultSet res = null;
	try {
	    prest = conn.prepareStatement("SELECT * FROM `" + DBTables.ArchiveTable.getTableName() + "`;");
	    res = prest.executeQuery();
	    while (res.next()) {

		int id = res.getInt(ArchiveTableFields.userid.getCollumn());
		String jobName = res.getString(ArchiveTableFields.job.getCollumn());
		Double exp = res.getDouble(ArchiveTableFields.experience.getCollumn());
		int lvl = res.getInt(ArchiveTableFields.level.getCollumn());
		Long left = res.getLong(ArchiveTableFields.left.getCollumn());
		int jobid = res.getInt(ArchiveTableFields.jobid.getCollumn());

		Job job = null;
		if (jobid != 0) {
		    job = Jobs.getJob(jobid);
		} else {
		    job = Jobs.getJob(jobName);
		    converted = false;
		}

		if (job == null)
		    continue;

		ArchivedJobs m = map.get(id);
		if (m == null)
		    m = new ArchivedJobs();
		JobProgression jp = new JobProgression(job, null, lvl, exp);
		if (left != 0L)
		    jp.setLeftOn(left);
		m.addArchivedJob(jp);
		map.put(id, m);
	    }
	} catch (Exception e) {
	    close(res);
	    close(prest);
	} finally {
	    close(res);
	    close(prest);
	}
	return map;
    }

    public HashMap<Integer, HashMap<String, Log>> getAllLogs() {
	HashMap<Integer, HashMap<String, Log>> map = new HashMap<>();
	JobsConnection conn = getConnection();
	if (conn == null)
	    return map;
	PreparedStatement prest = null;
	ResultSet res = null;
	try {
	    int time = TimeManage.timeInInt();
	    prest = conn.prepareStatement("SELECT * FROM `" + DBTables.LogTable.getTableName() + "` WHERE `" + LogTableFields.time.getCollumn() + "` = ? ;");
	    prest.setInt(1, time);
	    res = prest.executeQuery();
	    while (res.next()) {
		int id = res.getInt(LogTableFields.userid.getCollumn());

		HashMap<String, Log> m = map.get(id);
		if (m == null)
		    m = new HashMap<>();
		String action = res.getString(LogTableFields.action.getCollumn());
		Log log = m.get(action);

		if (log == null)
		    log = new Log(action);

		HashMap<CurrencyType, Double> amounts = new HashMap<>();
		amounts.put(CurrencyType.MONEY, res.getDouble(LogTableFields.money.getCollumn()));
		amounts.put(CurrencyType.EXP, res.getDouble(LogTableFields.exp.getCollumn()));
		amounts.put(CurrencyType.POINTS, res.getDouble(LogTableFields.points.getCollumn()));

		log.add(res.getString(LogTableFields.itemname.getCollumn()), res.getInt(LogTableFields.count.getCollumn()), amounts);

		m.put(action, log);
		map.put(id, m);

//		Jobs.getLoging().loadToLog(player, res.getString("action"), res.getString("itemname"), res.getInt("count"), res.getDouble("money"), res.getDouble("exp"));
	    }
	} catch (Exception e) {
	    close(res);
	    close(prest);
	} finally {
	    close(res);
	    close(prest);
	}
	return map;
    }

    private HashMap<Integer, ArrayList<JobsDAOData>> map = new HashMap<>();

    public List<JobsDAOData> getAllJobs(PlayerInfo pInfo) {
	return map.getOrDefault(pInfo.getID(), new ArrayList<JobsDAOData>());
    }

    public void cleanUsers() {
	if (!Jobs.getGCManager().DBCleaningUsersUse)
	    return;
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	long mark = System.currentTimeMillis() - (Jobs.getGCManager().DBCleaningUsersDays * 24 * 60 * 60 * 1000);
	PreparedStatement prest = null;
	try {
	    prest = conn.prepareStatement("DELETE FROM `" + DBTables.UsersTable.getTableName() + "` WHERE `" + UserTableFields.seen.getCollumn() + "` < ?;");
	    prest.setLong(1, mark);
	    prest.execute();
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(prest);
	}
    }

    public void cleanJobs() {
	if (!Jobs.getGCManager().DBCleaningJobsUse)
	    return;
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	PreparedStatement prest = null;
	try {
	    prest = conn.prepareStatement("DELETE FROM `" + getJobsTableName() + "` WHERE `" + JobsTableFields.level.getCollumn() + "` <= ?;");
	    prest.setInt(1, Jobs.getGCManager().DBCleaningJobsLvl);
	    prest.execute();
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(prest);
	}
    }

    public void recordNewPlayer(Player player) {
	recordNewPlayer((OfflinePlayer) player);
    }

    public void recordNewPlayer(OfflinePlayer player) {
	recordNewPlayer(player.getName(), player.getUniqueId());
    }

    public void recordNewPlayer(String playerName, UUID uuid) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	PreparedStatement prestt = null;
	ResultSet res2 = null;
	try {
	    prestt = conn.prepareStatement("INSERT INTO `" + DBTables.UsersTable.getTableName() + "` (`" + UserTableFields.player_uuid.getCollumn()
		+ "`, `" + UserTableFields.username.getCollumn()
		+ "`, `" + UserTableFields.seen.getCollumn()
		+ "`, `" + UserTableFields.donequests.getCollumn()
		+ "`) VALUES (?, ?, ?, ?);",
		Statement.RETURN_GENERATED_KEYS);
	    prestt.setString(1, uuid.toString());
	    prestt.setString(2, playerName);
	    prestt.setLong(3, System.currentTimeMillis());
	    prestt.setInt(4, 0);
	    prestt.executeUpdate();

	    res2 = prestt.getGeneratedKeys();
	    int id = 0;
	    if (res2.next())
		id = res2.getInt(1);

	    Jobs.getPlayerManager().addPlayerToMap(new PlayerInfo(playerName, id, uuid, System.currentTimeMillis(), 0));
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(prestt);
	    close(res2);
	}
    }

    int convertSchedId = -1;
    boolean converted = true;

    public void recordNewWorld(String worldName) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	PreparedStatement prestt = null;
	ResultSet res2 = null;
	try {
	    prestt = conn.prepareStatement("INSERT INTO `" + DBTables.WorldTable.getTableName() + "` (`" + worldsTableFields.name.getCollumn() + "`) VALUES (?);",
		Statement.RETURN_GENERATED_KEYS);
	    prestt.setString(1, worldName);
	    prestt.executeUpdate();

	    res2 = prestt.getGeneratedKeys();
	    int id = 0;
	    if (res2.next())
		id = res2.getInt(1);

	    Util.addJobsWorld(new JobsWorld(worldName, id));

	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(prestt);
	    close(res2);
	}
    }

    public synchronized void loadAllJobsWorlds() {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;

	PreparedStatement prest = null;
	ResultSet res = null;
	try {
	    prest = conn.prepareStatement("SELECT * FROM `" + DBTables.WorldTable.getTableName() + "`;");
	    res = prest.executeQuery();
	    while (res.next()) {
		int id = res.getInt("id");
		String name = res.getString(worldsTableFields.name.getCollumn());
		Util.addJobsWorld(new JobsWorld(name, id));
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(res);
	    close(prest);
	}

	for (World one : Bukkit.getWorlds()) {
	    if (Util.getJobsWorld(one.getName()) != null)
		continue;
	    this.recordNewWorld(one.getName());
	}

	return;
    }

    public void triggerTableIdUpdate() {
	// Lets convert old fields
	if (convertSchedId > 0)
	    Bukkit.getServer().getScheduler().cancelTask(convertSchedId);
	if (!converted) {
	    convertSchedId = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
		@Override
		public void run() {
		    Jobs.consoleMsg("&6[Jobs] Converting to new database format");
		    convertID();
		    Jobs.consoleMsg("&6[Jobs] Converted to new database format");
		    converted = true;
		    return;
		}
	    }, 60L);
	}
    }

    private void convertID() {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	PreparedStatement exploreStatement = null;
	try {
	    exploreStatement = conn.prepareStatement("UPDATE `" + DBTables.ExploreDataTable.getTableName() + "` SET `" + ExploreDataTableFields.worldid.getCollumn() + "` = ? WHERE `"
		+ ExploreDataTableFields.worldname.getCollumn() + "` = ?;");
	    for (Entry<String, JobsWorld> jobsWorld : Util.getJobsWorlds().entrySet()) {
		exploreStatement.setInt(1, jobsWorld.getValue().getId());
		exploreStatement.setString(2, jobsWorld.getValue().getName());
		exploreStatement.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(exploreStatement);
	}

	PreparedStatement exploreStatementBack = null;
	try {
	    exploreStatementBack = conn.prepareStatement("UPDATE `" + DBTables.ExploreDataTable.getTableName() + "` SET `" + ExploreDataTableFields.worldname.getCollumn() + "` = ? WHERE `"
		+ ExploreDataTableFields.worldid.getCollumn() + "` = ?;");
	    for (Entry<String, JobsWorld> jobsWorld : Util.getJobsWorlds().entrySet()) {
		exploreStatementBack.setString(1, jobsWorld.getValue().getName());
		exploreStatementBack.setInt(2, jobsWorld.getValue().getId());
		exploreStatementBack.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(exploreStatementBack);
	}

	PreparedStatement bpStatement = null;
	try {
	    bpStatement = conn.prepareStatement("UPDATE `" + DBTables.BlocksTable.getTableName() + "` SET `" + BlockTableFields.worldid.getCollumn() + "` = ?  WHERE `" + BlockTableFields.world
		.getCollumn() + "` = ?;");
	    for (Entry<String, JobsWorld> jobsWorld : Util.getJobsWorlds().entrySet()) {
		bpStatement.setInt(1, jobsWorld.getValue().getId());
		bpStatement.setString(2, jobsWorld.getValue().getName());
		bpStatement.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(bpStatement);
	}

	PreparedStatement bpStatementback = null;
	try {
	    bpStatementback = conn.prepareStatement("UPDATE `" + DBTables.BlocksTable.getTableName() + "` SET `" + BlockTableFields.world.getCollumn() + "` = ?  WHERE `" + BlockTableFields.worldid
		.getCollumn() + "` = ?;");
	    for (Entry<String, JobsWorld> jobsWorld : Util.getJobsWorlds().entrySet()) {
		bpStatementback.setString(1, jobsWorld.getValue().getName());
		bpStatementback.setInt(2, jobsWorld.getValue().getId());
		bpStatementback.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(bpStatementback);
	}

	PreparedStatement archiveStatement = null;
	try {
	    archiveStatement = conn.prepareStatement("UPDATE `" + DBTables.ArchiveTable.getTableName() + "` SET `" + ArchiveTableFields.jobid.getCollumn() + "` = ? WHERE `" + ArchiveTableFields.job
		.getCollumn() + "` = ?;");
	    for (Job job : Jobs.getJobs()) {
		archiveStatement.setInt(1, job.getId());
		archiveStatement.setString(2, job.getName());
		archiveStatement.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(archiveStatement);
	}
	PreparedStatement archiveStatementBack = null;
	try {
	    archiveStatementBack = conn.prepareStatement("UPDATE `" + DBTables.ArchiveTable.getTableName() + "` SET `" + ArchiveTableFields.job.getCollumn() + "` = ? WHERE `" + ArchiveTableFields.jobid
		.getCollumn() + "` = ?;");
	    for (Job job : Jobs.getJobs()) {
		archiveStatementBack.setString(1, job.getName());
		archiveStatementBack.setInt(2, job.getId());
		archiveStatementBack.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(archiveStatementBack);
	}

	PreparedStatement usersStatement = null;
	try {
	    usersStatement = conn.prepareStatement("UPDATE `" + getJobsTableName() + "` SET `" + JobsTableFields.jobid.getCollumn() + "` = ? WHERE `" + JobsTableFields.job.getCollumn() + "` = ?;");
	    for (Job job : Jobs.getJobs()) {
		usersStatement.setInt(1, job.getId());
		usersStatement.setString(2, job.getName());
		usersStatement.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(usersStatement);
	}
	PreparedStatement usersStatementBack = null;
	try {
	    usersStatementBack = conn.prepareStatement("UPDATE `" + getJobsTableName() + "` SET `" + JobsTableFields.job.getCollumn() + "` = ? WHERE `" + JobsTableFields.jobid.getCollumn() + "` = ?;");
	    for (Job job : Jobs.getJobs()) {
		usersStatementBack.setString(1, job.getName());
		usersStatementBack.setInt(2, job.getId());
		usersStatementBack.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(usersStatementBack);
	}

	PreparedStatement limitsStatement = null;
	try {
	    limitsStatement = conn.prepareStatement("UPDATE `" + DBTables.LimitsTable.getTableName() + "` SET `" + LimitTableFields.typeid.getCollumn() + "` = ? WHERE `" + LimitTableFields.type
		.getCollumn() + "` = ?;");
	    for (CurrencyType type : CurrencyType.values()) {
		limitsStatement.setInt(1, type.getId());
		limitsStatement.setString(2, type.getName());
		limitsStatement.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(limitsStatement);
	}

	PreparedStatement limitsStatementBack = null;
	try {
	    limitsStatementBack = conn.prepareStatement("UPDATE `" + DBTables.LimitsTable.getTableName() + "` SET `" + LimitTableFields.type.getCollumn() + "` = ? WHERE `" + LimitTableFields.typeid
		.getCollumn() + "` = ?;");
	    for (CurrencyType type : CurrencyType.values()) {
		limitsStatementBack.setString(1, type.getName());
		limitsStatementBack.setInt(2, type.getId());
		limitsStatementBack.execute();
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    close(limitsStatementBack);
	}
    }

    public void recordNewJobName(Job job) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;

	PreparedStatement prestt = null;
	ResultSet res2 = null;
	try {
	    prestt = conn.prepareStatement("DELETE FROM `" + DBTables.JobNameTable.getTableName()
		+ "` WHERE `" + jobsNameTableFields.name.getCollumn() + "` = ?;");
	    prestt.setString(1, job.getName());
	    prestt.execute();

	    close(prestt);
	    prestt = null;

	    prestt = conn.prepareStatement("INSERT INTO `" + DBTables.JobNameTable.getTableName() + "` (`" + jobsNameTableFields.name.getCollumn() + "`) VALUES (?);",
		Statement.RETURN_GENERATED_KEYS);
	    prestt.setString(1, job.getName());
	    prestt.executeUpdate();

	    res2 = prestt.getGeneratedKeys();
	    int id = 0;
	    if (res2.next())
{'fraction_non_alphanumeric': 0.14010327567636063, 'fraction_numerical': 0.0027086105303174303, 'mean_word_length': 3.837036469506589, 'pattern_counts': {'":': 0, '<': 83, '<?xml version=': 0, '>': 81, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4886394', 'n_tokens_mistral': 21816, 'n_tokens_neox': 20200, 'n_words': 4360}