package com.cabletech.business.ah.excelreport.sum;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Resource;
import org.apache.commons.lang.StringUtils;
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.springframework.util.CollectionUtils;
import com.cabletech.baseinfo.business.Service.BaseInfoProvider;
import com.cabletech.business.ah.excelreport.dao.AhExcelReportRecodeDao;
import com.cabletech.business.ah.excelreport.dao.AhExcelReportSheetTypeDao;
import com.cabletech.business.ah.excelreport.model.AhExcelReportRecode;
import com.cabletech.business.ah.excelreport.model.AhExcelReportSheet;
import com.cabletech.business.excel.AutoGenerateFactory;
import com.cabletech.business.excel.AutoGenerateUtils;
import com.cabletech.business.excel.TableCellData;
/**
* Sheet汇总基类
*
* @author 杨隽 2012-06-28 创建
*
*/
public abstract class BaseSheetSumGenerate {
/**
* 除法公式标识符
*/
public static final String SUM_DIV_OPERATOR_CHAR = "%";
/**
* 除法公式匹配表达式
*/
public static final Pattern DIVIDE_FOMULA_PATTERN = Pattern
.compile("^\\%\\((\\d+)/(\\d+)\\)");
/**
* 关联除法公式匹配表达式
*/
public static final Pattern JOIN_DIVIDE_FOMULA_PATTERN = Pattern
.compile("^\\%\\((\\d+)/(\\d+)\\!(\\d+)\\)");
/**
* “合计”的字串常量
*/
public static final String SUM_STRING_CONSTANT = "合计";
/**
* 数据开始行的位置
*/
public static final int DATA_START_ROW_INDEX = 5;
/**
* 合计开始列的位置
*/
public static final int SUM_START_COL_INDEX = 5;
/**
* 不需进行汇总的列标记
*/
public static final int NOT_SUM_COL_FLAG = 0;
/**
* 地市每个月上传的excel报表DAO
*/
@Resource(name = "ahExcelReportRecodeDao")
private AhExcelReportRecodeDao ahExcelReportRecodeDao;
/**
* 地市每个月上传的excel报表中sheet类型DAO
*/
@Resource(name = "ahExcelReportSheetTypeDao")
private AhExcelReportSheetTypeDao ahExcelReportSheetTypeDao;
/**
* 基础服务包
*/
@Resource(name = "baseInfoProvider")
protected BaseInfoProvider baseInfoProvider;
/**
* 合计总值Map
*/
protected Map<String, Double> totalValueMap;
/**
* 关联合计总值Map
*/
protected Map<String, Double> joinTotalValueMap;
/**
* 工作表列表
*/
protected List<Workbook> wbList;
/**
* 根据查询条件获取汇总的Sheet数据信息
*
* @param report
* AhExcelReportRecode 查询条件
* @param sheetType
* Sheet类型信息
* @return Map<String, Object> 汇总的Sheet数据信息
* @throws Exception
*/
public Map<String, Object> getTableMap(AhExcelReportRecode report,
AhExcelReportSheet sheetType) throws Exception {
Map<String, Object> map = new HashMap<String, Object>();
List<AhExcelReportRecode> list = ahExcelReportRecodeDao
.queryAhExcelReportRecodeList(report);
if (CollectionUtils.isEmpty(list)) {
return map;
}
Workbook sampleWb = getSampleWorkbook(list);
int colNum = getSumColNum(sampleWb, sheetType);
int colSpan = getSumColSpan(report, sheetType, sampleWb);
totalValueMap = new HashMap<String, Double>();
joinTotalValueMap = new HashMap<String, Double>();
wbList = new ArrayList<Workbook>();
int tableWidth = AutoGenerateUtils.getTableWidth(
sampleWb.getSheetAt(sheetType.getSheetNum()),
DATA_START_ROW_INDEX);
map.put("tableWidth", tableWidth);
List<List<TableCellData>> rowDataList = new ArrayList<List<TableCellData>>();
rowDataList.addAll(getTableSubjectStr(sheetType, list));
int rowIndex = DATA_START_ROW_INDEX - sheetType.getRow();
for (int i = 0; i < list.size(); i++) {
AhExcelReportRecode record = list.get(i);
rowIndex = getOneSheetTableStr(rowDataList, report.getSumType(),
sheetType, record, rowIndex);
}
Sheet sheet = sampleWb.getSheetAt(sheetType.getSheetNum());
rowDataList.add(getTotalTrString(sheet, colNum, colSpan, rowIndex));
map.put("dataList", rowDataList);
return map;
}
/**
* 获取汇总的table单元格信息
*
* @param xwb
* Workbook 工作表
* @param sheetType
* AhExcelReportSheet sheet类型信息
* @param rowDataList
* List<List<TableCellData>>
* @param record
* AhExcelReportRecode
* @param rowIndex
* int
* @return int
*/
public abstract int getTableTdStr(Workbook xwb,
AhExcelReportSheet sheetType,
List<List<TableCellData>> rowDataList, AhExcelReportRecode record,
int rowIndex);
/**
* 获取工作表sheet的标题行
*
* @param sheetType
* AhExcelReportSheet sheet类型信息
* @param list
* List<AhExcelReportRecode> 汇总工作表列表
* @return List<List<TableCellData>> 工作表sheet的标题行
* @throws Exception
*/
public abstract List<List<TableCellData>> getTableSubjectStr(
AhExcelReportSheet sheetType, List<AhExcelReportRecode> list)
throws Exception;
public AhExcelReportRecodeDao getAhExcelReportRecodeDao() {
return ahExcelReportRecodeDao;
}
public void setAhExcelReportRecodeDao(
AhExcelReportRecodeDao ahExcelReportRecodeDao) {
this.ahExcelReportRecodeDao = ahExcelReportRecodeDao;
}
/**
* 判断是否为合计行
*
* @param sheetType
* AhExcelReportSheet sheet类型信息
* @param row
* Row 当前读入行
* @return boolean 判断是否为合计行
*/
protected boolean isSumRow(AhExcelReportSheet sheetType, Row row) {
return SUM_STRING_CONSTANT.equals(AutoGenerateUtils.getCellValue(row,
sheetType.getCol()));
}
/**
* 判断该列是否进行汇总
*
* @param sheet
* Sheet 工作表sheet
* @param colIndex
* int 列索引
* @return boolean 判断该列是否进行汇总
*/
protected boolean isNotSumColumn(Sheet sheet, int colIndex) {
Row firstRow = sheet.getRow(0);
String cellValue = AutoGenerateUtils.getCellValue(firstRow, colIndex);
if (StringUtils.isBlank(cellValue)) {
return false;
}
try {
int value = (int) Double.parseDouble(cellValue);
return value == NOT_SUM_COL_FLAG;
} catch (NumberFormatException ex) {
return false;
}
}
/**
* 判断该列是否为除法运算列
*
* @param sheet
* Sheet 工作表sheet
* @param colIndex
* int 列索引
* @return boolean 判断该列是否进行汇总
*/
protected boolean isDividedColumn(Sheet sheet, int colIndex) {
Row firstRow = sheet.getRow(0);
String cellValue = AutoGenerateUtils.getCellValue(firstRow, colIndex);
if (StringUtils.isBlank(cellValue)) {
return false;
}
Matcher matcher = DIVIDE_FOMULA_PATTERN.matcher(cellValue);
Matcher joinMatcher = JOIN_DIVIDE_FOMULA_PATTERN.matcher(cellValue);
return matcher.find() || joinMatcher.find();
}
/**
* 根据工作表sheet中单元格的数值和索引进行累加生成汇总的值Map
*
* @param sheet
* Sheet 工作表sheet
* @param cellValue
* String 工作表sheet中单元格的数值
* @param index
* int 工作表sheet中单元格的索引
*/
protected void getTotalSumValueMap(Sheet sheet, String cellValue, int index) {
Double number = new Double(0);
String key = Integer.toString(index);
if (totalValueMap.containsKey(key)) {
number = totalValueMap.get(key);
}
if (isDividedColumn(sheet, index)) {
return;
}
if (StringUtils.isNotBlank(cellValue)) {
number += Double.parseDouble(cellValue);
}
totalValueMap.put(key, number);
return;
}
/**
* 根据工作表sheet中单元格的数值和索引进行累加生成关联汇总的值Map
*
* @param wb
* Workbook 工作表
* @param sheet
* Sheet 工作表sheet
* @param colIndex
* int 列索引
*/
protected void getJoinTotalSumValueMap(Workbook wb, Sheet sheet,
int colIndex) {
if (wbList.contains(wb)) {
return;
}
Double number = new Double(0);
Row firstRow = sheet.getRow(0);
if (AutoGenerateUtils.isEmpty(firstRow)) {
return;
}
String cellValue = AutoGenerateUtils.getCellValue(firstRow, colIndex);
Matcher joinMatcher = JOIN_DIVIDE_FOMULA_PATTERN.matcher(cellValue);
if (!joinMatcher.find()) {
return;
}
int sheetIndex = Integer.parseInt(joinMatcher.group(2));
int sheetColIndex = Integer.parseInt(joinMatcher.group(3));
Sheet joinSheet = wb.getSheetAt(sheetIndex);
AhExcelReportSheet sheetType = ahExcelReportSheetTypeDao.findUniqueBy(
"sheetNum", sheetIndex);
for (int i = DATA_START_ROW_INDEX; i < joinSheet
.getPhysicalNumberOfRows(); i++) {
Row row = joinSheet.getRow(i);
if (!isSumRow(sheetType, row)) {
continue;
}
String joinCellValue = AutoGenerateUtils.getCellValue(row,
sheetColIndex);
String key = Integer.toString(colIndex);
if (joinTotalValueMap.containsKey(key)) {
number = joinTotalValueMap.get(key);
}
if (StringUtils.isBlank(joinCellValue)) {
continue;
}
number += Double.parseDouble(joinCellValue);
joinTotalValueMap.put(key, number);
}
return;
}
/**
* 获取数据单元格的格式
*
* @param dataFirstRow
* Row 数据开始行
* @param cellIndex
* int 列索引
* @return DecimalFormat 数据单元格的格式
*/
protected DecimalFormat getNumberFormat(Row dataFirstRow, int cellIndex) {
DecimalFormat f = new DecimalFormat("#0.00");
Cell cell = dataFirstRow.getCell(cellIndex);
if (cell != null) {
CellStyle style = cell.getCellStyle();
String fmt = style.getDataFormatString();
if (fmt.endsWith(AutoGenerateUtils.PERCENT_SUFFIX)) {
f = new DecimalFormat(fmt);
}
}
return f;
}
/**
* 获取工作表的样本数据
*
* @param list
* List<AhExcelReportRecode> 工作表数据列表
* @return AhExcelReportRecode 工作表的样本数据
* @throws Exception
*/
private Workbook getSampleWorkbook(List<AhExcelReportRecode> list)
throws Exception {
AhExcelReportRecode record = list.get(0);
String path = record.getFileUrl();
Workbook xwb = AutoGenerateFactory.getWorkbook(path);
return xwb;
}
/**
* 获取包含合计行的sheet的列数
*
* @param xwb
* Workbook 工作表
* @param sheetType
* AhExcelReportSheet sheet类型信息
* @return int 汇总的列数
*/
private int getSumColNum(Workbook xwb, AhExcelReportSheet sheetType) {
Sheet sheet = xwb.getSheetAt(sheetType.getSheetNum());
Row row = sheet.getRow(DATA_START_ROW_INDEX - 1);
if (row == null) {
return 0;
}
int colNum = 0;
int startCol = SUM_START_COL_INDEX;
for (int i = startCol; i < row.getLastCellNum(); i++) {
String cellValue = AutoGenerateUtils.getCellValue(row, i);
if (StringUtils.isNotBlank(cellValue)) {
if (!isNotSumColumn(sheet, i)) {
colNum++;
}
}
}
return colNum;
}
/**
* 获取汇总“合计”所占列数
*
* @param report
* AhExcelReportRecode 汇总数据信息
* @param sheetType
* AhExcelReportSheet sheet类型信息
* @param xwb
* Workbook 工作表
* @return int 汇总“合计”所占列数
*/
private int getSumColSpan(AhExcelReportRecode report,
AhExcelReportSheet sheetType, Workbook xwb) {
int colSpan = 0;
if (AhExcelReportSheet.PROVINCE_SUM_TYPE.equals(report.getSumType())) {
Sheet sheet = xwb.getSheetAt(sheetType.getSheetNum());
for (int i = sheetType.getCol(); i < SUM_START_COL_INDEX; i++) {
if (!isNotSumColumn(sheet, i)) {
colSpan++;
}
}
} else {
colSpan = 1;
}
return colSpan;
}
/**
* 获取单个EXCEL表格数据的表格数据字串
*
* @param rowDataList
* List<List<TableCellData>>
* @param sumType
* String 统计类型
* @param sheetType
* AhExcelReportSheet sheet类型信息
* @param record
* AhExcelReportRecode 汇总数据信息
* @param rowIndex
* int
* @return int
* @throws Exception
*/
private int getOneSheetTableStr(List<List<TableCellData>> rowDataList,
String sumType, AhExcelReportSheet sheetType,
AhExcelReportRecode record, int rowIndex) throws Exception {
String path = record.getFileUrl();
Workbook xwb = AutoGenerateFactory.getWorkbook(path);
return getTableTdStr(xwb, sheetType, rowDataList, record, rowIndex);
}
/**
* 生成汇总后表格的“合计”行数据
*
* @param sheet
* Sheet 工作表中的sheet
* @param colNum
* int “合计”行的数据列数
* @param colSpan
* int “合计”行的所在列宽
* @param rowIndex
* int “合计”行的行索引
* @return List<TableCellData> 汇总后表格的“合计”行数据
*/
private List<TableCellData> getTotalTrString(Sheet sheet, int colNum,
int colSpan, int rowIndex) {
List<TableCellData> cellDataList = new ArrayList<TableCellData>();
TableCellData sumCellData = new TableCellData();
sumCellData.setColSpan(colSpan);
sumCellData.setCellValue("合计");
sumCellData.setRowIndex(rowIndex);
sumCellData.setColIndex(0);
cellDataList.add(sumCellData);
for (int i = 0; i < colNum; i++) {
sumCellData = new TableCellData();
int cellIndex = i + SUM_START_COL_INDEX;
if (isNotSumColumn(sheet, cellIndex)) {
continue;
}
String value = getTotalValue(sheet, Integer.toString(cellIndex));
sumCellData.setCellValue(value);
sumCellData.setRowIndex(rowIndex);
sumCellData.setColIndex(i + colSpan);
cellDataList.add(sumCellData);
}
return cellDataList;
}
/**
* 获取汇总的数值
*
* @param key
* String 单元格索引
* @param sheet
* Sheet 工作表sheet
* @return String 汇总的数值
*/
private String getTotalValue(Sheet sheet, String key) {
Row firstRow = sheet.getRow(0);
Row dataFirstRow = sheet.getRow(DATA_START_ROW_INDEX);
int cellIndex = Integer.parseInt(key);
String cellValue = AutoGenerateUtils.getCellValue(firstRow, cellIndex);
String value = "";
DecimalFormat f = getNumberFormat(dataFirstRow, cellIndex);
Matcher matcher = DIVIDE_FOMULA_PATTERN.matcher(cellValue);
if (matcher.find()) {
double numerator = totalValueMap.get(matcher.group(1));
double denominator = totalValueMap.get(matcher.group(2));
if (denominator == 0) {
value = f.format(0);
} else {
value = f.format(numerator / denominator);
}
return value;
}
Matcher joinMatcher = JOIN_DIVIDE_FOMULA_PATTERN.matcher(cellValue);
if (joinMatcher.find()) {
double numerator = totalValueMap.get(joinMatcher.group(1));
double denominator = joinTotalValueMap.get(key);
if (denominator == 0) {
value = f.format(0);
} else {
value = f.format(numerator / denominator);
}
return value;
}
if (totalValueMap.containsKey(key)) {
double number = totalValueMap.get(key);
value = f.format(number);
}
return value;
}
}