/*******************************************************************************
 * This file is part of Educatio.
 *
 *     Educatio is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     Educatio is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with Educatio.  If not, see <http://www.gnu.org/licenses/>.
 *     
 *     Authors:
 *           Filipe Marinho de Brito - filipe.marinho.brito@gmail.com
 *           Rodrigo de Souza Ataides - rodrigoataides@gmail.com
 *******************************************************************************/
package br.com.core.business.persistencia; 

import java.util.*;

import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.*;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.AccessDeniedException;
import br.com.core.jdbc.dao.pessoa.PessoaRepository;
import br.com.core.jdbc.dao.edital.CandidatoSelecaoRepository;
import br.com.core.jdbc.dao.edital.SelecaoRepository;

import br.com.core.jdbc.dao.edital.SelecaoTable;
import br.com.core.conversor.CandidatoSelecaoConversor;
import br.com.core.jdbc.dao.pessoa.PessoaTable;
import br.com.core.conversor.SelecaoConversor;
import br.com.core.conversor.PessoaConversor;
import br.com.core.jdbc.dao.edital.CandidatoSelecaoTable;
import br.com.core.modelo.pessoa.Pessoa;
import br.com.core.modelo.edital.CandidatoSelecao;
import br.com.core.modelo.edital.Selecao;

@Service
public class CandidatoSelecaoPersistenciaBusiness {

	@Autowired
	PessoaRepository pessoaRepository;
	@Autowired
	CandidatoSelecaoRepository candidatoSelecaoRepository;
	@Autowired
	SelecaoRepository selecaoRepository;
	@Autowired
	SelecaoPersistenciaBusiness selecaoPersistenciaBusiness;
	@Autowired
	PessoaPersistenciaBusiness pessoaPersistenciaBusiness;

	@Transactional(readOnly = true, propagation=Propagation.NESTED)
	//@PostAuthorize("hasPermission(returnObject, 'READ')")
	public CandidatoSelecao find(Long id){
		return find(new CandidatoSelecao(id));
	}

	@Transactional(readOnly = true, propagation=Propagation.NESTED)
	//@PostAuthorize("hasPermission(returnObject, 'READ')")
	public CandidatoSelecao find(CandidatoSelecao candidatoSelecao){
		if(candidatoSelecao!=null && candidatoSelecao.getId()!=null){
			CandidatoSelecaoTable candidatoSelecaoTable  = candidatoSelecaoRepository.findOne(candidatoSelecao.getId()); 
			candidatoSelecao = CandidatoSelecaoConversor.converterTabelaParaModelo(candidatoSelecaoTable);
			try{candidatoSelecao.setSelecao(selecaoPersistenciaBusiness.findForCandidatoSelecao(candidatoSelecao.getSelecao()));}catch(AccessDeniedException ade){ }
			try{candidatoSelecao.setPessoa(pessoaPersistenciaBusiness.find(candidatoSelecao.getPessoa()));}catch(AccessDeniedException ade){ }
		}
		return candidatoSelecao;
	}

	@Transactional(readOnly = true, propagation=Propagation.NESTED)
	//@PostFilter("hasPermission(filterObject, 'READ')")
	public List<CandidatoSelecao> findBySelecao(Selecao selecao){
		List<CandidatoSelecao> retorno = new ArrayList<CandidatoSelecao>();
		for(CandidatoSelecaoTable candidatoSelecaoTable : candidatoSelecaoRepository.findBySelecao(selecao.getId())){
			retorno.add(find(CandidatoSelecaoConversor.converterTabelaParaModelo(candidatoSelecaoTable)));
		}
		 return retorno;
	}

	@Transactional(readOnly = true, propagation=Propagation.NESTED)
	//@PostFilter("hasPermission(filterObject, 'READ')")
	public List<CandidatoSelecao> findByPessoa(Pessoa pessoa){
		List<CandidatoSelecao> retorno = new ArrayList<CandidatoSelecao>();
		for(CandidatoSelecaoTable candidatoSelecaoTable : candidatoSelecaoRepository.findByPessoa(pessoa.getId())){
			retorno.add(find(CandidatoSelecaoConversor.converterTabelaParaModelo(candidatoSelecaoTable)));
		}
		 return retorno;
	}

