package com.ejie.ab79.service.protocolos;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Locale;

import javax.activation.MimetypesFileTypeMap;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ejie.ab79.comun.Constantes;
import com.ejie.ab79.dao.protocolos.ProtocolosDao;
import com.ejie.ab79.model.protocolos.Protocolos;
import com.ejie.x38.dto.JerarquiaDto;
import com.ejie.x38.dto.TableRequestDto;
import com.ejie.x38.dto.TableResponseDto;
import com.ejie.x38.dto.TableRowDto;

/**
 * ProtocolosServiceImpl  
 * 
 *  
 */

@Service(value = "protocolosService")
public class ProtocolosServiceImpl implements ProtocolosService {

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

	@Autowired
	private ProtocolosDao protocolosDao;

	@Resource
	private ReloadableResourceBundleMessageSource appMessageSource;

	/**
	 * Inserts a single row in the Protocolos table.
	 *
	 * @param protocolos
	 *            Protocolos
	 * @return Protocolos
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Protocolos add(Protocolos protocolos) {
		return this.protocolosDao.add(protocolos);
	}

	/**
	 * Updates a single row in the Protocolos table.
	 *
	 * @param protocolos
	 *            Protocolos
	 * @return Protocolos
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Protocolos update(Protocolos protocolos) {
		return this.protocolosDao.update(protocolos);
	}

	/**
	 * Finds a single row in the Protocolos table.
	 *
	 * @param protocolos
	 *            Protocolos
	 * @return Protocolos
	 */
	public Protocolos find(Protocolos protocolos) {
		return this.protocolosDao.find(protocolos);
	}

	/**
	 * Deletes a single row in the Protocolos table.
	 *
	 * @param protocolos
	 *            Protocolos
	 */
	@Transactional(rollbackFor = Throwable.class)
	public void remove(Protocolos protocolos) {
		this.protocolosDao.remove(protocolos);
	}

	/**
	 * Finds a list of rows in the Protocolos table.
	 *
	 * @param protocolos
	 *            Protocolos
	 * @param tableRequestDto
	 *            TableRequestDto
	 * @return List<Protocolos>
	 */
	public List<Protocolos> findAll(Protocolos protocolos, TableRequestDto tableRequestDto) {
		return this.protocolosDao.findAll(protocolos, tableRequestDto);
	}

	/**
	 * Finds rows in the Protocolos table using like.
	 *
	 * @param protocolos
	 *            Protocolos
	 * @param tableRequestDto
	 *            TableRequestDto
	 * @param startsWith
	 *            Boolean
	 * @return List<Protocolos>
	 */
	public List<Protocolos> findAllLike(Protocolos protocolos, TableRequestDto tableRequestDto, Boolean startsWith) {
		return this.protocolosDao.findAllLike(protocolos, tableRequestDto, startsWith);
	}

	/*
	 * OPERACIONES RUP_TABLE
	 */

	/**
	 * Removes rows from the Protocolos table.
	 *
	 * @param filterProtocolos
	 *            Protocolos
	 * @param tableRequestDto
	 *            TableRequestDto
	 * @param startsWith
	 *            Boolean
	 */
	public void removeMultiple(Protocolos filterProtocolos, TableRequestDto tableRequestDto, Boolean startsWith) {
		this.protocolosDao.removeMultiple(filterProtocolos, tableRequestDto, startsWith);
	}

