package kamicharserver;

import java.net.*;
import java.sql.*;
import java.io.IOException;
import java.util.ArrayList;
//import java.util.Iterator;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

public class KamiCharServer {

    public static final int nTimeout = 10000;
    public static KamiCharServer main = null;
    public static String sHost = null;
    private HashMap<String, String> hmConfig;
    private ArrayList<KamiUser> aUsers;
    private KamiServerListener ksl_Listen;
    private KamiProcessor kp_Processor;
    private KamiConfig kc_Config;
    Connection conConnection;
    Statement stState;

    private String sDBURL;
    int itP = 0;

    public KamiCharServer() {
        main = this;

        hmConfig = new HashMap<String, String>();
        kc_Config = new KamiConfig();
        aUsers = new ArrayList<KamiUser>();
        ksl_Listen = new KamiServerListener();
        kp_Processor = new KamiProcessor();
    }

    public void start(int port) {
        kc_Config.readConfig(hmConfig);
        if (hmConfig.get("redirect") != null) {
            KamiProcessor.sWorldIP = hmConfig.get("redirect");
        } else {
            KamiProcessor.sWorldIP = ".";
        }

        sHost = hmConfig.get("hostname");

        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";
            reconnect();

        } 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);
        }

        
        ksl_Listen.setPort(port);
        ksl_Listen.start();

        while (true) {
            itP = 0;
            while (itP < aUsers.size()) {
                if (aUsers.get(itP).process()) {
                    --itP;
                }
                ++itP;
            }

            try {

                if (stState.isClosed()) {
                    stState = getStatement();
                    kp_Processor.setStatement(stState);
                }

                Thread.sleep(10);
                Thread.yield();
            } catch (SQLException ex) {
                System.out.println("SQLStatement state check (closed?) failed.");
            } catch (Exception ec) {
                System.out.println("Unknow error :" + ec.toString());
            }
        }
    }

    public void addUser(Socket socket) {
        try {
            aUsers.add(new KamiUser(socket, kp_Processor));
            System.out.println("Current amount of users: " + aUsers.size());
        } catch (IOException ex) {
            System.out.println("New user failed to connect.");
        }
    }

    public void removeUser(KamiUser u) {
        aUsers.remove(u);
        System.out.println("Current amount of users: " + aUsers.size());
    }

    public Statement getStatement() {
        try {
            return conConnection.createStatement();
        } catch (SQLException ex) {
            System.exit(-1);
        }
        return null;
    }

    public void connect() {
        System.out.println("[KamiCharServer::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);
        }
        kp_Processor.setStatement(stState);
    }

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


//
// Connections Listener
class KamiServerListener extends Thread {

    ServerSocket ss_Socket;
    Socket s_Socket;
    int nPort = 0;

    public KamiServerListener() {
    }

    public void setPort(int port) {
        nPort = port;
    }

    //
    // run
    @Override
    public void run() {

        try {
            ss_Socket = new ServerSocket(nPort);
            System.out.println("Server listener: Accepting.");
            while (true) {
                s_Socket = ss_Socket.accept();
                //s_Socket.setTcpNoDelay(false);
                System.out.println("New user connected.");
                KamiCharServer.main.addUser(s_Socket);
            }
        } catch (IOException e) {
            System.out.println("Accept failed: 31337");
            System.exit(-1);
        }
    }
}