/*
 * Universidade Federal de Pernambuco
 * Centro de Informática
 *
 * SAC - Sociedade beneficente de Amparo aos portadores de AIDS e do Cancer
 *
 * Tipo: DBReferenciaBibliografica
 *
 * Esta classe implementa o repositorio: RepositorioReferenciaBibliografica
 *
 * @author Centro de Informatica - UFPE
 * @version  0.1 -  14/11/2001
 * @since JDK 1.2
 */

package sac.bibliografia;

import java.util.List;
import java.util.LinkedList;
import java.util.Iterator;

import java.sql.PreparedStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Date;

import sac.persistencia.OIDFactory;
import sac.persistencia.CacheObjetos;
import sac.persistencia.OID;
import sac.persistencia.PoolConexoes;

import sac.exception.NullArgumentException;
import sac.exception.NomeInvalidoException;
import sac.persistencia.PersistenceException;

public class DBReferenciaBibliografica implements RepositorioReferenciaBibliografica {

    private static final String procurarReferenciaBibliograficaSQL =
            "select cd_item, nm_titulo, nm_autores, nm_origem, dt_publicacao, "+
            "nm_local_armaz, ds_trecho, vl_tipo "+
            "from item_bibliografico where ";

    private static final String inserirReferenciaBibliograficaSQL =
            "insert into item_bibliografico (cd_item, nm_titulo, nm_autores, "+
            "nm_origem, dt_publicacao, "+
            "nm_local_armaz, ds_trecho, vl_tipo) values (?,?,?,?,?,?,?,?)";

    private static final String alterarReferenciaBibliograficaSQL =
            "update item_bibliografico set nm_titulo = ?, nm_autores = ?, "+
            "nm_origem = ?, dt_publicacao = ?, "+
            "nm_local_armaz = ?, ds_trecho = ?, vl_tipo = ? where cd_item = ?";

    private static DBReferenciaBibliografica instancia;

    private PoolConexoes connectionPool;
    private CacheObjetos cache;
    private OIDFactory factory;

    /**
    * Construtor da Classe
    */
    public DBReferenciaBibliografica() throws PersistenceException {
        connectionPool = PoolConexoes.getInstancia();
        cache = CacheObjetos.getInstancia();
        factory = OIDFactory.getInstancia();
    }

    public static synchronized DBReferenciaBibliografica getInstancia() throws PersistenceException {
      if (instancia == null) {
          instancia = new DBReferenciaBibliografica();
      }
      return instancia;
    }

    public void inserir(ReferenciaBibliografica referencia) throws PersistenceException, NomeInvalidoException, ReferenciaBibliograficaJaCadastradaException, NullArgumentException {
        Connection con = null;
        OID oid = null;

        try {

            FiltroBuscaReferencia verificaExistencia = new FiltroBuscaReferencia();
            verificaExistencia.setAutor(referencia.getAutores());
            verificaExistencia.setTitulo(referencia.getTitulo());
            List encontradas = null;
            try {
              encontradas = this.procurar(verificaExistencia);
            }
            catch (ReferenciaBibliograficaNaoCadastradaException exc) {
              encontradas = new LinkedList();
            }
            if (encontradas.size()==0) {
              con = connectionPool.obterConexao();
              con.setAutoCommit(false);

              oid = factory.novoOID();
              referencia.setID(oid);
              inserir(referencia, con);
              cache.inserirObjeto(oid, referencia);
              con.commit();
            }
            else {
              throw new ReferenciaBibliograficaJaCadastradaException();
            }
        }
        catch (SQLException exc) {
            cache.invalidarObjeto(oid);
            throw new PersistenceException(exc.getMessage());
        }
        finally {
            if (con != null) {
                try {
                    connectionPool.liberarConexao(con);
                } catch (SQLException exc) {
                    throw new PersistenceException(exc.getMessage());
                }
            }
        }
    }

