package com.eactive.eai.rms.common.excel;

import java.util.HashMap;
import java.util.Map;

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

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.springframework.web.servlet.view.document.AbstractXlsxView;

public class ExcelView extends AbstractXlsxView {
	
	protected final Logger logger = Logger.getLogger(ExcelView.class);

    @Override
    protected void buildExcelDocument(Map<String, Object> model, Workbook workbook, HttpServletRequest request,
            HttpServletResponse response) throws Exception {
    	
    	try {
	        String fileName = (String) model.get("fileName");
	        if (fileName == null) {
	            String uri = request.getRequestURI();
	            fileName = uri.substring(uri.lastIndexOf("/") + 1, uri.lastIndexOf("."));
	
	        }
	        String eFileName = new String(fileName.getBytes("utf-8"), "8859_1");
	
	        logger.debug("Excel fileName : " + fileName);
	        
	        response.setContentType("application/x-msdownload");
	        response.setHeader("Content-Disposition", "attachment;filename=\"" + eFileName + ".xlsx\"");
	        
	        logger.debug("Excel File Name : " + eFileName);
	
	        String[] headers = (String[]) model.get("headers");
	        
	        // postgresql의 경우 resultset의 col name이 소문자로 return되므로
	        String[] headers_lower = headers.clone();
	        for(int i=0; i<headers_lower.length; i++) {
	        	headers_lower[i] = headers_lower[i].toLowerCase();	        	
	        }
	        
	        String[] headerTitles = (String[]) model.get("headerTitles");
	        HashMap<String, Object>[] datas = (HashMap<String, Object>[]) model.get("datas");
	        // create a wordsheet
	        Sheet sheet = workbook.createSheet("Sheet1");
	        logger.debug("Create WorkbookSheet");
	
	        CellStyle tStyle = workbook.createCellStyle();
	        tStyle.setBorderBottom(BorderStyle.THIN);
	        tStyle.setBorderTop(BorderStyle.THIN);
	        tStyle.setBorderLeft(BorderStyle.THIN);
	        tStyle.setBorderRight(BorderStyle.THIN);
	        tStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.index);
	        tStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
	        tStyle.setAlignment(HorizontalAlignment.CENTER);
	        tStyle.setVerticalAlignment(VerticalAlignment.CENTER);
	
	        CellStyle dStyle = workbook.createCellStyle();
	        dStyle.setBorderBottom(BorderStyle.THIN);
	        dStyle.setBorderTop(BorderStyle.THIN);
	        dStyle.setBorderLeft(BorderStyle.THIN);
	        dStyle.setBorderRight(BorderStyle.THIN);
	
	        Row header = sheet.createRow(0);
	        for (int column = 0; column < headers.length; column++) {
	            Cell cell = header.createCell(column);
	            logger.debug("Excel Header Title : " + column + " => "+ headerTitles[column]);
	            // cell.setEncoding(HSSFCell.ENCODING_UTF_16);
	            cell.setCellValue(
	                    new XSSFRichTextString(headerTitles[column].replaceAll("<br>", "").replaceAll("<br/>", "")));
	            cell.setCellStyle(tStyle);
	        }
	
	        int rowNum = 1;
	        for (Map<String, Object> m : datas) {
	            // create the row data
	            Row row = sheet.createRow(rowNum++);
	            for (int column = 0; column < headers.length; column++) {
	            	Cell cell = row.createCell(column);
	            	String cellVal = null;
	            	Object o = m.get(headers[column]);
	            	if(o == null) {
	            		o = m.get(headers_lower[column]);
	            	}
	            	
					if (o == null) {
						cellVal = " ";
					} else if (o instanceof String) {
						cellVal = (String) o;
					} else if (o instanceof Double) {
						cellVal = ((Double) o).toString();
					} else if (o instanceof Integer) {
						cellVal = ((Integer) o).toString();
					} else {
						cellVal = o.toString();
					}
	            	logger.debug("[" + rowNum + ":" + column + "] / Data : " + cellVal);
	            	
	            	boolean isCellValNumeric = StringUtils.isNumeric(cellVal);
	            	if(isCellValNumeric && StringUtils.isNotEmpty(cellVal)) {
	            		cell.setCellValue(Double.parseDouble(cellVal));
	            	} else {
	            		cell.setCellValue(cellVal);
	            	}
	                cell.setCellStyle(dStyle);
	            }
	        }
	        HashMap<String, String>[] merge = (HashMap<String, String>[]) model.get("merge");
	        if (merge != null) {
	            sheet.shiftRows(0, sheet.getLastRowNum(), 1);
	            header = sheet.createRow(0);
	            for (int column = 0; column < headers.length; column++) {
	                Cell cell = header.createCell(column);
	                cell.setCellValue(new XSSFRichTextString(""));
	                cell.setCellStyle(tStyle);
	            }
	
	            for (HashMap<String, String> m : merge) {
	            	logger.debug("Row&Col merge data : " + m.toString());
	                int firstRow = Integer.parseInt(m.get("firstRow"));
	                int endRow = Integer.parseInt(m.get("endRow"));
	                int firstCol = Integer.parseInt(m.get("firstCol"));
	                int endCol = Integer.parseInt(m.get("endCol"));
	                String text = m.get("text");
	                boolean isTextNumeric = StringUtils.isNumeric(text.isEmpty()?"NAN":text);
	                if(isTextNumeric) {
	                	sheet.getRow(firstRow).getCell(firstCol).setCellValue(Double.parseDouble(text));
	            	} else {
	            		sheet.getRow(firstRow).getCell(firstCol).setCellValue(new XSSFRichTextString(text));
	            	}
	                sheet.addMergedRegion(new CellRangeAddress(firstRow, endRow, firstCol, endCol));
	            }
	        }
	
	        for (int column = 0; column < datas.length; column++) {
	            sheet.autoSizeColumn(column);
	        }
	
			workbook.write(response.getOutputStream());
			response.getOutputStream().flush();
    	} catch (Exception e) {
    		logger.error(e.getMessage());
    		logger.error(e.getCause());
    		logger.error(e.getStackTrace());
    		throw e;
    	}
    	

    }

}
