/*********************************************************************************************************
 * 프로그램명 : CalculationForm.java 프로그램설명 : 엑셀변환시 엑셀에 적용되는 수식을 처리하는곳 작성자 : 강원중 작성일 : 2004-12-02 변경일 : 2005-02-04
 **********************************************************************************************************/

package kr.co.kihyun.text.excel;

import java.util.ArrayList;
import java.util.List;

import kr.co.kihyun.lang.MInteger;
import kr.co.kihyun.lang.MString;
import kr.co.kihyun.moumi.doc.table.item.MItem;

public class CalculationForm {

	public static String getCalculationForm(String expr, int rowNum, String type) {

		// 필요없는 EXPR ^
		if (MString.isNull(expr) || expr.indexOf("^") > -1 || expr.indexOf("~") > -1)
			return expr;

		// "SUM", "(", ")", ":", ",", "+", "-", "*", "/"
		// SUM(B9:F99)
		char[] charList = expr.toCharArray(); // 수식을 char array로 변환
		int[] charInfoList = null;
		int[] numList = null;
		int charCount = 0;

		charCount = charList.length;

		// char infomation array, num value array create
		if (charList.length > 0) {
			charInfoList = new int[charCount];
			numList = new int[charCount];
		} else {
			return expr;
		}

		// char array analysis
		for (int i = 0; i < charCount; i++) {

			if (48 <= (int) charList[i] && (int) charList[i] <= 57) {
				numList[i] = Integer.parseInt(Character.toString(charList[i]));
				charInfoList[i] = MItem.INT;
			} else if ((65 <= (int) charList[i] && (int) charList[i] <= 90)
					|| (97 <= (int) charList[i] && (int) charList[i] <= 122)) {
				// a: 97, z: 122, A: 65, Z: 90
				charInfoList[i] = MItem.CHAR;
			} else {
				charInfoList[i] = MItem.SPCHAR; // 수식 == 기타 문자
			}
		}

		// item name에 포함되어있는 숫자의 값을 행(rowNum)만큼 증가 시키거나 감소 시킴
		StringBuffer exprbuf = new StringBuffer(); // 분리된 수식을 StringBuffer에 하나씩 변환하여 추가
		String tmpNum = ""; // item name에 속한 숫자를 문자로 표시
		boolean isItemNum = false; // item name에 속한 숫자들 이라면 append해라 "1"+"2"....

		for (int i = 0; i < charCount; i++) {
			if (charInfoList[i] == MItem.CHAR) { // 문자이고
				if (charInfoList[i] == 's' || charInfoList[i] == 'S') {
					isItemNum = true;
				} else if (i > 0 && (charInfoList[i] == 'u' || charInfoList[i] == 'U')) {
					isItemNum = true;
				} else if (i > 1 && (charInfoList[i] == 'm' || charInfoList[i] == 'M')) { // SUM으로 이건 Item name이 아니다
					isItemNum = false;
				} else { // sum을 뺀 나머지는 다 Item name이다
					isItemNum = true;
				}
				exprbuf.append(charList[i]);
			} else if (charInfoList[i] == MItem.INT) { // 숫자이고
				if (i > 0 && MItem.CHAR == charInfoList[i - 1] && isItemNum) { // Item name이며 첫번째 숫자임
					tmpNum = Integer.toString(numList[i]);
					isItemNum = true;
				} else if (i > 0 && MItem.INT == charInfoList[i - 1] && isItemNum) { // Item name이며 두번째 숫자임
					tmpNum += Integer.toString(numList[i]);
					isItemNum = true;
				} else { // Item name이 아닌 그냥 숫자라면
					exprbuf.append(charList[i]);
					isItemNum = false;
				}

				if ((i == (charCount - 1) || MItem.INT != charInfoList[i + 1]) && isItemNum) {
					if (type != null && type.equals("add")) { // 동적표에서 보고자료 보기시 보고한 행에 따라 수식을 변경해줌
						exprbuf.append((MInteger.parseInt(tmpNum) + rowNum));
					} else if (type != null && type.equals("sub")) { // 두개의 표를 등록할때 Form에 적용되는 수식사용
						exprbuf.append((MInteger.parseInt(tmpNum) - rowNum));
					}
				}
			} else {
				exprbuf.append(charList[i]);
				isItemNum = false;
			}
		}

		return exprbuf.toString();
	}

	// 보고자가 보고한 하나의 동적표의 total을 작성할때 사용하는 수식
	public static String getDynaReportTotCalculationForm(String itemName, int titleRowCount, int rowCount) {
		if (MString.isNull(itemName))
			return "";
		itemName = Character.toString((itemName.toCharArray())[0]);

		StringBuffer strbuf = new StringBuffer();
		strbuf.append("SUM(");
		strbuf.append(itemName);
		strbuf.append((titleRowCount + 1));
		strbuf.append(":");
		strbuf.append(itemName);
		strbuf.append((rowCount + titleRowCount));
		strbuf.append(")");

		return getCalculationForm(strbuf.toString());
	}

	// 엑셀에서 사용하는 수식 테그
	public static String getCalculationForm(String sumStr) {

		if (MString.isNull(sumStr))
			return "";

		StringBuffer strbuf = new StringBuffer();
		strbuf.append(" x:num=\"0\" x:fmla=\"=");
		strbuf.append(sumStr);
		strbuf.append("\"");

		return strbuf.toString();
	}