    private void inserir (ReferenciaBibliografica referencia, Connection con) throws SQLException {
        PreparedStatement pStmt = null;

        try {
            pStmt = con.prepareStatement(inserirReferenciaBibliograficaSQL);

            pStmt.setLong(1, referencia.getID().getLongValue());
            pStmt.setString(2, referencia.getTitulo());
            pStmt.setString(3, referencia.getAutores());
            pStmt.setString(4, referencia.getOrigem());
            pStmt.setDate(5, new Date(referencia.getDataPublicacao().getTime()));
            pStmt.setString(6, referencia.getLocalArmazenamento());
            pStmt.setString(7, referencia.getTrecho());
            pStmt.setInt(8, referencia.getTipo());
            pStmt.execute();
        }
        finally {
            if (pStmt!=null) {
                pStmt.close();
            }
        }
   }

   public void alterar(ReferenciaBibliografica referencia, ReferenciaBibliografica newReferencia) throws PersistenceException {
        Connection con = null;
        OID oid;
        try {
            con = connectionPool.obterConexao();
            con.setAutoCommit(false);

            oid = referencia.getID();
            alterar(oid, newReferencia, con);
            cache.inserirObjeto(oid,newReferencia);
            con.commit();
        }
        catch (SQLException exc) {
            throw new PersistenceException();
        }
        finally {
            if (con != null) {
                try {
                    connectionPool.liberarConexao(con);
                } catch (SQLException exc) {
                    throw new PersistenceException(exc.getMessage());
                }
            }
        }
   }

    private void alterar (OID oid, ReferenciaBibliografica referencia, Connection con) throws SQLException {
        PreparedStatement pStmt = null;

        try {
            pStmt = con.prepareStatement(alterarReferenciaBibliograficaSQL);

            pStmt.setString(1, referencia.getTitulo());
            pStmt.setString(2, referencia.getAutores());
            pStmt.setString(3, referencia.getOrigem());
            pStmt.setDate(4, new Date(referencia.getDataPublicacao().getTime()));
            pStmt.setString(5, referencia.getLocalArmazenamento());
            pStmt.setString(6, referencia.getTrecho());
            pStmt.setInt(7, referencia.getTipo());
            pStmt.setLong(8, oid.getLongValue());
            pStmt.executeUpdate();
        }
        finally {
            if (pStmt!=null) {
                pStmt.close();
            }
        }
    }

   public ReferenciaBibliografica procurar(OID id) throws ReferenciaBibliograficaNaoCadastradaException, PersistenceException, NullArgumentException, NomeInvalidoException {
      ReferenciaBibliografica referencia = null;
      Connection con = null;
      Object obj = null;
      try {
          obj = cache.pegarObjeto(id);
          if(obj == null){
            con =  connectionPool.obterConexao();
            referencia = procurar(id, con);
            cache.inserirObjeto(id, referencia);
          }
          else {
            referencia = (ReferenciaBibliografica) obj;
          }
          return referencia;
      } catch (SQLException exc) {
          throw new PersistenceException(exc.getMessage());
      }
      finally {
          if (con != null) {
              try {
                  connectionPool.liberarConexao(con);
              } catch (SQLException exc) {
                  throw new PersistenceException(exc.getMessage());
              }
          }
      }
    }

    private ReferenciaBibliografica procurar(OID id, Connection con) throws SQLException, ReferenciaBibliograficaNaoCadastradaException, NullArgumentException, NomeInvalidoException {
        PreparedStatement statement = null;
        ReferenciaBibliografica referencia = null;
        StringBuffer sql = new StringBuffer(procurarReferenciaBibliograficaSQL);
        sql.append("cd_item = ");
        sql.append(id.getLongValue());
        try {
            statement =  con.prepareStatement(sql.toString());
            ResultSet resultSet = statement.executeQuery();

            if(resultSet.next()) {
                referencia = getReferenciaBibliografica(resultSet);
            } else {
                throw new ReferenciaBibliograficaNaoCadastradaException ("O oid buscado não foi encontrado no sistema, oid = " + id+"." );
            }
        } finally {
            if(statement != null) {
              statement.close();
            }
        }
        return referencia;
    }


    private List procurar(FiltroBuscaReferencia filtro, Connection con) throws SQLException, ReferenciaBibliograficaNaoCadastradaException, NullArgumentException, NomeInvalidoException {
        PreparedStatement statement = null;
        ReferenciaBibliografica referencia = null;
        List referencias = new LinkedList();
        try {

          statement =  con.prepareStatement(constroiSQLProcurar(filtro));
          ResultSet resultSet = statement.executeQuery();

          while(resultSet.next()) {
            referencias.add(getReferenciaBibliografica(resultSet));
          }
        } finally {
            if(statement != null) {
              statement.close();
            }
        }
        return referencias;
    }

