package br.com.centralit.citcorpore.negocio;

import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collection;

import br.com.centralit.citajax.html.DocumentHTML;
import br.com.centralit.citcorpore.bean.EsquemaDadosDTO;
import br.com.centralit.citcorpore.bean.UploadDTO;
import br.com.centralit.citcorpore.integracao.EsquemaDadosDao;
import br.com.centralit.citcorpore.util.CriptoUtils;
import br.com.centralit.citcorpore.util.Enumerados;
import br.com.centralit.citcorpore.util.Enumerados.SimNao;
import br.com.centralit.citcorpore.util.ParametroUtil;
import br.com.centralit.citcorpore.util.Util;
import br.com.centralit.citged.bean.ControleGEDDTO;
import br.com.centralit.citged.integracao.ControleGEDDao;
import br.com.citframework.excecao.LogicException;
import br.com.citframework.excecao.PersistenceException;
import br.com.citframework.excecao.ServiceException;
import br.com.citframework.integracao.TransactionControler;
import br.com.citframework.integracao.TransactionControlerImpl;
import br.com.citframework.service.CrudServiceImpl;
import br.com.citframework.util.Constantes;
import br.com.citframework.util.UtilDatas;

/**
 * @author douglas.japiassu
 * @since 21.10.2015
 */
@SuppressWarnings("unchecked")
public class EsquemaDadosServiceEjb extends CrudServiceImpl implements EsquemaDadosService {
	private static final String DIRETORIO_PADRAO = "1";
	private static final String EXTENSAO_GED = ".ged";
	private static final String FS = System.getProperty("file.separator");
	
	private EsquemaDadosDao dao;
	private ControleGEDDao controleGEDDao;

	@Override
	protected EsquemaDadosDao getDao() {
		if (this.dao == null) {
			this.dao = new EsquemaDadosDao();
		}
		return this.dao;
	}

	@Override
	public Collection<EsquemaDadosDTO> findByIdServicoNegocio(final Integer idServicoNegocio) throws PersistenceException {
		return this.getDao().findByIdServicoNegocio(idServicoNegocio);
	}

	@Override
	public EsquemaDadosDTO salvar(EsquemaDadosDTO esquemaDadosDTO) throws PersistenceException {
		final TransactionControler tc = new TransactionControlerImpl(this.getDao().getAliasDB());
		try {
			tc.start();
			this.validaCreate(esquemaDadosDTO);
			esquemaDadosDTO = this.executarAcaoSalvar(esquemaDadosDTO, tc);
			tc.commit();
		} catch (final Exception e) {
			e.printStackTrace();
			try {
				this.rollbackTransaction(tc, e);
			} catch (ServiceException | LogicException e1) {
				e1.printStackTrace();
			}
			tc.close();
		}
		
		return esquemaDadosDTO;
	}

	private EsquemaDadosDTO executarAcaoSalvar(EsquemaDadosDTO esquemaDadosDTO, final TransactionControler tc)
			throws PersistenceException, Exception {
		
		if (esquemaDadosDTO.getIdEsquemaDados() != null && esquemaDadosDTO.getIdEsquemaDados().intValue() > 0) {
			if (this.isServicoExiste(esquemaDadosDTO.getIdServicoNegocio())) {
				this.getDao().update(esquemaDadosDTO);
			}
		} else {
			esquemaDadosDTO = (EsquemaDadosDTO) this.getDao().create(esquemaDadosDTO);
		}
		
		if (esquemaDadosDTO != null && esquemaDadosDTO.getColsUploadGED() != null && !esquemaDadosDTO.getColsUploadGED().isEmpty()) {
			this.gravarInformacaoGED(esquemaDadosDTO, tc);
		}
		
		return esquemaDadosDTO;
	}

	private void gravarInformacaoGED(final EsquemaDadosDTO esquemaDadosDTO, final TransactionControler tc) throws Exception {
		this.definirTransacao(tc);
		this.tratarListaDeArquivoGED(esquemaDadosDTO);
	}

