/*********************************************************************************************************
 * 프로그램명 : TagFilter.java 프로그램설명 : 프로젝트와 관련된 정보를 얻을수 있는 class 작성자 : 강원중 작성일 : 2004.01.06 변경일 : 2003.11.30
 **********************************************************************************************************/

package kr.co.kihyun.text.excel;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import kr.co.kihyun.lang.MString;

import kr.co.kihyun.moumi.doc.table.item.MItem;

import net.htmlparser.jericho.Attributes;
import net.htmlparser.jericho.Element;
import net.htmlparser.jericho.HTMLElementName;
import net.htmlparser.jericho.OutputDocument;
import net.htmlparser.jericho.Source;

public class Excel {

	public static String getHeader() {
		StringBuffer strbuf = new StringBuffer();
		strbuf.append("<html xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:x=\"urn:schemas-microsoft-com:office:excel\" xmlns=\"http://www.w3.org/TR/REC-html40\">\n");
		strbuf.append("<head>\n");
		strbuf.append("<meta http-equiv=Content-Type content=\"text/html; charset=UTF-8\">\n");
		strbuf.append("<meta name=ProgId content=Excel.Sheet>\n");
		strbuf.append("<meta name=Generator content=\"Microsoft Excel 10\">\n");
		strbuf.append("</head>\n");
		strbuf.append("<body>\n");

		return strbuf.toString();
	}

	public static String getTail() {
		StringBuffer strbuf = new StringBuffer();
		strbuf.append("</body>");
		strbuf.append("</html>");

		return strbuf.toString();
	}

	// TODO: move out these constants
      //v2. 5.static final 필드 변조 가능성 : Update by KWON,HAN         
//	public static final Pattern PATTERN_MS_CELL_NAME = Pattern.compile("[a-zA-Z]+[0-9]+");
//	public static final Pattern PATTERN_MS_CELL_ROW_NAME = Pattern.compile("(?<=[a-zA-Z]+)[0-9]+");
        
	private static final Pattern PATTERN_MS_CELL_NAME = Pattern.compile("[a-zA-Z]+[0-9]+");
	private static final Pattern PATTERN_MS_CELL_ROW_NAME = Pattern.compile("(?<=[a-zA-Z]+)[0-9]+");        
      //==========================================================                  

	public static String setCellTypes(String form, final int[] typeList) {
		Attributes.setDefaultMaxErrorCount(Integer.MAX_VALUE);

		Source source = new Source(form);
		OutputDocument outputDocument = new OutputDocument(source);

		List<Element> tdElements = source.getAllElements(HTMLElementName.TD);
		int tdNum = 0;
		for (Iterator<Element> x = tdElements.iterator(); x.hasNext() && tdNum < typeList.length; tdNum++) {
			Element tdElement = (Element) x.next();
			Attributes tdAttributes = tdElement.getAttributes();
			Map<String, String> attributesMap = outputDocument.replace(tdAttributes, false);
			if (typeList[tdNum] == MItem.INT)
				attributesMap.put("x:num", tdElement.getTextExtractor().toString().replaceAll(" ", "").trim());
			else
				attributesMap.put("x:str", null);
		}
		return outputDocument.toString();
	}

	public static String adjustFmlaToExcel(String form) {
		return Excel.modifyFmlaAll(form, 0);
	}

	public static String increaseFmlaAll(String form, int offset, int interval) {
		return Excel.increaseFmlaAll(form, new int[] { offset }, new int[] { interval }, new int[] { interval });
	}

	public static String increaseFmlaAll(String form, int offset, int interval, int increment) {
		return Excel.increaseFmlaAll(form, new int[] { offset }, new int[] { interval }, new int[] { increment });
	}

	public static String increaseFmlaAll(String form, int[] offset, int[] interval) {
		return Excel.increaseFmlaAll(form, offset, interval, interval);
	}

