package sac.persistencia;

import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Classe responsável pela geração de novos OIDs para novos objetos
 * a serem armazenados no repositório.
 * @author: srmq
 * @version: 0.1.0
 */
public class OIDFactory {

    private static OIDFactory instancia = null;

    /**
     * Proximo valor do low que sera usado para gerar os objetos do tipo OID
     */
    private int nextlow;

    /**
     * Proximo valor do high que sera usado para gerar os objetos do tipo OID
     */
    private long nexthigh;


    /**
     * Valor constante que determina o limite onde um novo valor do high deve ser
     * adquirido do Banco de Dados
     */
    private static final int MAX_LOW_OID = 9;

    private static final String OID_TABLE = "oid_high";
    private static final String OID_COLUMN = "high_val";


    /**
 * ObjectFactory constructor comment.
 */
    private OIDFactory() throws PersistenceException {
	super();
        this.nextlow = 0;
        this.nexthigh = this.fetchHigh();
    }

    public static synchronized OIDFactory getInstancia() throws PersistenceException {
        if (instancia == null) {
            instancia = new OIDFactory();
        }
        return instancia;
    }

/**
 * Cria e retorna um novo objeto OID.
 *
 * @return  novo id de objeto
 * @throws PersistenceException
 */
    public synchronized OID novoOID() throws PersistenceException {
        OID oid;

        if (this.nextlow <= OIDFactory.MAX_LOW_OID) {
            String oidStr = Long.toString(this.nexthigh) + this.getNextLow();
            oid = new OID(Long.parseLong(oidStr));
            this.nextlow++;
        } else {
            this.nexthigh = this.fetchHigh();
            this.nextlow  = 0;
            String oidStr = Long.toString(this.nexthigh) + this.getNextLow();
            oid = new OID(Long.parseLong(oidStr));
            this.nextlow++;
        }
        return oid;
    }

    private String getNextLow() {
	/*
	 * Para garantir que nextLow tenha o numero correto digitos.
         */
	String nextLow = Integer.toString(this.nextlow);
        String strMaxLow = Integer.toString(OIDFactory.MAX_LOW_OID);
        int dif;
        if ((dif = strMaxLow.length() - nextLow.length()) > 0) {
            StringBuffer stb = new StringBuffer(strMaxLow.length());
            while (dif-- != 0) {
                stb.append('0');
            }
            stb.append(nextLow);
            nextLow = stb.toString();
        }
	return nextLow;
}

    private long fetchHigh() throws PersistenceException {
        final String fetchSQL = "select * from " + OIDFactory.OID_TABLE;
        final String updateSQL = "update " + OIDFactory.OID_TABLE +
            " set " + OIDFactory.OID_COLUMN + " = " + OIDFactory.OID_COLUMN +
            " + 1";
        Connection con = null;
        try {
            con = PoolConexoes.getInstancia().obterConexao();
            Statement stmt = con.createStatement();
            ResultSet rset = stmt.executeQuery(fetchSQL);
            if (!rset.next()){
              throw new PersistenceException("Erro de persistencia ao tentar" +
                " atualizar OID");
            }
            long currHigh = rset.getLong(1);
            rset.close();
            stmt.executeUpdate(updateSQL);
            stmt.close();
            return currHigh;
        } catch (SQLException ex) {
            throw new PersistenceException("Erro de persistencia ao tentar" +
                " atualizar OID", ex);
        } finally {
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException ex) { }
            }
        }
    }

}
