package kamiworldserver;

import java.util.logging.Level;
import java.util.logging.Logger;
import kamiworldserver.control.*;
import kamiworldserver.elem.*;

import java.net.Socket;
import java.sql.*;

import java.util.HashMap;
import java.util.ArrayList;
import java.util.Iterator;

import java.io.IOException;

public class KamiServer {

    public static KamiServer main;

    public static String sHost = null;

    private final int nCount = 1;

    private KamiConfig kc_Config = null;
    private HashMap<String, String> hmConfig = null;
    private KamiWorldLoader kwl_Loader = null;
    private HashMap<String, KamiMap> hmLevels = null;
    private Connection conConnection;
    private Statement stState;
    private KamiListener kl_Listener = null;
    private KamiProcessor[] kp_Processors = null;
    private ArrayList<KamiUser> alUsers = null;
    //private KamiUser[] ku_Users = null;
    //private KamiMap[] km_Maps = null;
    private int nPort = 0;
    private String sDBURL;
    //private int nCurrent = 0;

    public KamiServer(int port) {

        main = this;
        nPort = port;

        hmConfig = new HashMap<String, String>();
        hmLevels = new HashMap<String, KamiMap>();
        alUsers = new ArrayList<KamiUser>();

        kc_Config = new KamiConfig();
        kwl_Loader = new KamiWorldLoader();
        kl_Listener = new KamiListener(nPort);

        kp_Processors = new KamiProcessor[nCount];
        int i = 0;
        while (i < nCount) {
            kp_Processors[i] = new KamiProcessor(this, hmLevels);
            ++i;
        }

    }

    public void start() {

        kc_Config.readConfig(hmConfig);
        sHost = (String) hmConfig.get("hostname");
        kwl_Loader.loadToMap(kwl_Loader.getList( sHost ), hmLevels);
        //kwl_Loader.start();


        try {
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            //conConnection = DriverManager.getConnection("jdbc:mysql://localhost:3306/Kamineko2","root", "");
            sDBURL = "jdbc:mysql://" + hmConfig.get("database") + "/" + hmConfig.get("use") + "?user=" + hmConfig.get("name") + "&password=" + hmConfig.get("pass") + "&autoReconnect=true";
            connect();

        } catch (InstantiationException ex) {
            System.out.println("SQL Connection failed - Class not found.");
            System.exit(-1);
        } catch (IllegalAccessException ex) {
            System.out.println("SQL Connection failed - Class not found.");
            System.exit(-1);
        } catch (ClassNotFoundException e) {
            System.out.println("SQL Connection failed - Class not found.");
            System.exit(-1);
        }

        kl_Listener.start();

        for (KamiProcessor kp : kp_Processors) {
            kp.start();
        }

    }

    public boolean hasUser(KamiUser ku) {
        synchronized (alUsers) {
            Iterator<KamiUser> itr = alUsers.iterator();
            while (itr.hasNext()) {
                if (itr.next().checkSame(ku.getSocket())) {
                    return true;
                }
            }
        }
        return false;
    }

    // =========================================================================
    // Other
    //
    public static void addUser(Socket s) {

        int i_low = main.kp_Processors[0].getAmount();
        int i_id = 0;
        int i = 0;

        while (i < main.kp_Processors.length) {
            if (i_low > main.kp_Processors[i].getAmount()) {
                i_id = i;
                i_low = main.kp_Processors[i].getAmount();
            }
            ++i;
        }

        try {
            KamiUser ku = new KamiUser(s, main.kp_Processors[i_id]);
            /*
            if (main.hasUser(ku)) {
            s.close();
            return;
            }
             **/
            main.alUsers.add(ku);
            main.kp_Processors[i_id].addUser(ku);
            System.out.println("New user connected. Current amount: " + main.alUsers.size());
        } catch (IOException ex) {
            System.out.println("Unable to add user.");
        }

    }

    public static void removeUser(KamiUser ku) {
        synchronized (main.alUsers) {
            main.alUsers.remove(ku);
        }
    }

    public static int countUsers() {
        synchronized (main.alUsers) {
            return main.alUsers.size();
        }
    }

    public static ArrayList<KamiUser> getUsers() {
        return main.alUsers;
    }

    public void connect() {
        System.out.println("[KamiServer::connect] Establishing a mysql connection");
        try {
            if(conConnection!=null && conConnection.isValid(0)) conConnection.close();
            conConnection = DriverManager.getConnection(sDBURL);
            stState = conConnection.createStatement();

        } catch (Exception e) {
            System.out.println("SQL Connection failed - Unknow error.");
            System.exit(-1);
        }
        for (KamiProcessor kp : kp_Processors) {
            kp.setStatement(stState);
        }
    }

    //
    // Statics
    public static void reconnect() {
        main.connect();
    }

    public static void checkMap(String map) {
        main.kwl_Loader.recheckFile(map);
    }
}
