package br.com.centralit.impressao;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import br.com.centralit.citajax.html.DocumentHTML;
import br.com.centralit.citcorpore.bean.CategoriaProblemaDTO;
import br.com.centralit.citcorpore.bean.ContratoDTO;
import br.com.centralit.citcorpore.bean.ProblemaBaseConhecimentoRelacionadoDTO;
import br.com.centralit.citcorpore.bean.ProblemaDTO;
import br.com.centralit.citcorpore.bean.ProblemaItemConfiguracaoDTO;
import br.com.centralit.citcorpore.bean.ProblemaJasperDTO;
import br.com.centralit.citcorpore.bean.ProblemaMudancaDTO;
import br.com.centralit.citcorpore.bean.ProblemaRelacionadoDTO;
import br.com.centralit.citcorpore.bean.SolicitacaoServicoDTO;
import br.com.centralit.citcorpore.bean.SolicitacaoServicoProblemaDTO;
import br.com.centralit.citcorpore.bean.SolucaoContornoDTO;
import br.com.centralit.citcorpore.bean.SolucaoDefinitivaDTO;
import br.com.centralit.citcorpore.bean.UsuarioDTO;
import br.com.centralit.citcorpore.negocio.CategoriaProblemaService;
import br.com.centralit.citcorpore.negocio.ContratoService;
import br.com.centralit.citcorpore.negocio.ProblemaBaseConhecimentoService;
import br.com.centralit.citcorpore.negocio.ProblemaItemConfiguracaoService;
import br.com.centralit.citcorpore.negocio.ProblemaMudancaService;
import br.com.centralit.citcorpore.negocio.ProblemaService;
import br.com.centralit.citcorpore.negocio.SolicitacaoServicoProblemaService;
import br.com.centralit.citcorpore.negocio.SolicitacaoServicoService;
import br.com.centralit.citcorpore.negocio.SolucaoContornoService;
import br.com.centralit.citcorpore.negocio.SolucaoDefinitivaService;
import br.com.centralit.citcorpore.util.CITCorporeUtil;
import br.com.centralit.citcorpore.util.Enumerados.ParametroSistema;
import br.com.centralit.citcorpore.util.LogoRel;
import br.com.centralit.citcorpore.util.ParametroUtil;
import br.com.centralit.citcorpore.util.UtilRelatorio;
import br.com.centralit.citcorpore.util.WebUtil;
import br.com.citframework.excecao.LogicException;
import br.com.citframework.excecao.ServiceException;
import br.com.citframework.service.ServiceLocator;
import br.com.citframework.util.Constantes;
import br.com.citframework.util.UtilDatas;
import br.com.citframework.util.UtilI18N;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.fill.JRAbstractLRUVirtualizer;
import net.sf.jasperreports.engine.fill.JRSwapFileVirtualizer;
import net.sf.jasperreports.engine.util.JRSwapFile;
import net.sf.jasperreports.engine.xml.JRXmlLoader;

/**
 * @author euler.ramos Classe que gera a impressão do cadastro de Problema
 */
public class ImpressaoCadProblema {

	private DocumentHTML document;
	private HttpServletRequest request;
	private ProblemaJasperDTO problemaJasperDTO;
	private ProblemaDTO problemaDTO;
	private UsuarioDTO usuarioDTO;

	private ProblemaService problemaService;

	private JRDataSource dataSource;
	private Map<String, Object> parametros;

	private String arquivoRelatorio;
	private String caminhoJasper;
	private String diretorioRelativo;
	private String diretorioTemp;
	private String jasperArqRel;

	public ImpressaoCadProblema(DocumentHTML document, HttpServletRequest request) throws Exception {
		super();
		this.document = document;
		this.request = request;
		this.usuarioDTO = WebUtil.getUsuario(this.request);
		this.problemaDTO = (ProblemaDTO) this.document.getBean();
		this.problemaService = (ProblemaService) ServiceLocator.getInstance().getService(ProblemaService.class, WebUtil.getUsuarioSistema(this.request));
	}