	private void tratarListaDeArquivoGED(final EsquemaDadosDTO esquemaDadosDTO) throws Exception {
		final String pasta = this.definirDiretorioGed(esquemaDadosDTO);
		
		for (final UploadDTO uploadDTO : esquemaDadosDTO.getColsUploadGED()) {
			if (uploadDTO.getTemporario().equals(SimNao.SIM.getValorStr())) {
				ControleGEDDTO controleGEDDTO = new ControleGEDDTO();
				
				this.definirControleGED(esquemaDadosDTO, pasta, uploadDTO, controleGEDDTO);
				this.definirPathArquivo(uploadDTO, controleGEDDTO);
				this.salvarSetarControleGED(uploadDTO, controleGEDDTO);
				this.criarGEDInternoBD(uploadDTO, controleGEDDTO);
			}
		}
	}

	/**
	 * Cria o arquivo no diretório, faz a encriptação do mesmo e depois o deleta.
	 * 
	 * @param esquemaDadosDTO
	 * @param uploadDTO
	 * @param controleGEDDTO
	 * @throws Exception
	 * 
	 * @author douglas.japiassu
	 * @since 21.10.2015
	 */
	private void criarGEDInternoBD(final UploadDTO uploadDTO, final ControleGEDDTO controleGEDDTO) throws Exception {
		if (getGedInternoBD().equalsIgnoreCase(SimNao.NAO.getValorStr())) {
			if (controleGEDDTO != null) {
				try {
					String caminho = getGedDiretorio().concat(FS).concat(DIRETORIO_PADRAO).concat(FS)
							.concat(controleGEDDTO.getPasta()).concat(FS).concat(String.valueOf(controleGEDDTO.getIdControleGED()));
					
					final File arquivo = new File(caminho.concat(".").concat(Util.getFileExtension(uploadDTO.getNameFile())));
					
					CriptoUtils.encryptFile(uploadDTO.getPath(),
							caminho.concat(EXTENSAO_GED), 
							((String) System.getProperties().get("user.dir")).concat(Constantes.getValue("CAMINHO_CHAVE_PUBLICA")));
					
					arquivo.delete();
				} catch (ClassNotFoundException | IOException | GeneralSecurityException e) {
					e.printStackTrace();
				}
			}
		}
		
	}

	private void salvarSetarControleGED(final UploadDTO uploadDTO, 
			ControleGEDDTO controleGEDDTO) throws PersistenceException {
		controleGEDDTO = (ControleGEDDTO) getControleGEDDao().create(controleGEDDTO);
		uploadDTO.setIdControleGED(controleGEDDTO.getIdControleGED());
	}

	private void definirPathArquivo(final UploadDTO uploadDTO, final ControleGEDDTO controleGEDDTO) {
		if (SimNao.SIM.getValorStr().equalsIgnoreCase(getGedInterno().trim()) && SimNao.SIM.getValorStr().equalsIgnoreCase(getGedInternoBD().trim())) {
			controleGEDDTO.setPathArquivo(uploadDTO.getPath());
		} else {
			controleGEDDTO.setPathArquivo(null);
		}
	}

	private void definirControleGED(final EsquemaDadosDTO esquemaDadosDTO, final String pasta, final UploadDTO uploadDTO,
			final ControleGEDDTO controleGEDDTO) {
		controleGEDDTO.setIdTabela(ControleGEDDTO.TABELA_ESQUEMA_DADOS);
		controleGEDDTO.setId(esquemaDadosDTO.getIdEsquemaDados());
		controleGEDDTO.setDataHora(UtilDatas.getDataAtual());
		controleGEDDTO.setDescricaoArquivo(uploadDTO.getDescricao());
		controleGEDDTO.setExtensaoArquivo(Util.getFileExtension(uploadDTO.getNameFile()));
		controleGEDDTO.setPasta(pasta);
		controleGEDDTO.setNomeArquivo(uploadDTO.getNameFile());
	}
	
	@Override
	public void removerAnexosDiretorioGed(final DocumentHTML document, EsquemaDadosDTO esquemaDadosDTO) throws PersistenceException {
		final TransactionControler tc = new TransactionControlerImpl(this.getDao().getAliasDB());
		try {
			this.deletarArquivos(document, esquemaDadosDTO, tc);
		} catch (final Exception e) {
			e.printStackTrace();
			try {
				this.rollbackTransaction(tc, e);
			} catch (ServiceException | LogicException e1) {
				e1.printStackTrace();
			}
			tc.close();
		}

	}
	