    private ReferenciaBibliografica getReferenciaBibliografica(ResultSet resultSet) throws SQLException, NomeInvalidoException, NullArgumentException {
        ReferenciaBibliografica referencia = new ReferenciaBibliografica();

        System.out.println("Construindo ref:"+resultSet.getLong("CD_ITEM"));

        referencia.setID(new OID(resultSet.getLong("CD_ITEM")));
        if (cache.pegarObjeto(referencia.getID())==null) {
            referencia.setTitulo(resultSet.getString("NM_TITULO"));
            referencia.setAutores(resultSet.getString("NM_AUTORES"));
            referencia.setOrigem(resultSet.getString("NM_ORIGEM"));
            referencia.setDataPublicacao(new java.util.Date((resultSet.getDate("DT_PUBLICACAO")).getTime()));
            referencia.setLocalArmazenamento(resultSet.getString("NM_LOCAL_ARMAZ"));
            referencia.setTrecho(resultSet.getString("DS_TRECHO"));
            referencia.setTipo(resultSet.getInt("VL_TIPO"));
            cache.inserirObjeto(referencia.getID(),referencia);
        }
        else {
          referencia = (ReferenciaBibliografica)cache.pegarObjeto(referencia.getID());
        }
        return referencia;
    }

    public List procurar(FiltroBuscaReferencia filtro) throws PersistenceException, NomeInvalidoException, NullArgumentException, ReferenciaBibliograficaNaoCadastradaException {
        Connection con = null;
        List referencias = new LinkedList();

        try {
            con =  connectionPool.obterConexao();
            referencias = procurar(filtro, con);
        } catch (SQLException excecao) {
            throw new PersistenceException(excecao);
        }
        finally {
            if (con != null) {
                try {
                    connectionPool.liberarConexao(con);
                } catch (SQLException exc) {
                    throw new PersistenceException(exc.getMessage());
                }
            }
        }
        return referencias;
    }

    private String constroiSQLProcurar(FiltroBuscaReferencia filtro) throws NomeInvalidoException {
        StringBuffer sql = new StringBuffer(procurarReferenciaBibliograficaSQL);
        boolean sqlValido = false;

        String titulo;
        if ((titulo=filtro.getTitulo())!=null && !titulo.equals("")) {
//          sql.append("nm_titulo like ");
          sql.append("nm_titulo = ");
//          sql.append('%');
//          sql.append(titulo.replace(' ','%'));
          sql.append("'"+titulo+"'");
//          sql.append('%');
          sqlValido = true;
        }

        String autor;
        if ((autor=filtro.getAutor())!=null && !autor.equals("")) {
          if (sqlValido) {
            sql.append(" and ");
          }
//          sql.append("nm_autores like ");
          sql.append("nm_autores = ");
//          sql.append('%');
//          sql.append(autor.replace(' ','%'));
          sql.append("'"+autor+"'");
//          sql.append('%');
          sqlValido = true;
        }

        if (!sqlValido) {
          throw new NomeInvalidoException("Nenhum campo para autor ou titulo foi setado");
        }
        return sql.toString();
    }

/*
   private List procurar(List oids, Connection con) throws PersistenceException, NomeInvalidoException, NullArgumentException, ReferenciaBibliograficaNaoCadastradaException {
        List referencias = new LinkedList();
        ReferenciaBibliografica referencia;
        Iterator iterator;
        Object obj;

        try {
            iterator = oids.iterator();
            while(iterator.hasNext()) {
              OID oid = (OID) iterator.next();

              obj = cache.pegarObjeto(oid);
              if(obj == null) {
                referencia = procurar(oid, con);
                cache.inserirObjeto(oid, referencia);
              } else {
                referencia = (ReferenciaBibliografica) obj;
              }
              referencias.add(referencia);
            }
        } catch (SQLException excecao) {
            throw new PersistenceException(excecao);
        } finally {
            if (con != null) {
                try {
                    connectionPool.liberarConexao(con);
                } catch (SQLException exc) {
                    throw new PersistenceException(exc.getMessage());
                }
            }
        }
        return referencias;
   }
*/
}
