package com.ejie.ab04b.control;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import com.ejie.ab04b.constantes.Constantes;
import com.ejie.ab04b.exception.AB04BException;
import com.ejie.ab04b.exception.ErrorGenericoException;
import com.ejie.ab04b.model.VimpresionDoc;
import com.ejie.ab04b.service.GeneracionEtiquetasService;
import com.ejie.ab04b.service.VimpresionDocService;
import com.ejie.ab04b.service.dokusi.DokusiService;
import com.ejie.ab04b.service.pif.PifService;
import com.ejie.ab04b.util.PropertiesUtil;
import com.ejie.ab04b.util.seguridad.UtilSeguridad;
import com.ejie.t65.jaxb.beans.fsd.T65BDocumentType;
import com.ejie.t65.jaxb.beans.fsd.T65BStringListType;
import com.ejie.x38.control.bind.annotation.RequestJsonBody;
import com.ejie.x38.dto.JQGridRequestDto;
import com.ejie.x38.dto.JQGridResponseDto;
import com.ejie.x38.dto.TableRowDto;

/**
 * VimpresionDocController generated by UDA, 05-sep-2017 8:53:45.
 * 
 * @author UDA
 */

@Controller()
@RequestMapping(value = "/vimpresiondoc")
public class VimpresionDocController {

	private static final Logger logger = LoggerFactory
			.getLogger(VimpresionDocController.class);

	private static final String PARAM_DOWNLOAD_FILE_PATH = "pathDownloadFile";
	private static final String PARAM_LIST_FILE_DELETE = "listFileDelete";

	public static final Long TIPO_REQUERIMIENTO_APERTURAS = (long) 1;
	public static final Long TIPO_COMUNICACION_OS2 = (long) 11;
	public static final Long TIPO_COMUNICACION_OS3 = (long) 12;

	private static final String FILE_DEST_SUFIX = "FINAL.pdf";

	@Autowired()
	private VimpresionDocService vimpresionDocService;

	@Autowired()
	private DokusiService dokusiService;

	@Autowired()
	private PifService pifService;

	@Autowired()
	private GeneracionEtiquetasService generacionEtiquetasService;

	/**
	 * Usamos este mÃ©todo para indicarle a Spring el formato que debe usar para
	 * serializar las fechas cuando cargamos la entidad en el Model. En el resto
	 * de peticiones que devuelven un objeto con la anotaciÃ³n '@ResponseBody'
	 * se usan los serializadores de UDA
	 * 
	 *  binder
	 *            WebDataBinder
	 *
	 * @param binder the binder
	 */
	@InitBinder()
	public void initBinder(WebDataBinder binder) {

		Locale locale = LocaleContextHolder.getLocale();
		DateFormat dateFormat = null;
		if (locale.equals(Constantes.LOCALE_ES)) {
			dateFormat = new SimpleDateFormat(Constantes.ES_DATE_MASK);
		} else {
			dateFormat = new SimpleDateFormat(Constantes.EU_DATE_MASK);
		}
		binder.registerCustomEditor(Date.class, new CustomDateEditor(
				dateFormat, true));
	}

	/*
	 * OPERACIONES CRUD (Create, Read, Update, Delete)
	 */

	/**
	 * Operacion CRUD Read. Devuelve el bean correspondiente al identificador
	 * indicado.
	 * 
	 *  tipo
	 *            String
	 *  ter
	 *            String
	 *  ano
	 *            String
	 *  num
	 *            Integer
	 *  idtram
	 *            Long
	 *  tipotram
	 *            Long
	 *  procedure
	 *            String
	 *  fecpre
	 *            Date
	 *
	 * @param tipo the tipo
	 * @param ter the ter
	 * @param ano the ano
	 * @param num the num
	 * @param idtram the idtram
	 * @param tipotram the tipotram
	 * @param procedure the procedure
	 * @param fecpre the fecpre
	 *  VimpresionDoc Objeto correspondiente al identificador indicado.
	 * @return the vimpresion doc
	 */
	@RequestMapping(value = "/{tipo}/{ter}/{ano}/{num}/{idtram}/{tipotram}/{procedure}/{fecpre}", method = RequestMethod.GET)
	public @ResponseBody
	VimpresionDoc get(@PathVariable String tipo, @PathVariable String ter,
			@PathVariable String ano, @PathVariable Integer num,
			@PathVariable Long idtram, @PathVariable Long tipotram,
			@PathVariable String procedure, @PathVariable Date fecpre) {
		VimpresionDoc vimpresionDoc = new VimpresionDoc();
		vimpresionDoc.setTipo(tipo);
		vimpresionDoc.setTer(ter);
		vimpresionDoc.setAnio(ano);
		vimpresionDoc.setNum(num);
		vimpresionDoc.setIdtram(idtram);
		vimpresionDoc.setTipotram(tipotram);
		vimpresionDoc.setProcedure(procedure);
		vimpresionDoc.setFecpre(fecpre);
		vimpresionDoc = this.vimpresionDocService.find(vimpresionDoc);
		VimpresionDocController.logger
				.info("[GET - findBy_PK] : Obtener VimpresionDoc por PK");
		return vimpresionDoc;
	}

