package com.ejie.ab79.service.inspecciones;

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.inspecciones.ResultadosInspeccionDao;
import com.ejie.ab79.model.inspecciones.DesResIns;
import com.ejie.ab79.model.inspecciones.ResultadosInspeccion;
import com.ejie.x38.dto.JerarquiaDto;
import com.ejie.x38.dto.TableRequestDto;
import com.ejie.x38.dto.TableResponseDto;
import com.ejie.x38.dto.TableRowDto;

/**
 * ResultadosInspeccionServiceImpl  
 * 
 *  
 */

@Service(value = "resultadosInspeccionService")
public class ResultadosInspeccionServiceImpl implements ResultadosInspeccionService {

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

	@Autowired
	private ResultadosInspeccionDao resultadosInspeccionDao;

	@Resource
	private ReloadableResourceBundleMessageSource appMessageSource;

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

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

	/**
	 * Finds a single row in the ResultadosInspeccion table.
	 *
	 * @param resultadosInspeccion
	 *            ResultadosInspeccion
	 * @return ResultadosInspeccion
	 */
	public ResultadosInspeccion find(ResultadosInspeccion resultadosInspeccion) {
		return this.resultadosInspeccionDao.find(resultadosInspeccion);
	}

	@Override
	public Integer findRegistroDuplicado(ResultadosInspeccion resultadoInspeccion) {
		return this.resultadosInspeccionDao.findRegistroDuplicado(resultadoInspeccion);
	}

	@Override
	public List<ResultadosInspeccion> findByDesResIns(DesResIns desResIns) {
		return this.resultadosInspeccionDao.findByDesResIns(desResIns);
	}

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

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

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

	/*
	 * OPERACIONES RUP_TABLE
	 */

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

	/**
	 * Filter method in the ResultadosInspeccion table.
	 *
	 * @param filterResultadosInspeccion
	 *            ResultadosInspeccion
	 * @param tableRequestDto
	 *            TableRequestDto
	 * @param startsWith
	 *            Boolean
	 * @return TableResponseDto<ResultadosInspeccion>
	 */
	public TableResponseDto<ResultadosInspeccion> filter(ResultadosInspeccion filterResultadosInspeccion,
			TableRequestDto tableRequestDto, Boolean startsWith) {
		List<ResultadosInspeccion> listaResultadosInspeccion = this.resultadosInspeccionDao
				.findAllLike(filterResultadosInspeccion, tableRequestDto, false);
		Long recordNum = this.resultadosInspeccionDao.findAllLikeCount(
				filterResultadosInspeccion != null ? filterResultadosInspeccion : new ResultadosInspeccion(), false);

		TableResponseDto<ResultadosInspeccion> usuarioDto = new TableResponseDto<ResultadosInspeccion>(tableRequestDto,
				recordNum, listaResultadosInspeccion);

		if (tableRequestDto.getMultiselection().getSelectedIds() != null) {
			List<TableRowDto<ResultadosInspeccion>> reorderSelection = this.resultadosInspeccionDao
					.reorderSelection(filterResultadosInspeccion, 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<ResultadosInspeccion>> reorderSeeker = this.resultadosInspeccionDao
					.reorderSelection(filterResultadosInspeccion, tableRequestDto, startsWith);
			usuarioDto.setReorderedSeeker(reorderSeeker);
			usuarioDto.addAdditionalParam("reorderedSeeker", reorderSeeker);
		}
		return usuarioDto;
	}

	/**
	 * Searches rows in the ResultadosInspeccion table.
	 *
	 * @param filterResultadosInspeccion
	 *            ResultadosInspeccion
	 * @param searchResultadosInspeccion
	 *            ResultadosInspeccion
	 * @param tableRequestDto
	 *            TableRequestDto
	 * @param startsWith
	 *            Boolean
	 * @return List<TableRowDto<ResultadosInspeccion>>
	 */
	public List<TableRowDto<ResultadosInspeccion>> search(ResultadosInspeccion filterResultadosInspeccion,
			ResultadosInspeccion searchResultadosInspeccion, TableRequestDto tableRequestDto, Boolean startsWith) {
		return this.resultadosInspeccionDao.search(filterResultadosInspeccion, searchResultadosInspeccion,
				tableRequestDto, startsWith);
	}

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

	/*
	 * OPERACIONES RUP_TABLE JERARQUIA
	 */

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

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

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

	@Override
	public ResultadosInspeccion findDatosBasicos(ResultadosInspeccion resultadosInspeccion) {
		return this.resultadosInspeccionDao.findDatosBasicos(resultadosInspeccion);
	}

	public List<ResultadosInspeccion> findAllDatosInspeccion(ResultadosInspeccion resultadosInspeccion,
			TableRequestDto tableRequestDto) {
		return this.resultadosInspeccionDao.findAllDatosInspeccion(resultadosInspeccion, tableRequestDto);
	}

	@Override
	public void getExcel(List<ResultadosInspeccion> listaResultadosInspeccion, HttpServletResponse response) {

		Locale locale = LocaleContextHolder.getLocale();

		boolean euskera = false;

		if (locale.toString().equals(Constantes.EUSKERA)) {
			euskera = true;
		}

		try {

			// Nombre del archivo
			String fileName = appMessageSource.getMessage("excel.resultadosInspeccion.sheetName", null, locale)
					+ ".xls";

			// Creamos la hoja
			HSSFWorkbook workbook = new HSSFWorkbook();
			HSSFSheet sheet = workbook
					.createSheet(appMessageSource.getMessage("excel.resultadosInspeccion.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);

			HSSFCellStyle disabledStyle = workbook.createCellStyle();
			disabledStyle.setFillPattern(CellStyle.THIN_FORWARD_DIAG);

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

			rowHead.createCell(0)
					.setCellValue(appMessageSource.getMessage("excel.resultadosInspeccion.descripcion", null, locale));
			rowHead.createCell(1)
					.setCellValue(appMessageSource.getMessage("excel.resultadosInspeccion.direccion", null, locale));
			rowHead.createCell(2)
					.setCellValue(appMessageSource.getMessage("excel.resultadosInspeccion.origen", null, locale));

			rowHead.getCell(0).setCellStyle(headerStyle);
			rowHead.getCell(1).setCellStyle(headerStyle);
			rowHead.getCell(2).setCellStyle(headerStyle);

			// Creamos el resto de filas con sus celdas
			int rowCount = 1;
			for (ResultadosInspeccion resultadosInspeccion : listaResultadosInspeccion) {

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

				resultadosInspeccionRow.createCell(0)
						.setCellValue((euskera) ? resultadosInspeccion.getDesResIns().getDescripcionEuskera()
								: resultadosInspeccion.getDesResIns().getDescripcionCastellano());
				resultadosInspeccionRow.createCell(1)
						.setCellValue((euskera) ? resultadosInspeccion.getDireccion().getDescripcionEuskera()
								: resultadosInspeccion.getDireccion().getDescripcionCastellano());
				resultadosInspeccionRow.createCell(2)
						.setCellValue((euskera) ? resultadosInspeccion.getOrigenInspeccion().getDescripcionEuskera()
								: resultadosInspeccion.getOrigenInspeccion().getDescripcionCastellano());
			}

			// Anchura de las columnas
			sheet.autoSizeColumn(0);
			sheet.autoSizeColumn(1);
			sheet.autoSizeColumn(2);

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

			ResultadosInspeccionServiceImpl.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";
			}
			ResultadosInspeccionServiceImpl.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();

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

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

}
