package sac.pessoa.endereco.jdbc;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.SQLException;
import java.util.List;


import sac.exception.ItemNaoCadastradoException;
import sac.pessoa.endereco.Endereco;
import sac.pessoa.endereco.RepositorioEndereco;
import sac.pessoa.util.jdbc.DBRepository_Abstract;
import sac.pessoa.util.jdbc.PersistenteFactory;
import sac.persistencia.CacheObjetos;
import sac.persistencia.OID;
import sac.persistencia.OIDFactory;
import sac.persistencia.PersistenceException;
import sac.persistencia.PoolConexoes;


public class DBEndereco extends DBRepository_Abstract implements RepositorioEndereco {
    // instancia unica da clase
    private static DBEndereco instancia;

    //Atributos para controle de acesso ao BD.
    private PoolConexoes pool;
    private CacheObjetos cache;
    private OIDFactory oidfactory;

    // fabrica de objectos persistentes
    private PersistenteFactory addressFactory;

    // consulta por um endereco atraves de seu codigo
    private final String preparedSelectEnderecoSql =
            "select cd_endereco, tx_endereco,tx_bairro, tx_cidade,tx_estado," +
            "tx_pais,tx_cep,tx_telefone, tx_email from endereco "+
            " where cd_endereco = ? ";
   private final String preparedSelecCodetAddressWithDataAddressSql =
            "select cd_endereco from endereco "+
            " where tx_endereco= ? and tx_bairro = ? and  tx_cidade = ? and "+
            " tx_estado = ? and tx_pais = ? and tx_telefone = ? and tx_email = ? " +
            "and tx_cep = ?" ;
   private final String preparedInsertEndereco =
            "insert into endereco (cd_endereco, tx_endereco,tx_bairro, tx_cidade," +
            "tx_estado,tx_pais,tx_cep,tx_telefone,tx_email) values ( ?, ?,?, ?,"+
            "?,?,?,?,?)";

    public DBEndereco() throws PersistenceException{
        pool = PoolConexoes.getInstancia();
        cache = CacheObjetos.getInstancia();
        oidfactory = OIDFactory.getInstancia();

        addressFactory = PersistenteFactory_Endereco.getInstancia();
    }

    public static synchronized DBEndereco getInstancia()
            throws PersistenceException {
        if (instancia == null) {
            instancia = new DBEndereco();
        }
        return instancia;
    }

    /**
    * Assinatura de método para conlsuta de um endereco.
    *
    * @param id            Long contendo ID do endereco.
    *
    * @return Endereco com o OID buscado.
    */
    public Endereco procurar(OID oid) throws PersistenceException,
            ItemNaoCadastradoException {
        Connection con = getConnection();
        PreparedStatement pre = createPreparedStatement(con,
            preparedSelectEnderecoSql);
        try {
            pre.setLong(1, oid.getLongValue());
            return (Endereco) selectObject( oid, pre,
                                addressFactory);
        } catch (SQLException sqle){
            throw new PersistenceException ("Problemas no BD.", sqle);
        } finally {
            closeStatement(pre);
            freeConnection(con);
        }
    }

    /**
    * Assinatura de método para consulta de um OID de endereco, quando achado é
    * setado o OID neste objecto de procura.
    *
    * @param endereco            Endereco do qual se deseja saber o OID.
    *
    * @return OID  correspondente a busca pelo endereco
    */
    public Endereco procurar(Endereco endereco) throws PersistenceException,
            ItemNaoCadastradoException {
        OID oid ;
        Connection con = getConnection();
        PreparedStatement preCodigo = createPreparedStatement(con,
            preparedSelecCodetAddressWithDataAddressSql);
        try {
            preCodigo.setString(1,endereco.getRua());
            preCodigo.setString(2,endereco.getBairro());
            preCodigo.setString(3,endereco.getCidade());
            preCodigo.setString(4,endereco.getEstado());
            preCodigo.setString(5,endereco.getPais());
            preCodigo.setString(6,endereco.getTelefone());
            preCodigo.setString(7,endereco.getEmail());
            preCodigo.setString(8,endereco.getCep());

            ResultSet rsCodigo = preCodigo.executeQuery();
            if (rsCodigo.next()){
                oid = new OID (rsCodigo.getLong("cd_endereco"));
            }else {
                throw new ItemNaoCadastradoException("Endereco não cadastrado:"+
                    endereco.toString());
            }
            endereco.setId(oid);
            rsCodigo.close();
        }catch(SQLException e){
            throw new PersistenceException ("Problema Endereco no banco", e) ;
        }finally{
            closeStatement(preCodigo);
            freeConnection(con);
        }
        return endereco;
   }

   public void inserir ( Endereco endereco) throws PersistenceException {
        Connection con = getConnection();
        try {
            inserir(endereco, con);
            con.commit();
        } catch (SQLException sqle) {
            throw new PersistenceException ("Problemas ao inserir o Endereco "+
                "no banco", sqle) ;
        } catch (PersistenceException pere){
            throw pere;
        } finally {
            freeConnection(con);
        }
   }

    public void inserir ( Endereco endereco, Connection con)
        throws PersistenceException {

        PreparedStatement preEndereco = createPreparedStatement(con,
            preparedInsertEndereco);
        try {
            OID oid;
            if ( endereco.getId() == null ) {

                try {
                    oid = procurar(endereco).getId();
                } catch ( ItemNaoCadastradoException iteme) {
                    oid = oidfactory.novoOID();
                    preEndereco.setLong (1, oid.getLongValue());
                    preEndereco.setString(2,endereco.getRua());
                    preEndereco.setString(3,endereco.getBairro());
                    preEndereco.setString(4,endereco.getCidade());
                    preEndereco.setString(5,endereco.getEstado());
                    preEndereco.setString(6,endereco.getPais());
                    preEndereco.setString(7,endereco.getCep());
                    preEndereco.setString(8,endereco.getTelefone());
                    preEndereco.setString(9,endereco.getEmail());
                    preEndereco.executeUpdate();
                    cache.inserirObjeto(oid, endereco);

                }
                endereco.setId(oid);
            }

        }catch(SQLException e){
            throw new PersistenceException ("Problemas Endereco no banco", e) ;
        }finally{
            closeStatement(preEndereco);
        }
    }
}