	/**
	 * Devuelve una lista de beans correspondientes a los valores de filtrados
	 * indicados en el objeto pasado como parametro.
	 * 
	 *  filterVimpresionDoc
	 *            VimpresionDoc Objeto que contiene los parametros de filtrado
	 *            utilizados en la busqueda.
	 *
	 * @param filterVimpresionDoc the filter vimpresion doc
	 *  List<VimpresionDoc> Lista de objetos correspondientes a la
	 *         busqueda realizada.
	 * @return the all
	 */
	@RequestMapping(method = RequestMethod.GET)
	public @ResponseBody
	List<VimpresionDoc> getAll(@ModelAttribute VimpresionDoc filterVimpresionDoc) {
		VimpresionDocController.logger
				.info("[GET - find_ALL] : Obtener VimpresionDoc por filtro");
		return this.vimpresionDocService.findAll(filterVimpresionDoc, null);
	}

	/**
	 * Operacion CRUD Edit. Modificacion del bean indicado.
	 * 
	 *  vimpresionDoc
	 *            VimpresionDoc Bean que contiene la informacion a modificar.
	 *
	 * @param vimpresionDoc the vimpresion doc
	 *  VimpresionDoc Bean resultante de la modificacion.
	 * @return the vimpresion doc
	 */
	@RequestMapping(method = RequestMethod.PUT)
	public @ResponseBody
	VimpresionDoc edit(@RequestBody VimpresionDoc vimpresionDoc) {
		VimpresionDoc vimpresionDocAux = this.vimpresionDocService
				.update(vimpresionDoc);
		VimpresionDocController.logger
				.info("[PUT] : VimpresionDoc actualizado correctamente");
		return vimpresionDocAux;
	}

	/**
	 * Operacion CRUD Create. Creacion de un nuevo registro a partir del bean
	 * indicado.
	 * 
	 *  vimpresionDoc
	 *            VimpresionDoc Bean que contiene la informacion con la que se
	 *            va a crear el nuevo registro.
	 *
	 * @param vimpresionDoc the vimpresion doc
	 *  VimpresionDoc Bean resultante del proceso de creacion.
	 * @return the vimpresion doc
	 */
	@RequestMapping(method = RequestMethod.POST)
	public @ResponseBody
	VimpresionDoc add(@RequestBody VimpresionDoc vimpresionDoc) {
		VimpresionDoc vimpresionDocAux = this.vimpresionDocService
				.add(vimpresionDoc);
		VimpresionDocController.logger
				.info("[POST] : VimpresionDoc insertado correctamente");
		return vimpresionDocAux;
	}

	/**
	 * Operacion CRUD Delete. Borrado del registro correspondiente al
	 * identificador especificado.
	 * 
	 *  tipo
	 *            String
	 *  ter
	 *            String
	 *  ano
	 *            String
	 *  num
	 *            Integer
	 *  idtram
	 *            Long
	 *  tipotram
	 *            Long
	 *  procedure
	 *            String
	 *  fecpre
	 *            Date Identificador del objeto que se desea eliminar.
	 *
	 * @param tipo the tipo
	 * @param ter the ter
	 * @param ano the ano
	 * @param num the num
	 * @param idtram the idtram
	 * @param tipotram the tipotram
	 * @param procedure the procedure
	 * @param fecpre the fecpre
	 *  VimpresionDoc Bean eliminado.
	 * @return the vimpresion doc
	 */
	@RequestMapping(value = "/{tipo}/{ter}/{ano}/{num}/{idtram}/{tipotram}/{procedure}/{fecpre}", method = RequestMethod.DELETE)
	@ResponseStatus(value = HttpStatus.OK)
	public @ResponseBody
	VimpresionDoc remove(@PathVariable String tipo, @PathVariable String ter,
			@PathVariable String ano, @PathVariable Integer num,
			@PathVariable Long idtram, @PathVariable Long tipotram,
			@PathVariable String procedure, @PathVariable Date fecpre) {
		VimpresionDoc vimpresionDoc = new VimpresionDoc();
		vimpresionDoc.setTipo(tipo);
		vimpresionDoc.setTer(ter);
		vimpresionDoc.setAnio(ano);
		vimpresionDoc.setNum(num);
		vimpresionDoc.setIdtram(idtram);
		vimpresionDoc.setTipotram(tipotram);
		vimpresionDoc.setProcedure(procedure);
		vimpresionDoc.setFecpre(fecpre);
		this.vimpresionDocService.remove(vimpresionDoc);
		VimpresionDocController.logger
				.info("[DELETE] : VimpresionDoc borrado correctamente");
		return vimpresionDoc;
	}