	// FIXME : remove me.
	public static String getCalculationForms(String arrayName, String propName, String sData) {

		int stTDIndex = 0;
		int edTDIndex = 0;
		int stExIndex = 0;
		int edExIndex = 0;
		int exHeadIndex = 0;
		int index = -1;

		String headEx = "x:fmla=";
		String stEx = "=";
		String edEx = "\"";
		String tdContext = null;
		String endResult = null;
		StringBuffer exprbuf = new StringBuffer();

		while (true) {
			stTDIndex = sData.indexOf("<td", stTDIndex + 1);
			if (stTDIndex == -1)
				break;
			index++;

			edTDIndex = sData.indexOf(">", stTDIndex);
			if (stTDIndex == -1)
				break;

			tdContext = sData.substring(stTDIndex, edTDIndex + 1); // TD의 옵션 내용
			exHeadIndex = tdContext.indexOf(headEx);
			// 예) <td nowrap x:num x:fmla="=sum(c2:c5)" >

			if (exHeadIndex != -1) {
				stExIndex = tdContext.indexOf(stEx, exHeadIndex + headEx.length()); // x:fmla="=sum(c2:c5)" 에서 첫번째 `=` 를
																					// 검색
				edExIndex = tdContext.indexOf(edEx, stExIndex + stEx.length()); // x:fmla="=sum(c2:c5)" 에서 마지막 `"`를 검색
				endResult = tdContext.substring(stExIndex + stEx.length(), edExIndex);
				endResult = endResult.toUpperCase();
				exprbuf.append(arrayName);
				exprbuf.append("[");
				exprbuf.append(index);
				exprbuf.append("].");
				exprbuf.append(propName);
				exprbuf.append(" = '");
				exprbuf.append(endResult);
				exprbuf.append("';\n");
			}
		}
		return exprbuf.toString();
	}

	// 엑셀 sum수식을 javascript itemExprList로 추출
	public static String getCalculationForms(String sData) {

		int stTDIndex = 0;
		int edTDIndex = 0;
		int stExIndex = 0;
		int edExIndex = 0;
		int exHeadIndex = 0;
		int index = -1;

		String headEx = "x:fmla=";
		String stEx = "=";
		String edEx = "\"";
		String tdContext = null;
		String endResult = null;
		StringBuffer exprbuf = new StringBuffer();

		while (true) {
			stTDIndex = sData.indexOf("<td", stTDIndex + 1);
			if (stTDIndex == -1)
				break;
			index++;

			edTDIndex = sData.indexOf(">", stTDIndex);
			if (stTDIndex == -1)
				break;

			tdContext = sData.substring(stTDIndex, edTDIndex + 1); // TD의 옵션 내용
			exHeadIndex = tdContext.indexOf(headEx);
			// 예) <td nowrap x:num x:fmla="=sum(c2:c5)" >

			if (exHeadIndex != -1) {
				stExIndex = tdContext.indexOf(stEx, exHeadIndex + headEx.length()); // x:fmla="=sum(c2:c5)" 에서 첫번째 `=` 를
																					// 검색
				edExIndex = tdContext.indexOf(edEx, stExIndex + stEx.length()); // x:fmla="=sum(c2:c5)" 에서 마지막 `"`를 검색
				endResult = tdContext.substring(stExIndex + stEx.length(), edExIndex);
				endResult = endResult.toUpperCase();
				exprbuf.append("itemExprList[");
				exprbuf.append(index);
				exprbuf.append("] = '");
				exprbuf.append(endResult);
				exprbuf.append("';\n");
			}
		}
		return exprbuf.toString();
	}

	// 엑셀 sum수식을 javascript itemExprList로 추출
	// TODO refactoring, duplicated code with getCalculationForms(String)
	public static List<String> getExprList(String sData) {
		List<String> exprList = new ArrayList<String>();

		int stTDIndex = 0;
		int edTDIndex = 0;
		int stExIndex = 0;
		int edExIndex = 0;
		int exHeadIndex = 0;
		int index = -1;

		String headEx = "x:fmla=";
		String stEx = "=";
		String edEx = "\"";
		String tdContext = null;
		String endResult;
		;
		StringBuffer exprbuf = new StringBuffer();

		while (true) {
			endResult = null;
			stTDIndex = sData.indexOf("<td", stTDIndex + 1);
			if (stTDIndex == -1)
				break;
			index++;

			edTDIndex = sData.indexOf(">", stTDIndex);
			if (stTDIndex == -1)
				break;

			tdContext = sData.substring(stTDIndex, edTDIndex + 1); // TD의 옵션 내용
			exHeadIndex = tdContext.indexOf(headEx);
			// 예) <td nowrap x:num x:fmla="=sum(c2:c5)" >

			if (exHeadIndex != -1) {
				stExIndex = tdContext.indexOf(stEx, exHeadIndex + headEx.length()); // x:fmla="=sum(c2:c5)" 에서 첫번째 `=` 를
																					// 검색
				edExIndex = tdContext.indexOf(edEx, stExIndex + stEx.length()); // x:fmla="=sum(c2:c5)" 에서 마지막 `"`를 검색
				endResult = tdContext.substring(stExIndex + stEx.length(), edExIndex);
				endResult = endResult.toUpperCase();
				exprbuf.append("itemExprList[");
				exprbuf.append(index);
				exprbuf.append("] = '");
				exprbuf.append(endResult);
				exprbuf.append("';\n");
			}
			exprList.add(endResult);
		}
		return exprList;
	}
}
