/*
Copyright 2012-2014 Samuel Gesche

This file is part of the Greek Reuse Toolkit.

The Greek Reuse Toolkit is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

The Greek Reuse Toolkit is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with the Greek Reuse Toolkit.  If not, see <http://www.gnu.org/licenses/>.
*/

package fr.cnrs.liris.drim.grt.proc.base;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
 *
 * @author Sam
 */
public class BaseDeDonnees {
    public static int DB_ERR = 0;
    public static int DB_OK = 1;
    private String databaseConnectionString;
    private String dbUser;
    private String dbPass;
    private Connection dB = null;
    //private ResultSet theResults;
    //private Statement stmt;
    private boolean connected = false;
    private String erreurConnexion = "";
    //private PreparedStatement stmt;
    // Jusqu'à 10000 Threads pourront interroger la base en parallèle.
    private Statement[] stmts = new Statement[10000];
    // compteur de requêtes effectuées
    private int compteur;

    public BaseDeDonnees(String url, String nom, String login, String motDePasse) {
        databaseConnectionString = "jdbc:mysql://"+url+"/"+nom;
        dbUser = login;
        dbPass = motDePasse;
    }
    
    public boolean testOK() {
        return connect() == DB_OK;
    }
    
    public String getErreurConnexion() {
        return erreurConnexion;
    }

    /**
     * Attempts to connect, if not already connected.
     * @return DB_OK if connected, DB_ERR if an error occured.
     */
    public int connect() {
        if (!connected) {
            try {
                Class.forName("com.mysql.jdbc.Driver");
                dB = DriverManager.getConnection(databaseConnectionString, dbUser, dbPass);
                for (int i = 0; i < stmts.length; i++) {
                    stmts[i] = dB.createStatement();
                }
                connected = true;
                erreurConnexion = "";
            } catch (ClassNotFoundException e) {
                erreurConnexion = "Impossible de trouver le driver JDBC pour MySQL (" + e.getLocalizedMessage() + ").";
                return DB_ERR;
            } catch (SQLException e) {
                erreurConnexion = "Impossible de se connecter à la base " + databaseConnectionString + " (" + e.getLocalizedMessage() + ").";
                return DB_ERR;
            }
        }
        if (connected) {
            return DB_OK;
        } else {
            return DB_ERR;
        }
    }

    public ResultSet executeSelection(String sql) throws NoBaseException {
        if(!connected) connect();
        if(!connected) throw new NoBaseException();
        int id = (int) (Thread.currentThread().getId() % stmts.length);
        ResultSet theResults = null;
        try {
            theResults = stmts[id].executeQuery(sql);
            theResults.beforeFirst();
        } catch (Exception e) {
            //e.printStackTrace();
        }
        incrementeCompteur();
        return theResults;
    }

    public int executeInsertOrUpdate(String sql) throws NoBaseException {
        if(!connected) connect();
        if(!connected) throw new NoBaseException();
        int id = (int) (Thread.currentThread().getId() % stmts.length);
        int res = 0;
        try {
            Statement stmt = stmts[id];
            stmt.executeUpdate(sql, stmt.RETURN_GENERATED_KEYS);
            res = stmt.getGeneratedKeys().getRow();
            ResultSet clefs = stmt.getGeneratedKeys();
            if (clefs.next()) {
                res = Integer.parseInt(clefs.getObject(1).toString());
            }
            clefs.close();
            // Closing the Statement to avoid memory leaks
            stmt.close();
            stmts[id] = dB.createStatement();
        } catch (Exception e) {
            //e.printStackTrace();
        }
        incrementeCompteur();
        return res;
    }

    public void executeDeletion(String sql) throws NoBaseException {
        if(!connected) connect();
        if(!connected) throw new NoBaseException();
        int id = (int) (Thread.currentThread().getId() % stmts.length);
        try {
            Statement stmt = stmts[id];
            stmt.executeUpdate(sql);
            // Closing the Statement to avoid memory leaks
            stmt.close();
            stmts[id] = dB.createStatement();
        } catch (Exception e) {
            //e.printStackTrace();
        }
        incrementeCompteur();
    }

    public int disconnect() {
        try {
            for (int i = 0; i < stmts.length; i++) {
                stmts[i].close();
            }
            dB.close();
            connected = false;
            //System.out.println("Disconnected");
            return DB_OK;
        } catch (Exception e) {
            //System.err.println("Error Disconnecting");
            return DB_ERR;
        }

    }

    private void incrementeCompteur(){
        compteur++;
        if(compteur%1000==0){
            System.err.println(compteur+" requêtes effectuées sur la base.");
        }
    }
}