	/*
	 * METODOS COMPONENTE RUP_TABLE
	 */

	/**
	 * Metodo de presentacion del RUP_TABLE.
	 * 
	 *  model
	 *            Model
	 *
	 * @param model the model
	 *  String
	 * @return the form edit
	 */
	@RequestMapping(value = "/maint", method = RequestMethod.GET)
	public String getFormEdit(Model model) {
		VimpresionDocController.logger.info("[GET - View] : vimpresiondoc");
		// Combos del Filtro
		this.precargaCombosFiltroBusqueda(model);

		return "vimpresiondoc";
	}

	/**
	 * Operacion de filtrado del componente RUP_TABLE.
	 * 
	 *  filterVimpresionDoc
	 *            VimpresionDoc Bean que contiene los parametros de filtrado a
	 *            emplear.
	 *  jqGridRequestDto
	 *            Dto que contiene los parametros de configuracion propios del
	 *            RUP_TABLE a aplicar en el filtrado.
	 *
	 * @param filterVimpresionDoc the filter vimpresion doc
	 * @param jqGridRequestDto the jq grid request dto
	 *  JQGridResponseDto<VimpresionDoc> Dto que contiene el resultado
	 *         del filtrado realizado por el componente RUP_TABLE.
	 * @return the JQ grid response dto
	 */
	@RequestMapping(value = "/filter", method = RequestMethod.POST)
	public @ResponseBody
	JQGridResponseDto<VimpresionDoc> filter(
			@RequestJsonBody(param = "filter") VimpresionDoc filterVimpresionDoc,
			@RequestJsonBody JQGridRequestDto jqGridRequestDto) {
		VimpresionDocController.logger
				.info("[POST - filter] : Obtener VimpresionDocs");
		return this.vimpresionDocService.filter(filterVimpresionDoc,
				jqGridRequestDto, false);
	}

	/**
	 * Operacion de busqueda del componente RUP_TABLE.
	 * 
	 *  filterVimpresionDoc
	 *            VimpresionDoc Bean que contiene los parametros de filtrado a
	 *            emplear.
	 *  searchVimpresionDoc
	 *            VimpresionDoc Bean que contiene los parametros de busqueda a
	 *            emplear.
	 *  jqGridRequestDto
	 *            Dto que contiene los parametros de configuracion propios del
	 *            RUP_TABLE a aplicar en la búsqueda.
	 *
	 * @param filterVimpresionDoc the filter vimpresion doc
	 * @param searchVimpresionDoc the search vimpresion doc
	 * @param jqGridRequestDto the jq grid request dto
	 *  TableRowDto<VimpresionDoc> Dto que contiene el resultado de la
	 *         busqueda realizada por el componente RUP_TABLE.
	 * @return the list
	 */
	@RequestMapping(value = "/search", method = RequestMethod.POST)
	public @ResponseBody
	List<TableRowDto<VimpresionDoc>> search(
			@RequestJsonBody(param = "filter") VimpresionDoc filterVimpresionDoc,
			@RequestJsonBody(param = "search") VimpresionDoc searchVimpresionDoc,
			@RequestJsonBody JQGridRequestDto jqGridRequestDto) {
		VimpresionDocController.logger
				.info("[POST - search] : Buscar VimpresionDocs");
		return this.vimpresionDocService.search(filterVimpresionDoc,
				searchVimpresionDoc, jqGridRequestDto, false);
	}

	/**
	 * Borrado multiple de registros.
	 * 
	 *  filterVimpresionDoc
	 *            VimpresionDoc Bean que contiene los parametros de filtrado a
	 *            emplear.
	 *  jqGridRequestDto
	 *            Dto que contiene los parametros de configuracion propios del
	 *            RUP_TABLE a aplicar en la busqueda.
	 *
	 * @param filterVimpresionDoc the filter vimpresion doc
	 * @param jqGridRequestDto the jq grid request dto
	 *  List<String> Lista de los identificadores de los registros
	 *         eliminados.
	 * @return the list
	 */
	@RequestMapping(value = "/deleteAll", method = RequestMethod.POST)
	@ResponseStatus(value = HttpStatus.OK)
	public @ResponseBody
	List<String> removeMultiple(
			@RequestJsonBody(param = "filter") VimpresionDoc filterVimpresionDoc,
			@RequestJsonBody JQGridRequestDto jqGridRequestDto) {
		VimpresionDocController.logger
				.info("[POST - search] : [POST - removeMultiple] : Eliminar multiples VimpresionDocs");
		this.vimpresionDocService.removeMultiple(filterVimpresionDoc,
				jqGridRequestDto, false);
		VimpresionDocController.logger.info("All entities correctly deleted!");

		return jqGridRequestDto.getMultiselection().getSelectedIds();
	}

