/* ==================================================================   
 * Created [2018-06-22] by Jon.King 
 * ==================================================================  
 * TSS 
 * ================================================================== 
 * mailTo:[email protected]
 * Copyright (c) boubei.com, 2015-2018 
 * ================================================================== 
 */

package com.boubei.tss.dm;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
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.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.boubei.tss.PX;
import com.boubei.tss.framework.exception.BusinessException;
import com.boubei.tss.modules.param.ParamManager;
import com.boubei.tss.util.DateUtil;
import com.boubei.tss.util.EasyUtils;
import com.boubei.tss.util.FileHelper;

/**
 * 1.org.apache.poi.ss.usermodel.Workbook 对应Excel文档;
  2.org.apache.poi.hssf.usermodel.HSSFWorkbook  对应xls格式的Excel文档; 65536
  3.org.apache.poi.xssf.usermodel.XSSFWorkbook  对应xlsx格式的Excel文档;1048576
  4.org.apache.poi.ss.usermodel.Sheet  对应Excel文档中的一个sheet;
  5.org.apache.poi.ss.usermodel.Row    对应一个sheet中的一行;
  6.org.apache.poi.ss.usermodel.Cell   对应一个单元格。
 *
 */
public class ExcelPOI extends Excel {
	
	protected  String _csv2Excel(String sourceFile, String charSet) {
		File csvFile = new File(sourceFile);
		String csvName = FileHelper.getFileNameNoSuffix( csvFile.getName() );
		
		String targetFile = DataExport.getExportPath() + "/" + csvName + XLSX_FIX; // POI 一律输出 XLSX;
		Workbook wb = null;
		FileOutputStream ios = null;
		try {
			wb = new SXSSFWorkbook(5000);  // 替代XSSFWorkbook,批量(满5000)输出到文件里,防止OOM
			Sheet ws = wb.createSheet( csvName );
			
			String dataStr = FileHelper.readFile(csvFile, charSet);
			String[] rows = EasyUtils.split(dataStr, "\n");
			
			for (int i = 0; i < rows.length; i++) {
				String[] rowData = rows[i].split(",");
				Row row = ws.createRow(i);
				
				for (int j = 0; j < rowData.length; j++) {
					Cell cell = row.createCell(j, CellType.STRING);
					cell.setCellValue( rowData[j] );
				}
			}
			wb.write(  ios = new FileOutputStream(targetFile)  );
		} 
		catch (Exception e) {
			log.error(e.getMessage(), e.getCause());
		} 
		finally {
			try { wb.close(); } catch (Exception e) {}
			try { ios.close(); } catch (Exception e) {}
		}
		
		return targetFile;
	}

	protected Map<String, Object> readExcel(String filepath) {
		List<String> headers = new ArrayList<String>();
		List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
		
		InputStream is = null;
		Workbook wb = null;
		try {
			is = new FileInputStream(filepath);
			boolean isXLS = isXLS(filepath);
			
			checkExcelSize(is, isXLS);
			
			wb = isXLS ? new HSSFWorkbook(is) : new XSSFWorkbook(is);
			
			Sheet sheet1 = wb.getSheetAt(0);   // 获取第一张Sheet表
			Row row0 = sheet1.getRow(0);      // 获取第一行
            
			int rsColumns = row0.getPhysicalNumberOfCells();  // 获取Sheet表中所包含的总列数
			int rsRows  = sheet1.getPhysicalNumberOfRows();   // 获取Sheet表中所包含的总行数
			
			// 获取指定单元格的对象引用
			for (int i = 0; i <= rsRows; i++) {
				Map<String, Object> row = new LinkedHashMap<String, Object>();
				Row _row = sheet1.getRow(i);
				if( _row == null) continue;
				
				for (int j = 0; j < rsColumns; j++) {
					Cell cell = _row.getCell(j);
					String value = getCellVal(cell, i, j);
					
					if (i == 0) {
						headers.add(value);
					}
					else {
						row.put(headers.get(j), value);
					}
				}
				
				if (i > 0) data.add(row);
			}
		} 
		catch (Exception e) {
			throw new BusinessException( "readExcel error: " + e.getMessage(), e.getCause());
		} 
		finally {
			try { is.close(); } catch (Exception e) {}
			try { wb.close(); } catch (Exception e) {}
		}
		
		Map<String, Object> result = new HashMap<String, Object>();
		result.put("data", data);
		result.put("headers", headers);
		return result;
	}

	public static void checkExcelSize(InputStream is, boolean isXLS) throws IOException {
		int MAX_XLSX_SIZE = EasyUtils.obj2Int( ParamManager.getValue(PX.MAX_XLSX_SIZE, "1024") );
		MAX_XLSX_SIZE = Math.max(MAX_XLSX_SIZE, 1024);
		
		int max_size = 1024 * MAX_XLSX_SIZE * (isXLS ? 5 : 1) ;
		if( is.available() > max_size ) { // 1M xlsx 约等于 1万行*20列
			throw new BusinessException("导入文件过大,已超过" +(max_size*1.0/1024/1024)+ "M,请将数据分开多次导入");
		}
	}

	public static String getCellVal(Cell cell, int i, int j) {
		if(cell == null) return "";
		
		try {
	        switch(cell.getCellTypeEnum()) { // 判断cell类型
		        case NUMERIC:
		            // 判断cell是否为日期格式
		            if( org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell) ) {
		                Date dateCellVal = cell.getDateCellValue();
						return DateUtil.formatCare2Second( dateCellVal );
		            } 
		            else { // 数字,常规类型的数字会自动多出 .0(因转换后是double类型),需要格式化掉
		            	double cellVal = cell.getNumericCellValue();
		            	
		            	NumberFormat f = NumberFormat.getInstance();
		        		f.setMaximumFractionDigits(8); // 最多保留8位小数
						String val = f.format( cellVal );
						
		            	return val.replace(",", "");
		            }
		        case FORMULA:
		        	return ( (XSSFCell)cell ).getCTCell().getV();
		        case STRING:
		        	return cell.getStringCellValue();
		        default:
		        	return cell.toString();
	        }
		} 
		catch( Exception e ) {
			throw new BusinessException( "Excel.getCellVal error, location = [" + i + "," + j + "], cell = " + cell, e);
		}
	}
}