	public void gerarRelatorio() {
		if (this.usuarioDTO == null) {
			this.document.alert(UtilI18N.internacionaliza(this.request, "citcorpore.comum.sessaoExpirada"));
			this.document.executeScript("window.location = '" + Constantes.getValue("SERVER_ADDRESS") + this.request.getContextPath() + "'");
		} else {
			try {
				if (this.problemaDTO != null && this.problemaDTO.getIdProblema() != null && this.problemaDTO.getIdProblema().intValue() > 0) {
					this.geraImpressaoCadProblema();
				} else {
					this.document.alert(UtilI18N.internacionaliza(this.request, "problema.naoEncontrado"));
				}
				this.document.getJanelaPopupById("JANELA_AGUARDE_MENU").hide();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private void abreRelatorioPDF() {
		try {
			JRSwapFile arquivoSwap = new JRSwapFile(this.diretorioTemp, 4096, 25);
			JRAbstractLRUVirtualizer virtualizer = new JRSwapFileVirtualizer(25, arquivoSwap, true);
			this.parametros.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);

			final JasperDesign desenho = JRXmlLoader.load(this.caminhoJasper + this.jasperArqRel + ".jrxml");
			desenho.setLanguage("java");
			final JasperReport relatorio = JasperCompileManager.compileReport(desenho);

			JasperPrint print = JasperFillManager.fillReport(relatorio, parametros, dataSource);

			JasperExportManager.exportReportToPdfFile(print, this.diretorioTemp + this.arquivoRelatorio + ".pdf");

			this.document.executeScript("window.open('" + Constantes.getValue("SERVER_ADDRESS") + Constantes.getValue("CONTEXTO_APLICACAO") + "/printPDF/printPDF.jsp?url=" + this.diretorioRelativo
					+ this.arquivoRelatorio + ".pdf')");
		} catch (OutOfMemoryError e) {
			this.document.alert(UtilI18N.internacionaliza(this.request, "citcorpore.erro.erroServidor"));
		} catch (JRException e) {
			e.printStackTrace();
		}
	}

	private String buscarNumeroContrato() {
		if (this.problemaDTO.getIdContrato() != null && this.problemaDTO.getIdContrato().intValue() > 0) {
			try {
				ContratoService contratoService = (ContratoService) ServiceLocator.getInstance().getService(ContratoService.class, null);
				ContratoDTO contratoDTO = new ContratoDTO();
				contratoDTO.setIdContrato(this.problemaDTO.getIdContrato());
				contratoDTO = (ContratoDTO) contratoService.restore(contratoDTO);
				return contratoDTO.getNumero();
			} catch (LogicException | ServiceException e) {
				e.printStackTrace();
				return null;
			}
		}
		return null;
	}

	private String buscarNomeCategoria() {
		if (this.problemaDTO.getIdCategoriaProblema() != null && this.problemaDTO.getIdCategoriaProblema().intValue() > 0) {
			CategoriaProblemaService categoriaProblemaService;
			try {
				categoriaProblemaService = (CategoriaProblemaService) ServiceLocator.getInstance().getService(CategoriaProblemaService.class, null);
				CategoriaProblemaDTO categoriaProblemaDTO = new CategoriaProblemaDTO();
				categoriaProblemaDTO.setIdCategoriaProblema(this.problemaDTO.getIdCategoriaProblema());
				categoriaProblemaDTO = (CategoriaProblemaDTO) categoriaProblemaService.restore(categoriaProblemaDTO);
				return categoriaProblemaDTO.getNomeCategoria();
			} catch (LogicException | ServiceException e) {
				e.printStackTrace();
				return null;
			}
		}
		return null;
	}

	private void buscarICsRelacionados() throws ServiceException, Exception {
		ProblemaItemConfiguracaoService problemaItemConfiguracaoService = (ProblemaItemConfiguracaoService) ServiceLocator.getInstance().getService(ProblemaItemConfiguracaoService.class, null);
		@SuppressWarnings("unchecked")
		Collection<ProblemaItemConfiguracaoDTO> listaICs = problemaItemConfiguracaoService.findByIdProblema(this.problemaDTO.getIdProblema());
		JRDataSource dsICs = new JRBeanCollectionDataSource(listaICs);
		this.problemaJasperDTO.setListaICs(dsICs);
	}

	private void buscarMudancasRelacionadas() throws Exception {
		ProblemaMudancaService problemaMudancaService = (ProblemaMudancaService) ServiceLocator.getInstance().getService(ProblemaMudancaService.class, null);
		Collection<ProblemaMudancaDTO> listaMudancas = problemaMudancaService.findByIdProblema(this.problemaDTO.getIdProblema());
		if (listaMudancas != null && !listaMudancas.isEmpty()) {
			for (ProblemaMudancaDTO problemaMudancaDTO : listaMudancas) {
				problemaMudancaDTO.setDescrStatus(UtilI18N.internacionaliza(request, problemaMudancaDTO.getDescrStatus()));
			}
			JRDataSource dsMudancas = new JRBeanCollectionDataSource(listaMudancas);
			this.problemaJasperDTO.setListaMudancas(dsMudancas);
		}
	}

	private void buscarSolicitacoesRelacionadas() {
		try {
			SolicitacaoServicoProblemaService solicitacaoServicoProblemaService = (SolicitacaoServicoProblemaService) ServiceLocator.getInstance().getService(SolicitacaoServicoProblemaService.class,
					null);
			SolicitacaoServicoService solicitacaoServicoService;
			solicitacaoServicoService = (SolicitacaoServicoService) ServiceLocator.getInstance().getService(SolicitacaoServicoService.class, null);
			@SuppressWarnings("unchecked")
			Collection<SolicitacaoServicoProblemaDTO> listaSolicitacaoServico = solicitacaoServicoProblemaService.findByIdProblema(this.problemaDTO.getIdProblema());

			if (listaSolicitacaoServico != null && listaSolicitacaoServico.size() > 0) {
				for (SolicitacaoServicoProblemaDTO solicitacaoServicoProblemaDto : listaSolicitacaoServico) {
					SolicitacaoServicoDTO solicitacaoServicoDto = new SolicitacaoServicoDTO();
					if (solicitacaoServicoProblemaDto.getIdSolicitacaoServico() != null) {
						solicitacaoServicoDto = solicitacaoServicoService.restoreAll(solicitacaoServicoProblemaDto.getIdSolicitacaoServico());
					}

					if (solicitacaoServicoDto != null) {
						solicitacaoServicoProblemaDto.setNomeServico(solicitacaoServicoDto.getNomeServico());
						solicitacaoServicoProblemaDto.setDescricao(solicitacaoServicoDto.getDescricaoSemFormatacao());
					}
				}
			}
			JRDataSource dsSolicitacoes = new JRBeanCollectionDataSource(listaSolicitacaoServico);
			this.problemaJasperDTO.setListaSolicitacoes(dsSolicitacoes);
		} catch (Exception e) {
			e.printStackTrace();
			JRDataSource dsSolicitacoes = new JRBeanCollectionDataSource(null);
			this.problemaJasperDTO.setListaSolicitacoes(dsSolicitacoes);
		}
	}

	private void buscarSolucoesContorno() {
		SolucaoContornoDTO solucaoContorno = new SolucaoContornoDTO();
		try {
			SolucaoContornoService solucaoContornoService = (SolucaoContornoService) ServiceLocator.getInstance().getService(SolucaoContornoService.class, null);
			solucaoContorno.setIdProblema(this.problemaDTO.getIdProblema());
			solucaoContorno = solucaoContornoService.findByIdProblema(solucaoContorno);
		} catch (Exception e) {
			e.printStackTrace();
			solucaoContorno = null;
		}
		Collection<SolucaoContornoDTO> listaSolucaoContorno = null;
		if (solucaoContorno != null) {
			listaSolucaoContorno = new ArrayList<SolucaoContornoDTO>();
			listaSolucaoContorno.add(solucaoContorno);
		}
		JRDataSource dsSolucoesContorno = new JRBeanCollectionDataSource(listaSolucaoContorno);
		this.problemaJasperDTO.setListaSolucoesContorno(dsSolucoesContorno);
	}

	private void buscarSolucoesDefinitivas() {
		SolucaoDefinitivaDTO solucaoDefinitiva = new SolucaoDefinitivaDTO();
		try {
			SolucaoDefinitivaService solucaoDefinitivaService = (SolucaoDefinitivaService) ServiceLocator.getInstance().getService(SolucaoDefinitivaService.class, null);
			solucaoDefinitiva.setIdProblema(this.problemaDTO.getIdProblema());
			solucaoDefinitiva = solucaoDefinitivaService.findByIdProblema(solucaoDefinitiva);
		} catch (Exception e) {
			e.printStackTrace();
			solucaoDefinitiva = null;
		}
		Collection<SolucaoDefinitivaDTO> listaSolucaoDefinitiva = null;
		if (solucaoDefinitiva != null) {
			listaSolucaoDefinitiva = new ArrayList<SolucaoDefinitivaDTO>();
			listaSolucaoDefinitiva.add(solucaoDefinitiva);
		}
		JRDataSource dsSolucoesDefinitiva = new JRBeanCollectionDataSource(listaSolucaoDefinitiva);
		this.problemaJasperDTO.setListaSolucoesDefinitivas(dsSolucoesDefinitiva);
	}

	private void buscarErrosConhecidos() {
		ProblemaBaseConhecimentoService problemaBaseConhecimentoService;
		try {
			problemaBaseConhecimentoService = (ProblemaBaseConhecimentoService) ServiceLocator.getInstance().getService(ProblemaBaseConhecimentoService.class, null);
			ProblemaBaseConhecimentoRelacionadoDTO erroConhecido = problemaBaseConhecimentoService.getErroConhecidoByProblema(this.problemaDTO.getIdProblema());

			Collection<ProblemaBaseConhecimentoRelacionadoDTO> listaErrosConhecidos = null;
			if (erroConhecido != null) {
				listaErrosConhecidos = new ArrayList<ProblemaBaseConhecimentoRelacionadoDTO>();
				listaErrosConhecidos.add(erroConhecido);
			}
			JRDataSource dsErrosConhecidos = new JRBeanCollectionDataSource(listaErrosConhecidos);
			this.problemaJasperDTO.setListaErrosConhecidos(dsErrosConhecidos);
		} catch (Exception e) {
			e.printStackTrace();
			JRDataSource dsErrosConhecidos = new JRBeanCollectionDataSource(null);
			this.problemaJasperDTO.setListaErrosConhecidos(dsErrosConhecidos);
		}
	}

	private void buscarProblemasRelacionados() throws ServiceException, Exception {
		ProblemaRelacionadoDTO problemaRelacionadoDTO = new ProblemaRelacionadoDTO();
		problemaRelacionadoDTO.setIdProblema(this.problemaDTO.getIdProblema());
		@SuppressWarnings("rawtypes")
		Collection listaProblemas = this.problemaService.findByProblemaRelacionado(problemaRelacionadoDTO);
		JRDataSource dsProblemas = new JRBeanCollectionDataSource(listaProblemas);
		this.problemaJasperDTO.setListaProblemas(dsProblemas);
	}

	private void geraImpressaoCadProblema() throws ServiceException, Exception {
		// Obtendo informações do problema
		this.problemaDTO = this.problemaService.restoreAll(this.problemaDTO.getIdProblema());

		if (this.problemaDTO != null && this.problemaDTO.getIdProblema() != null && this.problemaDTO.getIdProblema() >= 0) {

			// O DTO de Problema não tem a capacidade de passar os JRDataSource necessários para a impressão das informações complementares, então,
			// Foi criado este objeto problemaJasperDTO para passar os objetos coleção: JRDataSource.
			this.problemaJasperDTO = new ProblemaJasperDTO();
			this.problemaJasperDTO.setIdProblema(this.problemaDTO.getIdProblema());
			this.problemaJasperDTO.setTitulo(this.problemaDTO.getTitulo());
			this.problemaJasperDTO.setContrato(this.buscarNumeroContrato());
			this.problemaJasperDTO.setDescrSituacao(UtilI18N.internacionaliza(request, this.problemaDTO.getDescrStatus()));
			this.problemaJasperDTO.setNomeSolicitante(this.problemaDTO.getSolicitante());
			this.problemaJasperDTO.setNomeProprietario(this.problemaDTO.getNomeProprietario());
			this.problemaJasperDTO.setNomeGrupoAtual(this.problemaDTO.getNomeGrupoAtual());
			this.problemaJasperDTO.setNomeCategoriaProblema(this.buscarNomeCategoria());
			this.problemaJasperDTO.setDataHoraInicio(this.problemaDTO.getDataHoraInicio());
			this.problemaJasperDTO.setDataHoraFim(this.problemaDTO.getDataHoraFim());
			this.problemaJasperDTO.setDataHoraCaptura(this.problemaDTO.getDataHoraCaptura());
			this.problemaJasperDTO.setDescricao(this.problemaDTO.getDescricao());
			this.problemaJasperDTO.setFechamento(this.problemaDTO.getFechamento());
			this.problemaJasperDTO.setAcoesRealizadasCorretamente(this.problemaDTO.getAcoesCorretas());
			this.problemaJasperDTO.setAcoesRealizadasIncorretamente(this.problemaDTO.getAcoesIncorretas());
			this.problemaJasperDTO.setPossiveisMelhoriasFuturas(this.problemaDTO.getMelhoriasFuturas());
			this.problemaJasperDTO.setComoPrevenirRecorrencia(this.problemaDTO.getRecorrenciaProblema());

			if (this.problemaDTO.getAcompanhamento() != null && this.problemaDTO.getAcompanhamento().equalsIgnoreCase("S")) {
				this.problemaJasperDTO.setNecessidadeAcompanhamento(UtilI18N.internacionaliza(request, "citcorpore.comum.sim"));
			} else {
				this.problemaJasperDTO.setNecessidadeAcompanhamento(UtilI18N.internacionaliza(request, "citcorpore.comum.nao"));
			}
			this.problemaJasperDTO.setResponsabilidadeTerceiros(this.problemaDTO.getResponsabilidadeTerceiros());
			this.problemaJasperDTO.setCausaRaiz(this.problemaDTO.getCausaRaiz());
			this.problemaJasperDTO.setMensagemErroAssociada(this.problemaDTO.getMsgErroAssociada());
			this.problemaJasperDTO.setDiagnostico(this.problemaDTO.getDiagnostico());

			// Alimentando as Informações Complementares da Mudança
			this.buscarICsRelacionados();
			this.buscarMudancasRelacionadas();
			this.buscarSolicitacoesRelacionadas();
			this.buscarSolucoesContorno();
			this.buscarSolucoesDefinitivas();
			this.buscarErrosConhecidos();
			this.buscarProblemasRelacionados();

			ArrayList<ProblemaJasperDTO> listaProblema = new ArrayList<ProblemaJasperDTO>();
			listaProblema.add(this.problemaJasperDTO);
			this.dataSource = new JRBeanCollectionDataSource(listaProblema);

			// Alimentando os parâmetros com informações adicionais sobre a impressão para serem mostradas no relatório
			this.alimentaParametros(UtilI18N.internacionaliza(this.request, "problema.numero"));

			// Configurando dados para geração do Relatório
			Date dt = new Date();
			String strMiliSegundos = Long.toString(dt.getTime());
			this.jasperArqRel = "cadastroProblema";
			this.caminhoJasper = CITCorporeUtil.CAMINHO_REAL_APP + Constantes.getValue("CAMINHO_RELATORIOS");
			this.diretorioTemp = CITCorporeUtil.CAMINHO_REAL_APP + "/tempFiles";
			this.diretorioRelativo = Constantes.getValue("SERVER_ADDRESS") + Constantes.getValue("CONTEXTO_APLICACAO") + "/tempFiles";
			this.arquivoRelatorio = "/" + this.jasperArqRel + strMiliSegundos + "_" + this.usuarioDTO.getIdUsuario();

			// Chamando o relatório
			this.abreRelatorioPDF();
		} else {
			this.document.alert(UtilI18N.internacionaliza(this.request, "citcorpore.comum.relatorioVazio"));
		}
	}

	private void alimentaParametros(String titulo) throws ServiceException, Exception {
		HttpSession session = this.request.getSession();
		this.parametros = new HashMap<String, Object>();
		this.parametros = UtilRelatorio.trataInternacionalizacaoLocale(session, this.parametros);
		this.parametros.put("TITULO_RELATORIO", titulo);
		this.parametros.put("CIDADE", getCidadeParametrizada(request));
		this.parametros.put("DATA_HORA", UtilDatas.getDataHoraAtual());
		this.parametros.put("Logo", LogoRel.getFile());
		this.parametros.put("NOME_USUARIO", this.usuarioDTO.getNomeUsuario());
		this.parametros.put("SUBREPORT_DIR", CITCorporeUtil.CAMINHO_REAL_APP + Constantes.getValue("CAMINHO_RELATORIOS"));
	}


    /**
     * Método retorna a cidade onde o sistema foi instalado, é um parametro que dece ser configurado. Caso não seja informado
     * o mesmo retorna a cidade de Brasilia.
	 * defeito-2287 - AjaxFormAction.java_(#getCidadeParametrizada).
	 *
	 * @since 21/12/2015
	 * @author ibimon.morais
     */
    public String getCidadeParametrizada(final HttpServletRequest request) throws Exception{
    	String cidadeRelatorio = ParametroUtil.getValor(ParametroSistema.CIDADE_LOCALIDADE);
    	if(cidadeRelatorio == null || "".equals(cidadeRelatorio)){
    		cidadeRelatorio = UtilI18N.internacionaliza(request, "citcorpore.comum.relatorioCidade");
    	}
		return cidadeRelatorio;
    }

}