	/**
	 * Descargar documento completo imprimir.
	 * 
	 *  request
	 *            HttpServletRequest
	 *  response
	 *            HttpServletResponse
	 *
	 * @param request the request
	 * @param response the response
	 */
	@RequestMapping(value = "/descargarDocImprimir", produces = "application/pdf; charset=utf-8")
	@ResponseStatus(value = HttpStatus.OK)
	public void descargarDocumentoCompletoImprimir(HttpServletRequest request,
			HttpServletResponse response) {

		String destFile = (String) request.getSession().getAttribute(
				VimpresionDocController.PARAM_DOWNLOAD_FILE_PATH);
		request.getSession().removeAttribute(this.PARAM_DOWNLOAD_FILE_PATH);

		List<String> listaFicherosBorrar = (List<String>) request.getSession()
				.getAttribute(VimpresionDocController.PARAM_LIST_FILE_DELETE);
		request.getSession().removeAttribute(
				VimpresionDocController.PARAM_LIST_FILE_DELETE);

		File fDestFile = new File(destFile);
		try {
			InputStream is = new FileInputStream(fDestFile);
			byte[] bytes = IOUtils.toByteArray(is);
			response.setContentType("application/pdf");
			response.setHeader("content-disposition", "inline; filename=\""
					+ fDestFile.getName() + "\"");
			FileCopyUtils.copy(bytes, response.getOutputStream());
			is.close();

			for (String fileDelete : listaFicherosBorrar) {
				try {
					File file = new File(fileDelete);
					file.delete();
				} catch (Exception e) {
					VimpresionDocController.logger
							.error("Se ha producido un error al borrar el temporal {0}. No se hace nada.",
									fileDelete);
				}
			}

		} catch (Exception e) {
			VimpresionDocController.logger.error(
					"Error al descargar el documento a imprimir", e);
		}
	}

	/**
	 * Generar documento completo imprimir.
	 * 
	 *  request
	 *            HttpServletRequest
	 *  listaPk
	 *            Long[]
	 *
	 * @param request the request
	 * @param listaPk the lista pk
	 * @throws AB04BException the AB 04 B exception
	 */
	@ResponseStatus(value = HttpStatus.OK)
	@RequestMapping(value = "/generarDocImprimir", method = RequestMethod.POST)
	public void generarDocumentoCompletoImprimir(HttpServletRequest request,
			@RequestParam(value = "listaTramites[]") List<String> listaPk) throws AB04BException {

		List<String> listaDocsError = new ArrayList<String>();
		listaDocsError.size();
		boolean error = false;
		if (listaPk != null && !listaPk.isEmpty()) {

			OutputStream outStream = null;
			PDFMergerUtility merger = new PDFMergerUtility();

			String auditUser = UtilSeguridad.getInstance().getAuditUser();

			List<String> listaFicherosBorrar = new ArrayList<String>();

			for (String pk : listaPk) {
				String[] tipo = pk.split("~");
				T65BDocumentType documentType = new T65BDocumentType();
				try {

					documentType = this.dokusiService.recuperarDocumentoConOid(
							auditUser, tipo[tipo.length - 1],
							new T65BStringListType());

					if (documentType == null) {
						// Si el documento recuperado es nulo,
						// añadimos
						// error
						listaDocsError.add(tipo[tipo.length - 1]);
					} else {
						// Copiamos contenido a un fichero temporal
						InputStream is = pifService
								.downloadDocument(documentType.getContent()
										.getPifId());
						byte[] buffer = IOUtils.toByteArray(is);
						is.close();

						StringBuilder fileName = new StringBuilder();
						fileName.append(PropertiesUtil
								.getProperty(PropertiesUtil.RUTA_PLANTILLA_EST_TEMP));
						fileName.append(documentType.getDocumentID().getId());
						fileName.append(Long.toString(System
								.currentTimeMillis()));
						fileName.append(Constantes.PUNTO).append(
								Constantes.EXT_PDF);
						File targetFile = new File(fileName.toString());
						outStream = new FileOutputStream(targetFile);
						outStream.write(buffer);
						
						// Añadimos el documento al merge
						merger.addSource(targetFile);

						// Añadimos el fichero para ser borrado al
						// final
						listaFicherosBorrar.add(fileName.toString());
					}
				} catch (Exception e) {
					VimpresionDocController.logger.error(
							"Error en generarDocumentoCompletoImprimir", e);
					error = true;
				}finally{
					try {
						outStream.close();
					} catch (IOException e) {
						VimpresionDocController.logger.error(
								"Error en generarDocumentoCompletoImprimir - outStream.close()", e);
					}
				}

				if (!listaDocsError.isEmpty()) {
					// Si la lista contiene algún documento con error,
					// los guardamos en el mapa junto con el Id del
					// trámite
					error = true;
				}
			}

			StringBuilder destFile = new StringBuilder();
			destFile.append(PropertiesUtil
					.getProperty(PropertiesUtil.RUTA_PLANTILLA_EST_TEMP));
			destFile.append(Long.toString(System.currentTimeMillis()));
			destFile.append(VimpresionDocController.FILE_DEST_SUFIX);
			merger.setDestinationFileName(destFile.toString());
			if (!error) {
				try {
					merger.mergeDocuments(null);
					request.getSession().setAttribute(
							VimpresionDocController.PARAM_DOWNLOAD_FILE_PATH,
							destFile.toString());

					// Añadimos el documento resultante para ser borrado al
					// final
					listaFicherosBorrar.add(destFile.toString());
					request.getSession().setAttribute(
							VimpresionDocController.PARAM_LIST_FILE_DELETE,
							listaFicherosBorrar);

				} catch (IOException ioe) {
					VimpresionDocController.logger.error(
							"Error al hacer merge de los documentos", ioe);
					throw new ErrorGenericoException("error.titulo",
							"error.mergeEnvios");
				}
			} else {

				throw new ErrorGenericoException("error.titulo",
						"error.imprimirdoc");
			}

		}
	}