	private void deletarArquivos(final DocumentHTML document, EsquemaDadosDTO esquemaDadosDTO, final TransactionControler tc) throws Exception {
		if (esquemaDadosDTO.getColsUploadGEDExcluidos() != null && !esquemaDadosDTO.getColsUploadGEDExcluidos().isEmpty()) {
			final String gedDiretorio = this.getGedDiretorio();
			
			for (final String valorId : esquemaDadosDTO.getColsUploadGEDExcluidos()) {
				if (valorId.startsWith("ID=")) {
					tc.start();
					this.definirTransacao(tc);
					
					ControleGEDDTO controleGEDDTO = new ControleGEDDTO();
					controleGEDDTO.setIdControleGED(this.obterIdParaExclusaoGed(valorId));
					controleGEDDTO = (ControleGEDDTO) this.getControleGEDDao().restore(controleGEDDTO);
					this.getControleGEDDao().delete(controleGEDDTO);

					final File arquivo = new File(gedDiretorio.concat(FS).concat(DIRETORIO_PADRAO).concat(FS)
							.concat(controleGEDDTO.getPasta()).concat(FS).concat(String.valueOf(controleGEDDTO.getIdControleGED()))
							.concat(EXTENSAO_GED));
					
					this.deleteDir(arquivo);
					tc.commit();
					document.executeScript("parent.reloadAnexosEsquemaDados();");
				} else {
					final File arquivoTemporario = new File(valorId);
					
					this.deleteDir(arquivoTemporario);
				}
			}
		}
	}

	private boolean deleteDir(final File dir) {
		if (dir.isDirectory()) {
			final String[] children = dir.list();
			for (final String element : children) {
				final boolean success = this.deleteDir(new File(dir, element));
				if (!success) {
					return false;
				}
			}
		}
		
		return dir.delete();
	}

	private Integer obterIdParaExclusaoGed(final String strParaVerificar) {
		Integer idParaExclusao = null;
		
		final String[] strParaVerificarArray = strParaVerificar.split("=");
		
		if (strParaVerificarArray[1] != null) {
			idParaExclusao = Integer.valueOf(strParaVerificarArray[1].toString());
		}
		
		return idParaExclusao;
	}

	private String definirDiretorioGed(final EsquemaDadosDTO esquemaDadosDTO)
			throws Exception {
		String pasta = "";

		if (getGedInterno().equalsIgnoreCase(SimNao.SIM.getValorStr())) {
			pasta = getControleGEDDao().getProximaPastaArmazenar();

			File fileDir = new File(getGedDiretorio());
			if (!fileDir.exists()) {
				fileDir.mkdirs();
			}

			fileDir = new File(getGedDiretorio().concat(FS).concat(DIRETORIO_PADRAO));
			if (!fileDir.exists()) {
				fileDir.mkdirs();
			}

			fileDir = new File(getGedDiretorio().concat(FS).concat(DIRETORIO_PADRAO).concat(FS).concat(pasta));
			if (!fileDir.exists()) {
				fileDir.mkdirs();
			}
		}
		
		return pasta;
	}

	private String getGedInternoBD() {
		String gedInternoBancoDados = ParametroUtil.getValorParametroCitSmartHashMap(Enumerados.ParametroSistema.GedInternoBD,
				SimNao.NAO.getValorStr());
		
		return gedInternoBancoDados;
	}

	private String getGedInterno() {
		String gedInterno = ParametroUtil.getValorParametroCitSmartHashMap(Enumerados.ParametroSistema.GedInterno, 
				SimNao.SIM.getValorStr());
		
		return gedInterno;
	}

	private String getGedDiretorio() throws Exception {
		final String gedDiretorio = ParametroUtil.getValorParametroCitSmartHashMap(Enumerados.ParametroSistema.GedDiretorio, "");
		if ("".equals(gedDiretorio.trim())) {
			throw new Exception("Diretório Não Informado.");
		}
		return gedDiretorio;
	}

	private void definirTransacao(final TransactionControler tc) {
		if (tc != null) {
			getControleGEDDao().setTransactionControler(tc);
		}
	}

	private boolean isServicoExiste(final Integer idServico) throws PersistenceException {
		final Collection<EsquemaDadosDTO> colEsquemaDados = this.findByIdServicoNegocio(idServico);
		return (colEsquemaDados != null && !colEsquemaDados.isEmpty()) ? Boolean.TRUE : Boolean.FALSE;
	}
	
	private ControleGEDDao getControleGEDDao() {
		if (controleGEDDao == null) {
			controleGEDDao = new ControleGEDDao();
		}
		
		return controleGEDDao;
	}
	
}