package com.ejie.ab04b.report;

import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

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

import org.apache.commons.beanutils.BeanUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;

import com.ejie.x38.dto.JerarquiaDto;
import com.ejie.x38.reports.AbstractPOIExcelView;

/**
 * @author GFI-NORTE
 * 
 */
public abstract class SdfAbstractPOIExcelView extends AbstractPOIExcelView {

	/**
	 * Sobreescritura del metodo buildExcelDocument. Aplica estilos al informe.
	 * No es compatible con Jerarquia. El mapa 'model', ahora tiene un parametro
	 * reportData cuyo tipo es: {@link SdfReportData}
	 * 
 model
	 *            Map<String, Object>
 workbook
	 *            Workbook
 request
	 *            HttpServletRequest
 response
	 *            HttpServletResponse
	 * @throws Exception
	 *             e;
	 */
	@SuppressWarnings(value = "unchecked")
	@Override()
	protected void buildExcelDocument(Map<String, Object> model,
			Workbook workbook, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		response.setHeader("Content-Disposition", "attachment; filename=\""
				+ model.get("fileName") + this.getFileExtension() + "\"");

		List<SdfReportData<?>> reportData = (List<SdfReportData<?>>) model
				.get("reportData");

		Sheet sheet = null;
		Row row = null;
		Cell cell = null;
		boolean isGrouping;
		int rowNum = 0;
		int cellNum = 0;
		for (SdfReportData<?> dataSheet : reportData) {
			// Por cada objeto dataSheet, se crea una hoja en el libro.
			isGrouping = dataSheet.isGrouping();
			sheet = workbook.createSheet(dataSheet.getSheetName());
			rowNum = 0;

			// Se inicializan los estilos para la hoja:
			CellStyle styleTitle = null;
			CellStyle styleHeader = null;

			if (dataSheet.getStyleTitleCell() != null) {
				styleTitle = dataSheet.getStyleTitleCell().getCellStyle(
						workbook);
			}
			if (dataSheet.getStyleHeaderCell() != null) {
				styleHeader = dataSheet.getStyleHeaderCell().getCellStyle(
						workbook);
			}

			// Si hay titulo, se crea una fila para ello
			if (dataSheet.getTitle() != null) {
				row = sheet.createRow(rowNum++);
			}

			// Se crea una fila para las cabeceras de las columnas
			row = sheet.createRow(rowNum++);
			Map<String, String> dataHeader = (LinkedHashMap<String, String>) dataSheet
					.getHeaderNames();
			cellNum = 0;
			if (dataSheet.isShowHeaders()) {
				if (isGrouping) {
					cell = row.createCell(cellNum++);
					cell.setCellValue("");
					cell.setCellStyle(styleHeader);
				}
				for (Map.Entry<String, String> entry : dataHeader.entrySet()) {
					if ((isGrouping)
							&& (!(dataSheet.isShowGroupColumng()))
							&& ((entry.getKey()).equals(dataSheet
									.getGroupColumnName()))) {
						continue;
					}
					cell = row.createCell(cellNum++);
					cell.setCellValue(entry.getValue());
					cell.setCellStyle(styleHeader);
				}
			}
			if (dataSheet.getTitle() != null) {
				// Aplica estilo a todas las celdas unidas:
				for (int i = 0; i < cellNum; i++) {
					sheet.getRow(0).createCell(i).setCellStyle(styleTitle);
				}
				sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, cellNum - 1));// NOPMD
																					// es
																					// necesario
				cell = sheet.getRow(0).createCell(0);
				cell.setCellValue(dataSheet.getTitle());
				cell.setCellStyle(styleTitle);
			}

			/*
			 * Escribir las filas de datos
			 */
			this.writeDataRows(workbook, sheet, dataSheet, rowNum, isGrouping);

			int columnNumber = dataHeader.size();
			for (int i = 0; i < columnNumber; ++i) {
				sheet.autoSizeColumn(i);
			}

		}

		Cookie cookie = new Cookie("fileDownload", "true");
		cookie.setPath("/");
		response.addCookie(cookie);
	}

	/**
	 * Escribe las filas de datos.
	 *
 workbook            Workbook
 sheet            Sheet
 dataSheet            SgetReportData<?>
 rowNumParam            int
 isGrouping            boolean
	 * @throws IllegalAccessException             e
	 * @throws InvocationTargetException             e
	 * @throws NoSuchMethodException             e
	 */
	private void writeDataRows(Workbook workbook, Sheet sheet,
			SdfReportData<?> dataSheet, int rowNumParam, boolean isGrouping)
			throws IllegalAccessException, InvocationTargetException,
			NoSuchMethodException {
		CellStyle styleEvenRow = null;
		CellStyle styleOddRow = null;
		if (dataSheet.getStyleRowEvenCell() != null) {
			styleEvenRow = dataSheet.getStyleRowEvenCell().getCellStyle(
					workbook);
		}
		if (dataSheet.getStyleRowOddCell() != null) {
			styleOddRow = dataSheet.getStyleRowOddCell().getCellStyle(workbook);
		}
		boolean rowEven = true;
		int rowNum = rowNumParam;
		Map<String, String> dataHeader = (LinkedHashMap<String, String>) dataSheet
				.getHeaderNames();
		List<?> modelData = dataSheet.getModelData();
		String prevGroupValue = "";
		String groupValue = "";
		Cell cell = null;
		Row row = null;
		int cellNum = 0;
		for (Iterator<?> localIterator3 = modelData.iterator(); localIterator3
				.hasNext();) {
			Object object = localIterator3.next();
			row = sheet.createRow(rowNum++);
			rowEven = !rowEven;
			cellNum = 0;

			if (isGrouping) {
				groupValue = BeanUtils.getProperty(
						((JerarquiaDto<?>) object).getModel(),
						dataSheet.getGroupColumnName());
				if (!(groupValue.equals(prevGroupValue))) {
					prevGroupValue = groupValue;
					cell = row.createCell(cellNum++);
					cell.setCellValue(groupValue);
					cell.setCellStyle(rowEven ? styleEvenRow : styleOddRow);
					row = sheet.createRow(rowNum++);
					rowEven = !rowEven;
					cellNum = 0;
				}
				cell = row.createCell(cellNum++);
				cell.setCellValue("");
				cell.setCellStyle(rowEven ? styleEvenRow : styleOddRow);

			}
			for (Map.Entry<String, String> entry : dataHeader.entrySet()) {
				if ((isGrouping)
						&& (!(dataSheet.isShowGroupColumng()))
						&& (((String) entry.getKey()).equals(dataSheet
								.getGroupColumnName()))) {
					continue;
				}
				String columnValue = BeanUtils.getProperty(object,
						(String) entry.getKey());

				cell = row.createCell(cellNum++);
				cell.setCellValue(columnValue);
				cell.setCellStyle(rowEven ? styleEvenRow : styleOddRow);
			}

		}
	}
}
