package sac.pessoa.juridica.jdbc;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.ArrayList;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import sac.exception.InvalidArgumentException;
import sac.exception.ItemNaoCadastradoException;
import sac.exception.NullArgumentException;
import sac.persistencia.OID;
import sac.persistencia.PersistenceException;
import sac.pessoa.endereco.RepositorioEndereco;
import sac.pessoa.endereco.jdbc.DBEndereco;
import sac.pessoa.juridica.CNPJInvalidoException;
import sac.pessoa.juridica.PessoaJuridica;
import sac.pessoa.juridica.RepositorioOfertaTrabalho;
import sac.pessoa.juridica.jdbc.DBOfertaTrabalho;
import sac.pessoa.util.jdbc.DBRepository_Abstract;
import sac.pessoa.util.jdbc.PersistenteFactory;
import sac.pessoa.SenhaInvalidaException;

public class PersistenteFactory_PessoaJuridica extends DBRepository_Abstract implements PersistenteFactory {

    private final String preparedSelectEndereco =
             "select rel_pj_endereco.cd_endereco as id from rel_pj_endereco "+
             " where rel_pj_endereco.cd_pj = ? ";

    private final String preparedSelectRelOfertas =
             "select cd_oferta as id from rel_pj_oferta where cd_pj = ? ";

    private final String preparedSelectRelCategoria =
            "select nm_categoria, nm_sub_categoria "+
            "from rel_pj_categoria, categoria, sub_categoria " +
            "where rel_pj_categoria.cd_categoria = categoria.cd_categoria "+
            "and  rel_pj_categoria.cd_sub_categoria = sub_categoria.cd_sub_categoria "+
            "and rel_pj_categoria.cd_pj = ?";

    RepositorioEndereco repositorioendereco;
    RepositorioOfertaTrabalho repositoriooferta;


    public PersistenteFactory_PessoaJuridica() throws PersistenceException{
        // criar sistema de persistencia na classe pai.
        super();
        // cria factories
        repositorioendereco = DBEndereco.getInstancia();
        repositoriooferta = DBOfertaTrabalho.getInstancia();
    }

    public Object produce (Connection con, ResultSet rs) throws PersistenceException {
        try {
            PessoaJuridica pessoa = null;
            if (rs.next()){
                long id = rs.getLong("cd_pj");
                OID oid = new OID (id);
                String cnpj = rs.getString("tx_cnpj");
                String nome = rs.getString("nm_pj");
                String descricao_servico = rs.getString("ds_servicos");
                String inscricao_mun = rs.getString("tx_insc_municipal");
                String homepage = rs.getString("tx_homepage");
                String inscricao_est = rs.getString("tx_insc_estadual");
                String senha = rs.getString("tx_senha");

                List lstenderecos = selectEnderecos(id, con);
                Map mapCategorias = selectCategorias(id, con);
                List lstOfertas = selectOfertas(oid, con);

                pessoa = new PessoaJuridica ( nome, cnpj, senha , mapCategorias, inscricao_mun, lstenderecos);
                pessoa.setHomePage(homepage);
                pessoa.setInscricaoEstadual(inscricao_est);

                pessoa.setOferta(lstOfertas);
                pessoa.setServicosOferecidos(descricao_servico);
                pessoa.setId( oid);
            }

            return pessoa;
        } catch (NullArgumentException nulle) {
            throw new PersistenceException("Nao foi possivel criar Pessoa Juridica.", nulle);
        } catch(SQLException sqle){
            throw new PersistenceException ("Problemas no Banco", sqle );
        } catch ( CNPJInvalidoException cnpje){
            throw new PersistenceException ("CNPJ no banco invalido", cnpje );
        } catch (InvalidArgumentException ine) {
            throw new PersistenceException("Nao foi possivel criar Pessoa Juridica.", ine);
        } catch ( SenhaInvalidaException se){
            throw new PersistenceException ("Senha no banco invalida",se );
        }
    }

    private List selectEnderecos(long codigoPessoa, Connection con) throws SQLException, PersistenceException{
        List resposta = new ArrayList();
        PreparedStatement pre = createPreparedStatement(con, preparedSelectEndereco);
        pre.setLong(1, codigoPessoa);

        List listaCodEnderecos = (List) selectListFromBD(pre, getCodeFactory());
        try {
            for (int i = 0; i < listaCodEnderecos.size(); i++) {
                OID oidendereco  = (OID) listaCodEnderecos.get(i);
                resposta.add( repositorioendereco.procurar( oidendereco));
            }
            return resposta;
        } catch (ItemNaoCadastradoException iteme){
            throw new PersistenceException ("Problema no Banco", iteme );
        }
    }

    private Map selectCategorias(long codigoPessoa, Connection con) throws SQLException, PersistenceException{
        PreparedStatement pre = createPreparedStatement(con, preparedSelectRelCategoria);
        pre.setLong(1, codigoPessoa);

        Map resposta = new Hashtable();
        String strcategoria, strsubcategoria;
        ResultSet rs = pre.executeQuery();
        while (rs.next()){
          strcategoria = rs.getString("nm_categoria");
          strsubcategoria = rs.getString("nm_sub_categoria");
          if ( resposta.containsKey(strcategoria)){
            Set lst = (Set) resposta.get( strcategoria);
            lst.add(strsubcategoria);
          } else {
            Set lst = new HashSet();
            lst.add(strsubcategoria);
            resposta.put(strcategoria, lst);
          }
        }
        return resposta;
    }

    private List selectOfertas(OID oidPessoa, Connection con) throws SQLException, PersistenceException{
        List resposta = new ArrayList();
        PreparedStatement pre = createPreparedStatement(con, preparedSelectRelOfertas);
        pre.setLong(1, oidPessoa.getLongValue());

        List listaCodes = selectListFromBD(pre, getCodeFactory()) ;
        try {
            for (int i = 0; i < listaCodes.size(); i++) {
                OID oidOferta = (OID) listaCodes.get(i);
                resposta.add( repositoriooferta.procurar(oidOferta));
            }
            return resposta;
        } catch (ItemNaoCadastradoException iteme){
            throw new PersistenceException ("Problema no Banco", iteme );
        }
    }
}