	@Transactional(readOnly = true, propagation=Propagation.NESTED)
	//@PostFilter("hasPermission(filterObject, 'READ')")
	public List<CandidatoSelecao> findBySelecaoOtimizado(Selecao selecao){
		List<CandidatoSelecao> retorno = new ArrayList<CandidatoSelecao>();
		for(CandidatoSelecaoTable candidatoSelecaoTable : candidatoSelecaoRepository.findBySelecao(selecao.getId())){
			retorno.add(CandidatoSelecaoConversor.converterTabelaParaModelo(candidatoSelecaoTable));
		}
		return retorno;
	}

	@Transactional(readOnly = true, propagation=Propagation.NESTED)
	//@PostFilter("hasPermission(filterObject, 'READ')")
	public List<CandidatoSelecao> findBySelecaoAndStatusProposta(Selecao selecao){
		List<CandidatoSelecao> retorno = new ArrayList<CandidatoSelecao>();
		for(CandidatoSelecaoTable candidatoSelecaoTable : candidatoSelecaoRepository.findBySelecaoAndStatusProposta(selecao.getId())){
			retorno.add(find(CandidatoSelecaoConversor.converterTabelaParaModelo(candidatoSelecaoTable)));
		}
		return retorno;
	}

	@Transactional(readOnly = true, propagation=Propagation.NESTED)
	//@PostFilter("hasPermission(filterObject, 'READ')")
	public CandidatoSelecao findByPessoaAndSelecaoStatusProposta(Pessoa pessoa, Selecao selecao){
		CandidatoSelecaoTable candidatoSelecaoTable = null; 
		try{ 
			candidatoSelecaoTable =  candidatoSelecaoRepository.findByPessoaAndSelecaoStatusProposta(pessoa.getId(), selecao.getId());
//			return 	find(CandidatoSelecaoConversor.converterTabelaParaModelo(candidatoSelecaoTable));
			return 	CandidatoSelecaoConversor.converterTabelaParaModelo(candidatoSelecaoTable);
		}catch(Exception e){
			return null;
		} 
		
	}

	@Transactional(readOnly = true, propagation=Propagation.NESTED)
	//@PostFilter("hasPermission(filterObject, 'READ')")
	public CandidatoSelecao findByPessoaAndSelecao(Pessoa pessoa, Selecao selecao){
		CandidatoSelecaoTable candidatoSelecaoTable = null; 
		try{ 
			candidatoSelecaoTable =  candidatoSelecaoRepository.findByPessoaAndSelecao(pessoa.getId(), selecao.getId());
			return 	find(CandidatoSelecaoConversor.converterTabelaParaModelo(candidatoSelecaoTable));
		}catch(Exception e){
			return null;
		} 
		
	}

	/*
	 * metodo otimizado para tela de selecaos
	 */
	@Transactional(readOnly = true, propagation=Propagation.NESTED)
	//@PostFilter("hasPermission(filterObject, 'READ')")
	public CandidatoSelecao findByPessoaAndSelecaoOtimizado(Pessoa pessoa, Selecao selecao){
		CandidatoSelecaoTable candidatoSelecaoTable = null; 
		try{ 
			candidatoSelecaoTable =  candidatoSelecaoRepository.findByPessoaAndSelecao(pessoa.getId(), selecao.getId());
			return 	CandidatoSelecaoConversor.converterTabelaParaModelo(candidatoSelecaoTable);
		}catch(Exception e){
			return null;
		} 
		
	}

	@Transactional(readOnly = true, propagation=Propagation.NESTED)
	public Boolean existsByPessoaAndSelecao(Pessoa pessoa, Selecao selecao){
		return candidatoSelecaoRepository.existByPessoaAndSelecao(pessoa.getId(), selecao.getId());
	}

