package hiro.yoshioka.sdh;

import hiro.yoshioka.util.StringUtil;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class CellParamList {
	private Log log = LogFactory.getLog(this.getClass());

	List<CellParam> list = new ArrayList<CellParam>();

	Map<Integer, List<CellParam>> hash;

	public CellParamList(StringRecordDataHolder sdh, int sampleNum,
			int lowestLetters) {
		int[] len = new int[sdh.getKey().length];
		boolean forceOneLine = false;
		for (int i = 0; i < len.length; i++) {
			len[i] = 0;
		}
		for (int irow = 0; irow < sdh.getRowCount() && irow < sampleNum; irow++) {
			String[] row = sdh.getRow(irow);
			for (int col = 1; col < row.length; col++) {
				if (len[col] < row[col].trim().length()) {
					len[col] = row[col].trim().length();
				}
			}
		}
		for (int i = 0; i < len.length; i++) {
			list.add(new CellParam(sdh.getKey()[i], len[i]));
			if (log.isDebugEnabled()) {
				log.debug(String.format("%02d[%03d] ", i + 1, len[i]));
			}
			if ((i + 1) % 10 == 0) {
				if (log.isDebugEnabled()) {
					log.debug(StringUtil.EMPTY_STRING);
				}
			}
		}
		if (log.isDebugEnabled()) {
			log.debug(StringUtil.EMPTY_STRING);
		}

		CellParam maxCell = null;
		int lineLength = getMaxCell(1).maxLength;
		if (sampleNum < 0 || lineLength < lowestLetters) {
			forceOneLine = true;
		}

		if (log.isDebugEnabled()) {
			log.debug(forceOneLine + " lowestLetters:" + lowestLetters
					+ " sampleNum:" + sampleNum + " getTotalLength(1):"
					+ getTotalLength(1));
		}

		if (lineLength < getTotalLength(1) / 3) {
			lineLength = getTotalLength(1) / 3;
		}

		int swapRow = 2;

		hash = new LinkedHashMap<Integer, List<CellParam>>();
		if (forceOneLine) {
			hash.put(new Integer(1), list);
			return;
		}

		for (int cn = 0; getTotalLength(1) > lineLength; cn++) {
			if (log.isDebugEnabled()) {
				log.debug(cn + " times >>" + lineLength + " swapRow:" + swapRow
						+ " getTotalLength(1):" + getTotalLength(1));
			}
			maxCell = getMaxCell(1);
			if (getTotalLength(swapRow) + maxCell.maxLength <= lineLength) {
				maxCell.row = swapRow;
			} else {
				swapRow++;
			}
		}
		// colspan
		for (int i = 0; i < list.size(); i++) {
			CellParam ccel = list.get(i);
			List<CellParam> mlist = hash.get(ccel.row);
			if (mlist == null) {
				mlist = new ArrayList<CellParam>();
				hash.put(ccel.row, mlist);
			}
			mlist.add(ccel);
		}
		List<CellParam> row1 = hash.get(1);
		for (int i = hash.size(); i >= 2; i--) {
			List<CellParam> mlist = hash.get(i);
			int totalLen = 0;
			int idx = 1; // row1 index
			int totalSpan = row1.size() - 1;
			if (mlist.size() == 1) {
				mlist.get(0).colSpan = row1.size() - 1;
				continue;
			}
			for (int j = 0; j < mlist.size(); j++) {
				if (j == mlist.size() - 1) {
					mlist.get(j).colSpan = (row1.size() - getTotalSpan(i));
					break;
				}
				for (; totalSpan > getTotalSpan(i); idx++) {
					totalLen += row1.get(idx).maxLength;
					mlist.get(j).colSpan++;

					if (mlist.get(j).maxLength <= totalLen) {
						break;
					}
				}
			}
		}
	}

	private CellParam getMaxCell(int rowNum) {
		int max = 0;
		CellParam maxCell = null;
		for (int i = 1; i < list.size(); i++) {
			if (list.get(i).row == rowNum) {
				if (max <= list.get(i).maxLength) {
					maxCell = list.get(i);
					max = maxCell.maxLength;
				}
			}
		}
		return maxCell;
	}

	private int getTotalLength(int rowNum) {
		int total = 0;

		for (int i = 0; i < list.size(); i++) {
			if (list.get(i).row == rowNum) {
				total += list.get(i).maxLength;
			}
		}
		return total;
	}

	private int getTotalSpan(int rowNum) {
		int total = 0;

		for (int i = 0; i < list.size(); i++) {
			if (list.get(i).row == rowNum) {
				total += list.get(i).colSpan;
			}
		}
		return total;
	}
}