	// FIXME: duplicated code with modifyFmlaAll
	public static String increaseFmlaAll(String form, int[] _offset, int[] _interval, int[] _increment) {
		int[] offset = new int[_offset.length];
		int[] interval = new int[_interval.length];
		int[] increment = new int[_increment.length];
		System.arraycopy(_offset, 0, offset, 0, _offset.length);
		System.arraycopy(_interval, 0, interval, 0, _interval.length);
		System.arraycopy(_increment, 0, increment, 0, _increment.length);
		Attributes.setDefaultMaxErrorCount(Integer.MAX_VALUE);

		Source source = new Source(form);
		OutputDocument outputDocument = new OutputDocument(source);

		int tableNum = 0;
		List<Element> tableElements = source.getAllElements(HTMLElementName.TABLE);
		for (Iterator<Element> x = tableElements.iterator(); x.hasNext() && tableNum < offset.length; tableNum++) {
			Element tableElement = (Element) x.next();
			int j = 0;
			List<Element> trElements = tableElement.getAllElements(HTMLElementName.TR);
			for (Element trElement : trElements) {
				if (offset[tableNum] > 0) {
					offset[tableNum] = offset[tableNum] - 1;
					continue;
				}
				List<Element> tdElements = trElement.getChildElements();
				for (Element tdElement : tdElements) {
					Attributes tdAttributes = tdElement.getAttributes();
					Map<String, String> attributesMap = outputDocument.replace(tdAttributes, false);
					String fmla = tdElement.getAttributeValue("x:fmla");
					if (fmla != null) {
						fmla = Excel.modifyFmla(fmla, increment[tableNum] * ((int) j / interval[tableNum]));
						attributesMap.put("x:fmla", fmla);
					}
				}
				j++;
			}
		}

		return outputDocument.toString();
	}

	// FIXME: duplicated code with increaseFmlaAll
	// this method correct the MS Excel and HWP's cell referencing error
	public static String modifyFmlaAll(String form, int mod) {
		if (MString.isNull(form))
			return "";

		Attributes.setDefaultMaxErrorCount(Integer.MAX_VALUE);

		Source source = new Source(form);
		OutputDocument outputDocument = new OutputDocument(source);

		int sumBrCnt = 0, sumPCnt = 0;
		List<Element> trElements = source.getAllElements(HTMLElementName.TR);
		for (Element trElement : trElements) {
			int maxBrCnt = 0, maxPCnt = 0;
			List<Element> tdElements = trElement.getChildElements();
			for (Element tdElement : tdElements) {
				Attributes tdAttributes = tdElement.getAttributes();
				Map<String, String> attributesMap = outputDocument.replace(tdAttributes, false);
				String fmla = tdElement.getAttributeValue("x:fmla");
				if (fmla != null) {
					fmla = Excel.modifyFmla(fmla, mod == 0 ? sumBrCnt + sumPCnt : mod);
					attributesMap.put("x:fmla", fmla);
				}

				int brCnt = tdElement.getAllElements(HTMLElementName.BR).size();
				int pCnt = tdElement.getAllElements(HTMLElementName.P).size();
				if (pCnt > 0)
					pCnt--;
				maxBrCnt = (brCnt > maxBrCnt) ? brCnt : maxBrCnt;
				maxPCnt = (pCnt > maxPCnt) ? pCnt : maxPCnt;
			}
			sumBrCnt += maxBrCnt;
			sumPCnt += maxPCnt;
		}

		return outputDocument.toString();
	}

	// TODO: rename me
	public static String modifyFmla(String fmla, int increment) {
		Matcher cellMatcher = PATTERN_MS_CELL_NAME.matcher(fmla);
		int currCellPos = -1;
		while (cellMatcher.find()) {
			String cellName = cellMatcher.group();
			currCellPos = fmla.indexOf(cellName, currCellPos);
			Matcher rowMatcher = PATTERN_MS_CELL_ROW_NAME.matcher(cellName);
			while (rowMatcher.find()) {
				String rowName = (Integer.parseInt(rowMatcher.group()) + increment) + "";
				fmla = fmla.substring(0, currCellPos)
						+ (fmla.substring(currCellPos, fmla.length())).replaceAll(cellName,
								cellName.replaceAll("[0-9]+", rowName));
				currCellPos += cellName.replaceAll("[0-9]+", rowName).length();
			}
		}
		return fmla;
	}

	public static String removeFmla(String form) {
		form = form.replaceAll("x:fmla", "x:x");
		return form.replaceAll("x:num", "x:x");
	}
}