	@Transactional(readOnly = true, propagation=Propagation.NESTED)
	//@PostFilter("hasPermission(filterObject, 'READ')")
	public List<CandidatoSelecao> findAll(){
		List<CandidatoSelecao> retorno = new ArrayList<CandidatoSelecao>();
		List<CandidatoSelecaoTable> all = candidatoSelecaoRepository.findAll();
		for(CandidatoSelecaoTable itemTable : all){
			CandidatoSelecao item = find(itemTable.getId());
			 retorno.add(item);
		}
		 return retorno;
	}

	@Transactional(readOnly = true, propagation=Propagation.NESTED)
	//@PostFilter("hasPermission(filterObject, 'READ')")
	public List<CandidatoSelecao> findForCombo(){
		List<CandidatoSelecao> retorno = new ArrayList<CandidatoSelecao>();
		List<CandidatoSelecaoTable> all = candidatoSelecaoRepository.findAll();
		for(CandidatoSelecaoTable itemTable : all){
			 retorno.add(CandidatoSelecaoConversor.converterTabelaParaModelo(itemTable));
		}
		 return retorno;
	}

	@Transactional(rollbackFor=Throwable.class, propagation=Propagation.NESTED)
	//@PreAuthorize("hasPermission(#candidatoSelecao, 'CREATE')")
	public CandidatoSelecao save(CandidatoSelecao candidatoSelecao){

		if(candidatoSelecao!=null ){
			//o campo Selecao foi salvo apenas como referencia  pois o cascade nao foi declarado
			//o campo Pessoa foi salvo apenas como referencia  pois o cascade nao foi declarado
			CandidatoSelecaoTable candidatoSelecaoTable  = CandidatoSelecaoConversor.converterModeloParaTabela(candidatoSelecao); 
			candidatoSelecaoRepository.save(candidatoSelecaoTable);
			candidatoSelecao.setId(candidatoSelecaoTable.getId());
		}
		return candidatoSelecao;

	}

	@Transactional(rollbackFor=Throwable.class,propagation=Propagation.NESTED)
	public List<CandidatoSelecao> save( List<CandidatoSelecao> colecao){
		List<CandidatoSelecao> retorno = new ArrayList<CandidatoSelecao>();
		for(CandidatoSelecao item : colecao){
			 retorno.add(save(item));
		}
		 return retorno;
	}

	@Transactional(rollbackFor=Throwable.class, propagation=Propagation.NESTED)
	//@PreAuthorize("hasPermission(#candidatoSelecao, 'WRITE')")
	public void update(CandidatoSelecao candidatoSelecao){

		CandidatoSelecaoTable candidatoSelecaoTable  = CandidatoSelecaoConversor.converterModeloParaTabela(candidatoSelecao); 
		candidatoSelecaoRepository.save(candidatoSelecaoTable);

	}

	@Transactional(rollbackFor=Throwable.class, propagation=Propagation.NESTED)
	//@PreAuthorize("hasPermission(#candidatoSelecao, 'DELETE')")
	public void delete(CandidatoSelecao candidatoSelecao){

		if(candidatoSelecao!=null && candidatoSelecao.getId()!=null){
			CandidatoSelecaoTable candidatoSelecaoTable  = CandidatoSelecaoConversor.converterModeloParaTabela(candidatoSelecao); 
			candidatoSelecaoRepository.delete(candidatoSelecaoTable);
			//o objeto Selecao nao serah removido junto pois nao esta com anotacao cascade
			//o objeto Pessoa nao serah removido junto pois nao esta com anotacao cascade
		}

	}

	@Transactional(rollbackFor=Throwable.class, propagation=Propagation.NESTED)
	public void delete( List<CandidatoSelecao> colecao){
		if(colecao!=null){
			for(CandidatoSelecao item : colecao){
				 delete(item);
			}
		}
	}

}
