package com.zjrs.appcomm.template.excel.mapper;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.List;
import java.util.Map;

/**
 * 单列中行合并逻辑
 */
public class FieldMergeCellStyler implements CellStyler {

	private Object[] lastValue;
	private int lastRowIndex;
	private int lastCellIndex;
	private CellRangeAddress currentRange;
	private int currentRangeIndex;

	private String[] relatedField;

	/**
	 *
	 * @param relatedField 需要关联的相关字段(用于防止不必要的单元格合并)
	 */
	public FieldMergeCellStyler(String... relatedField) {
		this.relatedField = relatedField;
	}
	
	@Override
	public boolean style(Cell cell, Object value, String field, int dataIndex, int rowIndex, int cellIndex, Map<?, ?> row) {
		Object[] currentValues = values(value, row);
		if (lastValue == null) {
			lastValue = currentValues;
			lastRowIndex = rowIndex;
			lastCellIndex = cellIndex;
			currentRange = null;
		} else {
			if (isEquals(lastValue, currentValues)) {
				if (currentRange == null) {
					currentRange = new CellRangeAddress(lastRowIndex, rowIndex, lastCellIndex, cellIndex);
					currentRangeIndex = cell.getSheet().addMergedRegionUnsafe(currentRange);
				} else {
					if (currentRangeIndex >= cell.getSheet().getNumMergedRegions()
							|| !currentRange.equals(cell.getSheet().getMergedRegion(currentRangeIndex))) {
						/* 当多列存在合并需求时，存在合并配置的角标混乱的情况 */
						List<CellRangeAddress> rangeList = cell.getSheet().getMergedRegions();
						for (int i = 0; i < rangeList.size(); i++) {
							if (currentRange.equals(rangeList.get(i))) {
								currentRangeIndex = i;
								break;
							}
						}
					}
					cell.getSheet().removeMergedRegion(currentRangeIndex);
					currentRange.setLastRow(rowIndex);
					currentRange.setLastColumn(cellIndex);
					currentRangeIndex = cell.getSheet().addMergedRegionUnsafe(currentRange);
				}
				return false;
			} else {
				lastValue = currentValues;
				lastRowIndex = rowIndex;
				lastCellIndex = cellIndex;
				currentRange = null;
			}
		}
		return true;
	}

	private Object[] values(Object value, Map<?, ?> row) {
		Object[] values = new Object[relatedField.length + 1];
		for (int i = 0; i < relatedField.length; i++) {
			values[i] = row.get(relatedField[i]);
		}
		values[values.length - 1] = value;
		return values;
	}

	private boolean isEquals(Object[] o1, Object[] o2) {
		if (o1.length != o2.length) {
			return false;
		} else {
			for (int i = 0; i < o1.length; i++) {
				if (!isEquals(o1[i], o2[i])) {
					return false;
				}
			}
			return true;
		}
	}

	private boolean isEquals(Object o1, Object o2) {
		if (o1 == null && o2 == null) {
			return true;
		} else if (o1 == null || o2 == null) {
			return false;
		} else {
			return o1.equals(o2);
		}
	}
}
