package combd;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
/**
 *   Facilita a manipulação de um <code>ResultSet</code>.
 *
 * @author Marcos V. S. Godinho
 */
public class ResultadoDeBusca{

    private ResultSet dados;
    private ResultSetMetaData info;
    private int numColunas;
    private int numLinhas;

    /**
     * Cria um nova instância de ResultadoDeBusca.
     * @param resultado o ResultSet que contém os dados.

     */
    public ResultadoDeBusca(ResultSet resultado){

        dados = resultado;

        try{
           info = resultado.getMetaData();
        }
        catch(SQLException ex0){

            System.err.println("Não foi possível a obtenção do ResultSetMetaData.");
            ex0.printStackTrace();
        }

        numColunas = contaColunas();
        numLinhas = contaLinhas();
    }


    /** Finalizador da instância da classe. */
    protected void finalize() throws Throwable{

        dados = null;//Marca Para coleta de lixo.
        info = null;

        /* Este objeto é finalizado antes da finalização do programa e deve
        chamar o finalizador dos seus objetos armazenados.*/
        System.runFinalization();
    }


    /**
     * Conta o número de linhas do ResultSet.
     * @return o número de linhas contabilizadas.
     */
    private final int contaLinhas(){

        int limInferior = 0;
        int limSuperior = 0;
        int posMedia;

        try{
           dados.last();
           limSuperior = dados.getRow();
        }
        catch(SQLException ex0){

            ex0.printStackTrace();
            return 0;//Não tem nenhuma por motivos de erros.
        }

        if(limSuperior == 0)  return 0;//Não obteve resultado.

        try{
           dados.getObject(1);//primeira coluna.

           return limSuperior;//O último realmente é o último.
        }
        catch(SQLException ex1){}

        do{

            posMedia = (limSuperior + limInferior) / 2;

            try{
                dados.absolute(posMedia + 1);//Obs: posição começa do zero.
                dados.getObject(1);//primeira coluna.
                dados.next();
                dados.getObject(1);

                limInferior = posMedia;
            }
            catch(SQLException ex2){

                limSuperior = posMedia;
            }

            if(limSuperior == limInferior) break;

        }while(true);

        return posMedia + 1;//Obs: posição começa do zero.
    }//procuraUltimo


    /**
     * Conta o número de colunas do ResultSet.
     * @return o número de colunas contabilizadas.
     */
    private final int contaColunas(){

        try{
            return info.getColumnCount();
        }
        catch(SQLException e){

            e.printStackTrace();
        }

        return 0;//Não tem nenhuma.
    }


    /**
     * Retorna o número de colunas do ResultadoDeBusca.
     * @return o número de colunas
     */
    public int getNumColunas(){

        return numColunas;
    }


    /**
     * Retorna o número de linhas do ResultadoDeBusca.
     * @return o número de linhas
     */
    public int getNumLinhas(){

        return numLinhas;
    }


    /**
     * Retorna o nome da classe da coluna especificada.
     * @param col o número da coluna. A primeira é a 0, a segunda é a 1, ...
     * @return o nome da classe.
     */
    public String getNomeClasse(int col){

        try{
            return info.getColumnClassName(col + 1);
        }
        catch(SQLException e){

            e.printStackTrace();
        }

        return null;
    }


    /**
     * Retorna o nome da coluna especificada.
     * @param col o número da coluna. A primeira é a 0, a segunda é a 1, ...
     * @return o nome da coluna.
     */
    public String getNomeColuna(int col){

        try{
            return info.getColumnName(col + 1);
        }
        catch(SQLException e){

            e.printStackTrace();
        }

        return null;
    }

    /**
     * Retorna um array com o nome das colunas.
     * @return o nome das colunas.
     */
    public String[] getNomeColunas(){

        String[] nome = new String[ numColunas ];

        for(int i=0; i < nome.length; i++){

            if( ( nome[i] = getNomeColuna(i) ) == null )

                return null;
        }

        return nome;
    }


    /**
     * Retorna o dado do local especificado.
     * @param linha o número da linha. A primeira é a 0, a segunda é a 1, ...
     * @param col o número da coluna. A primeira é a 0, a segunda é a 1, ...
     * @return o dado.
     */
    public Object getDado(int linha, int col){

        try{
            if( dados == null )
                return null;

            dados.absolute(linha + 1);

            return dados.getObject(col + 1);

        }
        catch(SQLException ex1){

            System.err.println("Erro na leitura de dado.");
            System.err.println("linha: " + linha + " col: " + col + " numLinhas: " + getNumLinhas() );
            ex1.printStackTrace();
        }

        return null;

    }//getDado


    /**
     * Retorna um array com os dados de toda uma linha.
     * @param linha o número da linha. A primeira é a 0, a segunda é a 1, ...
     * @return os dados da linha.
     */
    public Object[] getLinhaDados(int linha){

        if( dados == null )
                return null;

        Object[] linhaDados = new Object[ numColunas ];
        Object dado;
        int col = 0;

        try{
            dados.absolute(linha + 1);

            for( int i=0; i < linhaDados.length; col = ++i ){

                linhaDados[i] = dados.getObject(col + 1);
            }
        }
        catch(SQLException ex){

            System.err.println("Erro na leitura da linha de dados.");
            System.err.println("linha: " + linha + " col: " + col + " numLinhas: " + numLinhas );
            ex.printStackTrace();
            return null;
        }

        return linhaDados;
    }//getLinhaDados


    /**
     * Retorna um array bidimensional com todos os dados.
     * @return todos os dados.
     */
    public Object[][] getArrayDados(){

        if( !existeDados() )
            return null;

        Object[][] arrayDados = new Object[ numLinhas ][ numColunas ];
        Object[] linhaDados;

        for( int i=0; i < arrayDados.length; i++ ){

            linhaDados = getLinhaDados(i);

            if(linhaDados == null) break;

            arrayDados[i] = linhaDados;
        }

        return arrayDados;
    }//getArrayDados


    /**
     * Verifica se existe dados disponíveis para manipulação.
     * @return <code>true</code> se houver dados.
     */
    public boolean existeDados(){

        if(dados == null || numLinhas < 1)
            return false;

        return true;
    }
}