	/**
	 * Filter method in the Protocolos table.
	 *
	 * @param filterProtocolos
	 *            Protocolos
	 * @param tableRequestDto
	 *            TableRequestDto
	 * @param startsWith
	 *            Boolean
	 * @return TableResponseDto<Protocolos>
	 */
	public TableResponseDto<Protocolos> filter(Protocolos filterProtocolos, TableRequestDto tableRequestDto,
			Boolean startsWith) {
		List<Protocolos> listaProtocolos = this.protocolosDao.findAllLike(filterProtocolos, tableRequestDto, false);

		for (Protocolos protocolo : listaProtocolos) {
			protocolo.setNumeroPreguntas(this.protocolosDao.calcularNumPreguntasProtocolo(protocolo));

			int numeroRespuestasProtocolo = this.protocolosDao.calcularNumeroRespuestasProtocolo(protocolo);
			int numeroRespuestasValidar = this.protocolosDao.calcularNumeroRespuestasValidar(protocolo);
			int numeroRespuestasTotal = numeroRespuestasProtocolo + numeroRespuestasValidar;

			protocolo.setNumeroRespuestas(numeroRespuestasTotal);
			protocolo.setNumeroInspecciones(this.protocolosDao.calcularNumeroInspecciones(protocolo));
		}

		Long recordNum = this.protocolosDao
				.findAllLikeCount(filterProtocolos != null ? filterProtocolos : new Protocolos(), false);

		TableResponseDto<Protocolos> usuarioDto = new TableResponseDto<Protocolos>(tableRequestDto, recordNum,
				listaProtocolos);

		if (tableRequestDto.getMultiselection().getSelectedIds() != null) {
			List<TableRowDto<Protocolos>> reorderSelection = this.protocolosDao.reorderSelection(filterProtocolos,
					tableRequestDto, startsWith);
			usuarioDto.setReorderedSelection(reorderSelection);
			usuarioDto.addAdditionalParam("reorderedSelection", reorderSelection);
			usuarioDto.addAdditionalParam("selectedAll", tableRequestDto.getMultiselection().getSelectedAll());
		}
		if (tableRequestDto.getSeeker().getSelectedIds() != null) {
			tableRequestDto.setMultiselection(tableRequestDto.getSeeker());
			List<TableRowDto<Protocolos>> reorderSeeker = this.protocolosDao.reorderSelection(filterProtocolos,
					tableRequestDto, startsWith);
			usuarioDto.setReorderedSeeker(reorderSeeker);
			usuarioDto.addAdditionalParam("reorderedSeeker", reorderSeeker);
		}
		return usuarioDto;
	}

	/**
	 * Searches rows in the Protocolos table.
	 *
	 * @param filterProtocolos
	 *            Protocolos
	 * @param searchProtocolos
	 *            Protocolos
	 * @param tableRequestDto
	 *            TableRequestDto
	 * @param startsWith
	 *            Boolean
	 * @return List<TableRowDto<Protocolos>>
	 */
	public List<TableRowDto<Protocolos>> search(Protocolos filterProtocolos, Protocolos searchProtocolos,
			TableRequestDto tableRequestDto, Boolean startsWith) {
		return this.protocolosDao.search(filterProtocolos, searchProtocolos, tableRequestDto, startsWith);
	}

	/**
	 * Reorder the selection made in Protocolos table.
	 *
	 * @param filterProtocolos
	 *            Protocolos
	 * @param tableRequestDto
	 *            TableRequestDto
	 * @param startsWith
	 *            Boolean
	 * @return Object
	 */
	public Object reorderSelection(Protocolos filterProtocolos, TableRequestDto tableRequestDto, Boolean startsWith) {
		return this.protocolosDao.reorderSelection(filterProtocolos, tableRequestDto, startsWith);
	}

	/*
	 * OPERACIONES RUP_TABLE JERARQUIA
	 */

	/**
	 * Finder method in the hierarchical the Protocolos table.
	 *
	 * @param filterProtocolos
	 *            Protocolos
	 * @param tableRequestDto
	 *            TableRequestDto
	 * @param startsWith
	 *            Boolean
	 * @return TableResponseDto<JerarquiaDto<Protocolos>>
	 */
	public TableResponseDto<JerarquiaDto<Protocolos>> jerarquia(Protocolos filterProtocolos,
			TableRequestDto tableRequestDto, Boolean startsWith) {
		List<JerarquiaDto<Protocolos>> listaProtocolos = this.protocolosDao.findAllLikeJerarquia(filterProtocolos,
				tableRequestDto);
		Long recordNum = this.protocolosDao.findAllLikeCountJerarquia(filterProtocolos, tableRequestDto);
		return new TableResponseDto<JerarquiaDto<Protocolos>>(tableRequestDto, recordNum, listaProtocolos);
	}