	/**
	 * Descargar documento.
	 * 
	 *  rutaFichero
	 *            String
	 *
	 * @param rutaFichero the ruta fichero
	 *  byte[]
	 * @return the byte[]
	 * @throws AB04BException the AB 04 B exception
	 */
	public byte[] descargarDocumento(String rutaFichero) throws AB04BException {
		try {
			byte[] ficheroBytes = null;

			try {
				InputStream fichero = pifService.downloadDocument(rutaFichero);
				ficheroBytes = IOUtils.toByteArray(fichero);
				fichero.close();
			} catch (Exception ex) {
				logger.error("descargarDocumento: Error:" + ex.getMessage());
			}
			return ficheroBytes;
		} catch (Exception e) {
			throw new AB04BException(e, e.getMessage());
		}
	}

	/**
	 * Operacion de descarga de documento.
	 * 
	 *  pk
	 *            String
	 * 
	 *  response
	 *            HttpServletResponse
	 * 
	 *  request
	 *            HttpServletRequest
	 *
	 * @param pk the pk
	 * @param response the response
	 * @param request the request
	 */
	@RequestMapping(value = "/generarEtiquetas/{pk}", method = RequestMethod.GET)
	public @ResponseBody
	void generarEtiquetas(@PathVariable String pk,
			HttpServletResponse response, HttpServletRequest request) {
		response.setContentType("application/force-download");
		response.setHeader("Content-Disposition", "attachment; filename=\""
				+ "etiquetasDirecciones.rtf\"");

		InputStream is;
		try {
			is = this.generacionEtiquetasService.getEtiquetas(pk.split(","));

			IOUtils.copy(is, response.getOutputStream());
			is.close();
			response.getOutputStream().close();

		} catch (Exception e) {
			VimpresionDocController.logger
					.error("[ERROR] : GenerarEtiquetas por PK");
		}
	}

	/**
	 * AÃ±ade al model los datos necesarios para la carga de los combos de la
	 * pantalla del filtro de busqueda.
	 * 
	 *  model
	 *            Model
	 *
	 * @param model the model
	 */
	private void precargaCombosFiltroBusqueda(Model model) {

		model.addAttribute("autoridades", UtilSeguridad.getInstance()
				.obtenerDelegacionesUsuario());

		VimpresionDoc vimpDoc = new VimpresionDoc();
		vimpDoc.setCanalNotif(1);

		Calendar c = Calendar.getInstance();
		vimpDoc.setAnio(String.valueOf(c.get(Calendar.YEAR)));

		model.addAttribute("vimprimirDoc", vimpDoc);

	}

}