	/**
	 * Finder method for siblings rows in the hierarchical the Protocolos table.
	 *
	 * @param filterProtocolos
	 *            Protocolos
	 * @param tableRequestDto
	 *            TableRequestDto
	 * @return TableResponseDto<JerarquiaDto<Protocolos>>
	 */
	public TableResponseDto<JerarquiaDto<Protocolos>> jerarquiaChildren(Protocolos filterProtocolos,
			TableRequestDto tableRequestDto) {
		TableResponseDto<JerarquiaDto<Protocolos>> tableResponseDto = new TableResponseDto<JerarquiaDto<Protocolos>>();
		tableResponseDto.addAdditionalParam(TableResponseDto.CHILDREN,
				this.protocolosDao.findAllChild(filterProtocolos, tableRequestDto));
		return tableResponseDto;
	}

	/**
	 * Exporta Datos al clipBoard
	 *
	 */
	public List<Protocolos> getMultiple(Protocolos filterProtocolos, TableRequestDto tableRequestDto,
			Boolean startsWith) {
		return this.protocolosDao.getMultiple(filterProtocolos, tableRequestDto, startsWith);
	}

	@Override
	public Protocolos findProtocolo(Protocolos protocolo) {
		return this.protocolosDao.findProtocolo(protocolo);
	}

	@Override
	public void getExcel(List<Protocolos> listaProtocolos, HttpServletResponse response) {

		Locale locale = LocaleContextHolder.getLocale();

		boolean castellano = false;
		boolean euskera = false;

		// Configuramos variables de idioma.
		if (locale.toString().equals(Constantes.CASTELLANO)) {
			castellano = true;
		} else if (locale.toString().equals(Constantes.EUSKERA)) {
			euskera = true;
		}

		try {
			// Nombre del archivo
			String fileName = appMessageSource.getMessage("excel.protocolos.sheetName", null, locale)
					+ Constantes.EXTENSION_EXCEL;

			// Creamos la hoja
			HSSFWorkbook workbook = new HSSFWorkbook();
			HSSFSheet sheet = workbook
					.createSheet(appMessageSource.getMessage("excel.protocolos.sheetName", null, locale));

			// Definimos los estilos y fuentes de la hoja
			HSSFFont font = workbook.createFont();
			font.setFontName(HSSFFont.FONT_ARIAL);
			font.setFontHeightInPoints((short) 12);
			font.setBoldweight(Font.BOLDWEIGHT_BOLD);

			HSSFCellStyle headerStyle = workbook.createCellStyle();
			headerStyle.setBorderBottom(CellStyle.BORDER_MEDIUM);
			headerStyle.setFont(font);
			headerStyle.setAlignment(CellStyle.ALIGN_CENTER);

			// Creamos la fila cabecera
			HSSFRow rowHead = sheet.createRow(0);

			rowHead.createCell(0).setCellValue(appMessageSource.getMessage("excel.protocolos.direccion", null, locale));
			rowHead.createCell(1)
					.setCellValue(appMessageSource.getMessage("excel.protocolos.informeTecnico", null, locale));
			rowHead.createCell(2).setCellValue(appMessageSource.getMessage("excel.protocolos.origen", null, locale));
			rowHead.createCell(3)
					.setCellValue(appMessageSource.getMessage("excel.protocolos.procedimiento", null, locale));
			rowHead.createCell(4)
					.setCellValue(appMessageSource.getMessage("excel.protocolos.numeroPreguntas", null, locale));
			rowHead.createCell(5)
					.setCellValue(appMessageSource.getMessage("excel.protocolos.numeroRespuestas", null, locale));
			rowHead.createCell(6).setCellValue(appMessageSource.getMessage("excel.protocolos.estado", null, locale));

			rowHead.getCell(0).setCellStyle(headerStyle);
			rowHead.getCell(1).setCellStyle(headerStyle);
			rowHead.getCell(2).setCellStyle(headerStyle);
			rowHead.getCell(3).setCellStyle(headerStyle);
			rowHead.getCell(4).setCellStyle(headerStyle);
			rowHead.getCell(5).setCellStyle(headerStyle);
			rowHead.getCell(6).setCellStyle(headerStyle);
			rowHead.setHeightInPoints(20);

			// Creamos el resto de filas con sus celdas
			int rowCount = 1;
			for (Protocolos protocolo : listaProtocolos) {

				HSSFRow protocoloRow = sheet.createRow(rowCount++);

				if (castellano) {
					protocoloRow.createCell(0).setCellValue(protocolo.getDireccion().getDescripcionCastellano());
					protocoloRow.createCell(1).setCellValue(protocolo.getDescripcionCastellano());
					protocoloRow.createCell(2).setCellValue(protocolo.getOrigen().getDescripcionCastellano());
					protocoloRow.createCell(3).setCellValue(protocolo.getProcedimiento().getDescripcionEs());
				} else if (euskera) {
					protocoloRow.createCell(0).setCellValue(protocolo.getDireccion().getDescripcionEuskera());
					protocoloRow.createCell(1).setCellValue(protocolo.getDescripcionEuskera());
					protocoloRow.createCell(2).setCellValue(protocolo.getOrigen().getDescripcionEuskera());
					protocoloRow.createCell(3).setCellValue(protocolo.getProcedimiento().getDescripcionEu());
				}

				protocoloRow.createCell(4).setCellValue(protocolo.getNumeroPreguntas());
				protocoloRow.createCell(5).setCellValue(protocolo.getNumeroRespuestas());

				if (protocolo.getValidado() == Constantes.INFORME_ACTIVO) {
					protocoloRow.createCell(6)
							.setCellValue(appMessageSource.getMessage("excel.protocolos.estadoActivo", null, locale));
				} else if (protocolo.getValidado() == Constantes.INFORME_INACTIVO) {
					protocoloRow.createCell(6)
							.setCellValue(appMessageSource.getMessage("excel.protocolos.estadoInactivo", null, locale));
				}

				protocoloRow.setHeightInPoints(20);
			}

			// Anchura de las columnas
			sheet.autoSizeColumn(0);
			sheet.autoSizeColumn(1);
			sheet.autoSizeColumn(2);
			sheet.autoSizeColumn(3);
			sheet.autoSizeColumn(4);
			sheet.autoSizeColumn(5);
			sheet.autoSizeColumn(6);

			FileOutputStream fileOut = new FileOutputStream(fileName);
			workbook.write(fileOut);
			fileOut.close();

			ProtocolosServiceImpl.logger.info("[GET - exportarExcel] : Archivo generado");

			// Creamos el archivo a descargar
			File fileToDownload = new File(fileName);
			InputStream in = new FileInputStream(fileToDownload);

			// Recogemos el MIME type del fichero
			String mimeType = new MimetypesFileTypeMap().getContentType(fileName);

			if (mimeType == null) {
				// Si no se encuentra lo seteamos manualmente
				mimeType = "application/octet-stream";
			}
			ProtocolosServiceImpl.logger.info("[GET - exportarExcel] : MIME type: " + mimeType);

			// Seteamos el contentType de la response
			response.setContentType(mimeType);
			response.setContentLength((int) fileToDownload.length());

			// Descargamos el archivo
			response.setHeader("Content-Disposition", "attachment; filename=\"" + fileToDownload.getName() + "\"");

			// Obtenemos el outputStream de la response
			OutputStream outStream = response.getOutputStream();

			byte[] buffer = new byte[4096];
			int bytesRead = -1;

			while ((bytesRead = in.read(buffer)) != -1) {
				outStream.write(buffer, 0, bytesRead);
			}

			// Cerramos el InputStream y el OutputStream
			in.close();
			outStream.close();

			ProtocolosServiceImpl.logger.info("[GET - exportarExcel] : Archivo descargado con �xito");

		} catch (Exception e) {
			ProtocolosServiceImpl.logger.error(e.getMessage());
		}

	}

	@Override
	public Integer calcularNumPreguntasProtocolo(Protocolos protocolo) {
		return this.protocolosDao.calcularNumPreguntasProtocolo(protocolo);
	}

	@Override
	public Integer calcularNumeroRespuestasProtocolo(Protocolos protocolo) {
		return this.protocolosDao.calcularNumeroRespuestasProtocolo(protocolo);
	}

	@Override
	public Integer calcularNumeroRespuestasValidar(Protocolos protocolo) {
		return this.protocolosDao.calcularNumeroRespuestasValidar(protocolo);
	}

	@Override
	public Protocolos validarInforme(Protocolos protocolo) {
		return this.protocolosDao.validarInforme(protocolo);
	}

	@Override
	public Protocolos invalidarInforme(Protocolos protocolo) {
		return this.protocolosDao.invalidarInforme(protocolo);
	}

	@Override
	public List<Protocolos> findAllREST(Protocolos filterProtocolos) {
		return this.protocolosDao.findAllREST(filterProtocolos);
	}

}
