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

package kr.co.kihyun.text.html;

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

import kr.co.kihyun.moumi.MoumiConfig;
import kr.co.kihyun.lang.MString;
import net.htmlparser.jericho.Attributes;
import net.htmlparser.jericho.CharacterReference;
import net.htmlparser.jericho.Element;
import net.htmlparser.jericho.HTMLElementName;
import net.htmlparser.jericho.OutputDocument;
import net.htmlparser.jericho.Source;

public class TagFilter {
	public static String convertSingle(String form) {
		// TODO : tag의 속성이 '로 들어간 경우에는 코드값으로 변환이 일어나서 그부분을 해결 해줘야 함 예)align='center';
		form = form.replaceAll("'", "&#39;");
		return form;
	}

	public static String getConvertForm(String form) {
		// 문서 등록시 테이블에만 removeBlankPara 를 적용하는 함수
		StringBuilder reportBuf = new StringBuilder();
		int stTable = 0;
		int edTable = 0;
		int here = 0;

		while (true) {
			stTable = form.indexOf("<table", edTable);
			if (stTable == -1) {
				if (edTable + 8 < form.length())
					reportBuf.append(form.substring(edTable + 8, form.length()));

				break;
			}

			if (here == 0) {
				reportBuf.append(form.substring(here, stTable));
				here++;
			} else {
				here = edTable + 8;
				reportBuf.append(form.substring(here, stTable));
			}

			edTable = form.indexOf("</table>", stTable);
			if (edTable == -1) {
				break;
			} else {
				reportBuf.append(TagFilter.removeBlankPara(form.substring(stTable, edTable + 8)));
			}
		}
		return reportBuf.toString();
	}

	// white space P 태그 제거
	public static String removeBlankPara(String form) {
		if (MString.isNull(form))
			return "";

		Attributes.setDefaultMaxErrorCount(Integer.MAX_VALUE);

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

		List<Element> pElements = source.getAllElements(HTMLElementName.P);
		for (Element pElement : pElements)
			if (MString.isNull(pElement.getTextExtractor().setConvertNonBreakingSpaces(true).toString()))
				outputDocument.remove(pElement);

		return outputDocument.toString();
	}

	public static String removeTableHeight(String form) {
		Attributes.setDefaultMaxErrorCount(Integer.MAX_VALUE);

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

		List<Element> tableElements = source.getAllElements(HTMLElementName.TABLE);
		for (Element tableElement : tableElements) {
			Attributes tableAttributes = tableElement.getAttributes();
			Map<String, String> attributesMap = outputDocument.replace(tableAttributes, false);
			if (tableAttributes.equals("height"))
				attributesMap.put("height", tableElement.getTextExtractor().toString().replaceAll("　", ""));
		}
		return outputDocument.toString();
	}

	public static String removeXmlNamepace(String form) {
		Attributes.setDefaultMaxErrorCount(Integer.MAX_VALUE);

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

		List<Element> pElements = source.getAllElements(HTMLElementName.P);

		for (Element pElement : pElements)
			// if(pElement.getTextExtractor().toString().contains("namespace prefix"))
			// if(pElement.getTextExtractor().toString().contains("urn:schemas-microsoft-com:office:office"))
			if (pElement.getTextExtractor().toString()
					.contains("<?xml:namespace prefix = o ns = \"urn:schemas-microsoft-com:office:office\" />"))
				outputDocument.remove(pElement);

		return outputDocument.toString();
	}

	public static boolean quotationCheckForm(String form) {
		Attributes.setDefaultMaxErrorCount(Integer.MAX_VALUE);
		boolean check = true;
		String tdString = "";
		Source source = new Source(form);
		List<Element> tdElements = source.getAllElements(HTMLElementName.TD);
		for (Element tdElement : tdElements) {
			tdString = tdElement.getTextExtractor().toString();
			if (tdString.indexOf("\"") == 0 || tdString.indexOf("\'") == 0) {
				check = false;
				break;
			}
		}
		return check;
	}

	// ----------------------------------------------------------------------------------------------
	// choyongjun tagFilter job
	public static String baseFilter(String form) {
		form = removeGarbage(form);
		form = excelTailDelete(form); // excel 꼬리에 붙는 <![if supportmisalignedcolumns]> 날림
		form = removePre(form); // 한글 97버전에서 나오는 <pre> <br></pre>삭제
		form = excelSumSuTextToSpace(form); // 엑셀 sum수식 부분에 텍스트 들어 있는것을 공백으로 바뀌어 주기위한 로직
		form = HtmlUtil.addTABLE(form);
		form = HtmlUtil.addTR(form);
		// form = setBorder(form, 1);
		return form;
	}

	public static String filter(String form) {
		form = removeGarbage(form);
		form = excelTailDelete(form);
		form = removePre(form);
		form = excelSumSuTextToSpace(form);
		form = removeHeight(form);
		form = removeWidth(form);
		form = HtmlUtil.addTABLE(form); // 복사양식에서 테이블 태그가 없을때 넣어준다
		form = HtmlUtil.addTR(form); // 한글 97 <table>다음 <tr>없음, </tr>이 없음 두가지 추가
		form = setBorder(form, 1);

		return form;
	}

	// 폰트 사이즈, 칸띄우기, TD 옵션 다 날림
	public static String severeFilter(String form) {
		form = MString.delete(form, "<style", "</style>");// <style~</style> remove
		form = MString.delete(form, "<span", ">");// <span> remove
		form = removeSpan(form);// </span> remove
		form = MString.convert(form, "<p", ">", "<p>");// <p> remove 주석 by 구경모
		form = MString.delete(form, "</p", ">");// <p> remove
		form = removeCRLF(form);
		form = makeTD(form);

		return form;
	}

	// modify by 구경모
	public static String severeFilter2(String form) {
		// form = MString.orDelete(form, "border-left:", "solid,double,dotted,;");
		// form = MString.orDelete(form, "border-right:", "solid,double,dotted,;");
		// form = MString.orDelete(form, "border-top:", "solid,double,dotted,;");
		// form = MString.orDelete(form, "border-bottom:", "solid,double,dotted,;");
		form = MString.delete(form, "background:", ";");
		form = MString.delete(form, "bgcolor", " ");
		// form = MString.orDelete(form, "<div", "</div>");
		// form = MString.delete(form, "line-height:", ";");
		// form = MString.delete(form, "<div", ">");
		// form = MString.delete(form, "</div", ">");
		// form = MString.delete(form, "<img", ">");
		// form = MString.convert(form, "width", "=", "width='100%' hh=");

		// form = MString.convert(form, "border=", ">", "border=1>");
		// form = MString.convert(form, "border-left:", "pt", "border-left: #000000 0.0pt");
		// form = MString.convert(form, "border-right:", "pt", "border-right: #000000 0.0pt");
		// form = MString.convert(form, "border-top:", "pt", "border-left: #000000 0.0pt");
		// form = MString.convert(form, "border-bottom:", "pt", "border-bottom: #000000 0.0pt");

		return form;
	}

	public static String borderFilter(String form) {
		// form = MString.convert(form, "border=", ">", "border='2'>");
		// form = MString.convert(form, "border-left:", "pt", "border-left: #000000 0.5pt");
		// form = MString.convert(form, "border-right:", "pt", "border-right: #000000 0.5pt");
		// form = MString.convert(form, "border-top:", "pt", "border-top: #000000 0.5pt");
		// form = MString.convert(form, "border-bottom:", "pt", "border-bottom: #000000 0.5pt");
		return form;
	}

	public static String excelBorderFilter(String form) {
		int stTD = 0;
		int edTD = 0;

		StringBuffer editForm = new StringBuffer();

		stTD = form.indexOf("<td", stTD);

		for (edTD = form.indexOf(">", stTD + 1); stTD > -1 && edTD > -1; stTD = form.indexOf("<td", 0)) {
			editForm.append(form.substring(0, stTD));
			form = form.substring(stTD);
			edTD = form.indexOf(">");

			int stStyle = form.indexOf("style=");
			int edStyle = form.indexOf("\"", stStyle + 7);

			if (stStyle > -1 && edStyle > -1) {
				if (stStyle < edTD && edStyle < edTD) {
					editForm.append(form.substring(0, stStyle));
					form = form.substring(edStyle);
				}
			}
		}

		editForm.append(form);

		return editForm.toString();
	}

	public static String pFilter(String form) {
		form = MString.delete(form, "<p", ">");
		form = MString.delete(form, "</p", ">");
		return form;
	}

	public static String excelBaseFilter(String form) {
		form = removeGarbage(form);
		form = excelTailDelete(form); // excel 꼬리에 붙는 <![if supportmisalignedcolumns]> 날림
		form = removePre(form); // 한글 97버전에서 나오는 <pre> <br></pre>삭제
		form = HtmlUtil.addTABLE(form);
		form = HtmlUtil.addTR(form);
		form = setBorder(form, 1);
		return form;
	}

	// ----------------------------------------------------------------------------
	// 태그 필터 하는 부분
	/*
	 * public static String htmlFilter(String form){ //ban lower case form = form.toLowerCase(); //form =
	 * MString.delete(form, "<style", "</style>");//<style~</style> remove //form = MString.delete(form, "<span",
	 * ">");//<span> remove //form = removeSpan(form);//</span> remove //form = MString.delete(form, "<p", ">");//<p>
	 * remove //form = removeCRLF(form); //form = removeTRContent(form);//<tr 와 >사이에 내용 삭제 form = makeTD(form);
	 * 
	 * return form; }
	 */

	/*
	 * public static String filter(String form){ form = removeGarbage(form); form = excelTailDelete(form); form =
	 * removePre(form); form = excelSumSuTextToSpace(form); form = removeHeight(form); form = removeWidth(form); form =
	 * HtmlUtil.addTABLE(form); //복사양식에서 테이블 태그가 없을때 넣어준다 form = HtmlUtil.addTR(form); //한글 97 <table>다음 <tr>없음, </tr>이
	 * 없음 두가지 추가 form = setBorder(form, 1);
	 * 
	 * return form; }
	 */
	// --------------------------------------------------------------------------------

	public static String printFilter(String form) {

		// form = removeStyle(form);
		form = removeHeight(form);
		form = removeWidth(form);

		return form;
	}

	public static String excelTailDelete(String form) {

		// ban lower case form = form.toLowerCase();
		String startStr = "<![if supportmisalignedcolumns]>";
		String endStr = "<![endif]>";

		return MString.delete(form, startStr, endStr);
	}

	public static String setBorder(String form, int border) {
		return setBorder(new StringBuffer(form), border);
	}

	public static String setBorder(StringBuffer form, int border) {

		String strTag = "<table";
		String endTag = ">";
		int strIndex = form.indexOf(strTag);
		int endIndex = form.indexOf(endTag, strIndex);
		String tmpTableTag;

		String strWidth = "width=";
		String endWidth = " ";
		int strWidthIndex = -1;
		int endWidthIndex = -1;

		if (strIndex != -1 && endIndex != -1) {
			tmpTableTag = form.substring(strIndex, endIndex);
			strWidthIndex = tmpTableTag.indexOf(strWidth);
			endWidthIndex = tmpTableTag.indexOf(endWidth, strWidthIndex);
		}

		if (strWidthIndex != -1 && endWidthIndex != -1) {
			return setBorderHWP(form, border);
		} else {
			return setBorderExcel(form, border);
		}
	}

	// 엑셀용
	public static String setBorderExcel(StringBuffer form, int border) {
		return setBorderExcel(form.toString(), border);
	}

	public static String setBorderExcel(String form, int border) {
		// ban lower case form = form.toLowerCase();
		String strTag = "<table";
		String endTag = ">";
		String inTag = "<table cellspacing=0 cellpadding=0 width='100%' border=" + border + ">";
		return MString.convert(form, strTag, endTag, inTag);
	}

	// 한글 97용
	public static String setBorderHWP(String form, int border) {
		return setBorderHWP(new StringBuffer(form), border);
	}

	public static String setBorderHWP(StringBuffer form, int border) {
		String strTag = "<table";
		String endTag = ">";
		String inTag = "<table cellspacing=0 cellpadding=0 border=" + border + " width=";

		int strIndex = form.indexOf(strTag);
		int endIndex = form.indexOf(endTag, strIndex);
		String tmpTableTag;

		String strWidth = "width=";
		String endWidth = " ";
		String width = "";

		int strWidthIndex;
		int endWidthIndex;
		while (strIndex != -1 && endIndex != -1) {
			// 1) 해당 테그를 삭제한다
			// 2) width를 알아낸다
			// 3) 추출한 width를 inTag에 적용한다
			// 4) 삭제한곳에 생성한 입력 테그를 넣는다.
			tmpTableTag = form.substring(strIndex, endIndex);
			strWidthIndex = tmpTableTag.indexOf(strWidth);
			endWidthIndex = tmpTableTag.indexOf(endWidth, strWidthIndex);
			if (strWidthIndex != -1 && endWidthIndex != -1) {
				form.delete(strIndex, endIndex); // 1) 기존양식의 해당 태그 삭제
				width = tmpTableTag.substring(strWidthIndex + strWidth.length(), endWidthIndex); // 2) table의 width값 추출
				form.insert(strIndex, inTag + width); // 3) 기존양식에 width를 적용한 in tag 삽입
			}

			strIndex = form.indexOf(strTag, endIndex);
			endIndex = form.indexOf(endTag, strIndex);
		}
		return form.toString();
	}

	// 양식보기에서 <td ~ </td> 사이의 공백을 &nbsp로 변환
	public static String convertSpace(String form) {
		if (MString.isNull(form))
			return form;
		return convertSpace(new StringBuffer(form));
	}

	public static String convertSpace(StringBuffer form) {
		// <td> </td> 사이가 공백이라면 그사이에 &nbsp;를 넣어라
		// <td></td>상이의 문자 추출 공백인지 비교
		// 공백이라면 공백을 제거하고&nbsp;입력

		String strTag = "<td";
		String strTag2 = ">";
		String endTag = "</td>";
		String inTag = "&nbsp;";
		int strIndex = -1;
		int endIndex = -1;
		String tmpStr = "";

		while (true) {
			strIndex = form.indexOf(strTag, endIndex);
			if (strIndex == -1)
				break;
			strIndex = form.indexOf(strTag2, strIndex);
			strIndex += strTag2.length();
			endIndex = form.indexOf(endTag, strIndex);
			tmpStr = form.substring(strIndex, endIndex);
			if (tmpStr.trim().equals("")) {
				form.delete(strIndex, endIndex);
				form.insert(strIndex, inTag);
				endIndex = endIndex + (inTag.length() - (tmpStr.length()));
			}
		}

		return form.toString();
	}

	// 인쇄 재대로 되게
	public static String convertTD(String form) {
		return form.replaceAll("<td", "<td nowrap");
	}

	// -------------------------------------------------------
	public static String convertP(String form) {
		return form.replaceAll("</p>", "<br>");
	}

	public static String convertPAll(String form) {
		// <p>&nbsp;</p>삭제 함
		return form.replaceAll("<p>&nbsp;</p>", " ");
	}

	public static String convertMeta(String form) {
		form = form.replaceAll("'", "`");
		form = form.replaceAll("\"", "``");
		form = form.replaceAll("<", "&lt;");
		form = form.replaceAll(">", "&gt;");
		form = form.replaceAll("\\(", "&#40;");
		form = form.replaceAll("\\)", "&#41;");
		form = form.replaceAll("#", "&#35;");
		form = form.replaceAll("&", "&#38;");
                
                // xss 공격을 방지하기 위해 위의 replace 까지 처리하면, UI 출력시 괄호가 표현이 안된다. 2014.12.10 by YOUNGJUN,CHO
                // 괄호를 출력할 수 있도록 다시 replace 처리한다.
                form = form.replaceAll("&#38;&#38;#35;40;", "&#40;");
		form = form.replaceAll("&#38;&#38;#35;41;", "&#41;");
                
		return form;
	}

	public static String unconvertedMeta(String form) {
		form = form.replaceAll("&lt;", "<");
		form = form.replaceAll("&gt;", ">");
		form = form.replaceAll("&#40;", "\\(");
		form = form.replaceAll("&#41;", "\\)");
		form = form.replaceAll("&#35;", "#");
		form = form.replaceAll("&#38;", "&");

		while (form.indexOf("&&#35;40;") != -1 || form.indexOf("&&#35;41;") != -1) {
			form = form.replaceAll("&&#35;40;", "(");
			form = form.replaceAll("&&#35;41;", ")");
		}
                
		return form;
	}

	public static String removeSpan(String form) {
		return form.replaceAll("</span>", "");
	}

	// --------------------------------------------------------

	public static String removeStyle(String form) {
		return form.replaceAll("style", "hh");
	}

	public static String removeHeight(String form) {
		return form.replaceAll("height", "hh");
	}

	public static String removeWidth(String form) {
		return form.replaceAll("width", "hh");
	}

	// CRLF
	public static String removeCRLF(String form) {
		return form.replaceAll("\r\n", " ");
	}

	public static String removeGarbage(String form) {
		String strTag = "<";
		String endTag = ">";

		int strIndex = form.indexOf(strTag);
		int endIndex = form.indexOf(endTag);

		if (endIndex >= 0 && endIndex < strIndex) {
			form = form.substring(endIndex + endTag.length());
		}

		return form;
	}

	// tag 정리하는 로직(개발중)
	// ----------------------------------------------------------------------------------------------------
	// <tr 와 >사이에 내용 삭제
	public static String removeTRContent(String from) {

		return MString.convert(from, "<tr", ">", "<tr>");
	}

	public static String makeTD(String form) {

		int strIndex = 0;
		int endIndex = 0;
		int count = 0;
		String startStr = "<td";
		String endStr = ">";
		String tdOld = "";
		String tdNew = "";
		StringBuffer string = new StringBuffer(form);

		while (true) {
			strIndex = string.indexOf(startStr, strIndex);
			endIndex = string.indexOf(endStr, strIndex);

			// string table 삭제
			if (strIndex == -1 || endIndex == -1)
				break;
			tdOld = string.substring(strIndex, endIndex + endStr.length());
			string = string.delete(strIndex, endIndex + endStr.length());
			if (MString.isWidthORHeightORColsORRowsORSum(tdOld)) {
				tdNew = newMakeTD(tdOld);
			} else {
				tdNew = "<td>";
			}
			string = string.insert(strIndex, tdNew);
			count++;

			strIndex++;
		}

		return string.toString();
	}

	// choyongjun tagFilter job
	// <td 와 > 사이에서 width, height, rowspan, colspan, 엑셀 수식 살리는 로직
	public static String newMakeTD(String tdOld) {
		String newMakeTD = "<td ";
		String tmp = "";
		int stRowspan = 0;
		int stColspan = 0;
		int stWidth = 0;
		int stHeight = 0;
		int stSum = 0;
		int space = 0;
		tdOld = tdOld.replaceAll("\'", "");
		tdOld = tdOld.replaceAll("\"", "");

		stRowspan = tdOld.indexOf("rowspan", stRowspan);
		stColspan = tdOld.indexOf("colspan", stColspan);
		stWidth = tdOld.indexOf("width=", stWidth);
		stHeight = tdOld.indexOf("height=", stHeight);
		stSum = tdOld.indexOf("x:fmla=", stSum);

		if (stWidth > 0) {
			space = tdOld.indexOf(" ", stWidth);
			if (space != -1) {// width 중간에 있을때
				tmp = tdOld.substring(stWidth, space);
				newMakeTD = newMakeTD + tmp + " ";
			} else {// width 끝에 있을때
				space = tdOld.indexOf(">", stWidth);
				if (space != -1) {
					tmp = tdOld.substring(stWidth, space);
					newMakeTD = newMakeTD + tmp + " ";
				} else {
					System.err.println(MoumiConfig.getMessageBundle().getString("moumi.message.tot_doc.falseTable"));
				}
			}
		}

		if (stHeight > 0) {
			space = tdOld.indexOf(" ", stHeight);
			if (space >= 0) {// height 중간에 있을때
				tmp = tdOld.substring(stHeight, space);
				newMakeTD = newMakeTD + tmp + " ";
			} else {// height 끝에 있을때
				space = tdOld.indexOf("", stHeight);
				if (space >= 0) {
					tmp = tdOld.substring(stHeight, space);
					newMakeTD = newMakeTD + tmp + " ";
				} else {
					System.err.println(MoumiConfig.getMessageBundle().getString("moumi.message.tot_doc.falseTable"));
				}
			}
		}

		if (stRowspan > 0) {
			space = tdOld.indexOf(" ", stRowspan);
			if (space >= 0) {// rowspan 중간에 있을때
				tmp = tdOld.substring(stRowspan, space);
				newMakeTD = newMakeTD + tmp + " ";
			} else {// rowspan 끝에 있을때
				space = tdOld.indexOf(">", stRowspan);
				if (space >= 0) {
					tmp = tdOld.substring(stRowspan, space);
					newMakeTD = newMakeTD + tmp + " ";
				} else {
					System.err.println(MoumiConfig.getMessageBundle().getString("moumi.message.tot_doc.falseTable"));
				}
			}
		}

		if (stColspan > 0) {
			space = tdOld.indexOf(" ", stColspan);
			if (space >= 0) {// colspan 중간에 있을때
				tmp = tdOld.substring(stColspan, space);
				newMakeTD = newMakeTD + tmp + " ";
			} else {// colspan 끝에 있을때
				space = tdOld.indexOf(">", stColspan);
				if (space >= 0) {
					tmp = tdOld.substring(stColspan, space);
					newMakeTD = newMakeTD + tmp + " ";
				} else {
					System.err.println(MoumiConfig.getMessageBundle().getString("moumi.message.tot_doc.falseTable"));
				}
			}
		}

		if (stSum > 0) {
			space = tdOld.indexOf(" ", stSum);
			if (space >= 0) {// colspan 중간에 있을때
				tmp = tdOld.substring(stSum, space);
				tmp = insertQu(tmp);
				newMakeTD = newMakeTD + "x:num " + tmp + " ";
			} else {// colspan 끝에 있을때
				space = tdOld.indexOf(">", stSum);
				if (space >= 0) {
					tmp = tdOld.substring(stSum, space);
					tmp = insertQu(tmp);
					newMakeTD = newMakeTD + "x:num " + tmp + " ";
				} else {
					System.err.println(MoumiConfig.getMessageBundle().getString("moumi.message.tot_doc.falseTable"));
				}
			}
		}

		return newMakeTD + ">";
	}

	public static String insertQu(String tmp) {
		StringBuffer tmpbuf = new StringBuffer(tmp);

		tmpbuf.insert(7, "\"");

		return tmpbuf.toString() + "\"";
	}

	// --------------------------------------------------------------------------------------------------------------

	public static String removePre(String form) {
		int hwp2002, hwp97, hwpWordian;

		hwp2002 = form.indexOf("hwp 2002");
		hwp97 = form.indexOf("hwpw 97");
		hwpWordian = form.indexOf("hwp wordian");

		if (hwp2002 > 0 || hwp97 > 0 || hwpWordian > 0) {
			form = form.replaceAll("<pre> <br></pre>", " ");// 한글 97일때 적용.
		}

		return form;
	}

	public static int getSumSusig(String form) {
		return form.indexOf("x:fmla=");
	}

	public static int getComboBox(String form) {
		return form.indexOf("$$");
	}

	public static String nbspConvert(String html) {
		return html.replaceAll("&nbsp;", " ");
	}

	// 엑셀 sum수식 부분에 텍스트 들어 있는것을 공백으로 바뀌어 주기위한 로직
	private static String excelSumSuTextToSpace(String sData) {
		int findSum = 0;
		int findTextTd_st = 0;
		int findTextTd_end = 0;

		StringBuffer tmp = new StringBuffer();

		while (true) {
			findSum = sData.indexOf("x:fmla=");
			if (findSum == -1)
				break;
			findTextTd_st = sData.indexOf(">", findSum);
			if (findTextTd_st == -1)
				break;
			findTextTd_end = sData.indexOf("</td>", findTextTd_st);
			if (findTextTd_end == -1)
				break;

			tmp.append(sData.substring(0, findTextTd_st + 1));
			tmp.append(" ");
			sData = sData.substring(findTextTd_end, sData.length());
		}
		tmp.append(sData);
		return tmp.toString();
	}

	// 엑셀에 있는 콤보 박스의 형식으로 된 텍스트를 변수에 저장함.
	public static String excelComboBoxImport(String sData) {
		int stTD = 0;
		int edTD = 0;
		int index = -1;
		int find$$_st = 0;
		int find$$_ed = 0;
		int tdEnd = 0;
		int span_st = 0;
		int span_ed = 0;
		String tdContext = null;
		String endResult = null;
		StringBuffer str = new StringBuffer();
		String tmp = "";

		while (true) {
			stTD = sData.indexOf("<td", stTD + 1);
			if (stTD == -1)
				break;
			index++;
			edTD = sData.indexOf(">", stTD);
			if (edTD == -1)
				break;
			tdEnd = sData.indexOf("</td", edTD);
			if (tdEnd == -1)
				break;

			tdContext = sData.substring(edTD + 1, tdEnd);

			span_st = tdContext.indexOf("<span");
			if (span_st != -1) {
				span_ed = tdContext.indexOf(">", span_st + 2);
				tmp = tdContext.substring(0, span_st);
				tmp = tmp + tdContext.substring(span_ed + 1, tdContext.length());
				tdContext = tmp;
			}

			find$$_st = tdContext.indexOf("$$");
			if (find$$_st != -1) {

				find$$_ed = tdContext.indexOf("$$", find$$_st + 2);
				endResult = tdContext.substring(find$$_st + 2, find$$_ed);
				endResult = endResult.toUpperCase();
				str.append("itemExprList[");
				str.append(index);
				str.append("] = '");
				str.append(endResult);
				str.append("';  itemDescList[");
				str.append(index);
				str.append("] = 'empty'; ");
			}
		}
		return str.toString();
	}

	public static String tdTextToSpace(String sData) {// 엑셀에 정의된 텍스트를 공백으로 바꿔 줌.
		int stTD = 0;
		int edTD = 0;
		int find$$_st = 0;
		int tdEnd = 0;
		String tdContext = null;
		StringBuffer sInsertedData = new StringBuffer();

		while (true) {
			stTD = sData.indexOf("<td", stTD + 1);
			if (stTD == -1)
				break;
			edTD = sData.indexOf(">", stTD);
			if (edTD == -1)
				break;
			tdEnd = sData.indexOf("</td", edTD);
			if (tdEnd == -1)
				break;
			tdContext = sData.substring(edTD + 1, tdEnd);
			find$$_st = tdContext.indexOf("$$");

			if (find$$_st != -1) {
				sInsertedData.append(sData.substring(0, edTD + 1));
				sInsertedData.append(" ");
				sData = sData.substring(tdEnd, sData.length());
				stTD = 0;
			}
		}
		sInsertedData.append(sData);
		return sInsertedData.toString();
	}

	public static String tagFilter(String s) {
		String temp = s;

		temp = temp.replaceAll("<>", "");
		temp = temp.replaceAll("<t>", "<td>");
		temp = temp.replaceAll("<<td>", "<td>");
		temp = temp.replaceAll("</>", "");
		temp = temp.replaceAll("</t>", "</td>");
		temp = temp.replaceAll("</td>>", "</td>");
		temp = temp.replaceAll("</td>", "</td><td>");
		temp = temp.replaceAll("<td><td", "<td");
		temp = temp.replaceAll("</td><td></tr>", "</td></tr>");
		temp = temp.replaceAll("<tbody>", "");
		temp = temp.replaceAll("</tbody>", "");

		return temp;
	}

	public static String widthConvert(String form) {
		Attributes.setDefaultMaxErrorCount(Integer.MAX_VALUE);
		Source source = new Source(form);
		OutputDocument outputDocument = new OutputDocument(source);
		List<Element> tableElements = source.getAllElements(HTMLElementName.TABLE);

		for (Element tableElement : tableElements) {
			Attributes tableAttributes = tableElement.getAttributes();
			Map<String, String> tableAttributesMap = outputDocument.replace(tableAttributes, false);

			String tableWidthCheck = tableElement.getAttributeValue("width");
			String tableStyleVal = tableElement.getAttributeValue("style");
			if (tableStyleVal != null) {
				tableAttributesMap.put("style", tableStyleVal + "; width:" + tableWidthCheck + "pt");
				tableAttributesMap.put("width", "");
			}
			List<Element> trElements = source.getAllElements(HTMLElementName.TR);

			for (Element trElement : trElements) {
				Attributes trAttributes = trElement.getAttributes();
				Map<String, String> trAttributesMap = outputDocument.replace(trAttributes, false);
				String trWidthCheck = trElement.getAttributeValue("width");
				String trStyleVal = trElement.getAttributeValue("style");
				if (trStyleVal != null) {
					trAttributesMap.put("style", trStyleVal + "; width:" + trWidthCheck + "pt");
					trAttributesMap.put("width", "");
				}
				List<Element> tdElements = source.getAllElements(HTMLElementName.TD);
				for (Element tdElement : tdElements) {
					Attributes tdAttributes = tdElement.getAttributes();
					Map<String, String> tdAttributesMap = outputDocument.replace(tdAttributes, false);

					String tdWidthCheck = tdElement.getAttributeValue("width");
					String styleVal = tdElement.getAttributeValue("style");

					if (styleVal != null) {
						tdAttributesMap.put("style", styleVal + "; width:" + tdWidthCheck
								+ "pt; cursor: hand; height=0");
						tdAttributesMap.put("width", "");
					}
				}
			}
		}
		return CharacterReference.decode(outputDocument.toString());
	}

	public static String deleteTdText(String form, int num) {
		Attributes.setDefaultMaxErrorCount(Integer.MAX_VALUE);
		Source source = new Source(form);
		OutputDocument outputDocument = new OutputDocument(source);
		List<Element> tdElements = source.getAllElements(HTMLElementName.TD);

		int i = 0;
		for (Element tdElement : tdElements) {
			if (i++ == num)
				outputDocument.remove(tdElement.getContent());
		}
		return CharacterReference.decode(outputDocument.toString());
	}

	public static StringBuilder replace(StringBuilder htm, String from, String to) {
		int fromIndex = 0;
		while (true) {
			fromIndex = htm.indexOf(from);
			if (fromIndex != -1)
				htm = htm.replace(fromIndex, fromIndex + from.length(), to);
			else
				break;
		}
		return htm;
	}
        
        /**
         * 문서생성시 사용자가 입력한 표에서 불필요한 요소들을 제거한다.
         * 최초 문서생성시에 이 메서드를 사용하여 테이블표를 정리한다.
         * 
         * @since 2014.10.17 By YoungJun Cho.
         * @param htmlSource
         * @return 
         */
        public static String removeGarbageElements(String htmlSource) {
            
            Source source = new Source(htmlSource);
            source.fullSequentialParse();

            OutputDocument outputDocument = new OutputDocument(source);

            // font 태그를 찾아서 List 에 저장한다.
            List<Element> fontElements = source.getAllElements(HTMLElementName.FONT);
            
            // p 태그를 찾아서 List 에 저장한다.
            List<Element> pElements = source.getAllElements(HTMLElementName.P);
            
            //------------------------------------------------------------------------------------------------
            //  Excel 에서 붙여넣기를 한경우, td 태그내에 font 태그가 자동으로 붙는 현상이 있다.
            //  제거하지 않으면 개행이 발생하여 td 내 하단에 여백이 있는거 처럼 보인다.
            //  font 태그를 찾아서 공백을 제거한 뒤, 값이 없다면 제거한다.
            //  테이블 밖에 있는 텍스트, 테이블 헤더부분 텍스트등은 제거해선 안된다.
            //  td 태그내에 아래와 같은 font 태그가 존재할 경우 제거한다.
            //
            //      Example.
            //          
            //          <FONT size=2 face="맑은 고딕">　</FONT>
            //          <FONT size=2 face="맑은 고딕"><br/></FONT>
            //          <FONT size=2 face="맑은 고딕"> </FONT>
            //------------------------------------------------------------------------------------------------
            for (Element fontElement : fontElements) {
                //System.out.println("====> font 태그 전체 : [" + fontElement.toString() + "]");
                //System.out.println("====> font 태그내 텍스트만 : [" + fontElement.getTextExtractor().toString() + "]");
                
                // font 태그 내의 텍스트를 가져온다.
                String textInTag = fontElement.getTextExtractor().toString().trim();
                
                // tab, space 가 아닌 공백을 치환한다. ('ㄱ' -> 한자키 -> 1번째값과 같다.)
                textInTag = textInTag.replaceAll("　", "");
                
                //System.out.println("====> From font tag. textInTag : [" + textInTag + "]");

                // font 태그 내의 텍스트가 공백일 경우 font 태그를 제거한다.
                if (textInTag.equals("")) {
                    outputDocument.remove(fontElement);
                }
            }
            
            //------------------------------------------------------------------------------------------------
            //  HWP 에서 붙여넣기를 한경우, td 태그내에 p 태그가 자동으로 붙는 현상이 있다.
            //  p 태그내에 <?xml:namespace prefix = "o" ns = "urn:schemas-microsoft-com:office:office" /> 문자열을 발견하면 제거한다.
            //
            //      Example.
            //          
            //          <?xml:namespace prefix = "o" ns = "urn:schemas-microsoft-com:office:office" />
            //          <?xml:namespace prefix = "o" ns = urn:schemas-microsoft-com:office:office />
            //          <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
            //          <?xml:namespace prefix = o ns = urn:schemas-microsoft-com:office:office />
            //------------------------------------------------------------------------------------------------
            for (Element pElement : pElements) {
                //System.out.println("====> p 태그 전체 : [" + pElement.toString() + "]");
                //System.out.println("====> p 태그내 텍스트만 : [" + pElement.getTextExtractor().toString() + "]");
                
                // p 태그 내의 텍스트를 가져온다.
                String textInTag = pElement.getTextExtractor().toString().trim();
                
                // tab, space 가 아닌 공백을 치환한다. ('ㄱ' -> 한자키 -> 1번째값과 같다.)
                textInTag = textInTag.replaceAll("　", "");
                
                //System.out.println("====> From p tag. textInTag : [" + textInTag + "]");
                
                // 태그내에 "<?xml:namespace" 시작하고, "/>" 으로 끝나는 문자열이 있다면 해당 문자열을 제거한다.
                // 이때 p 태그를 제거해선 안된다. "xml:namespace" 포함된 문자열이라 하더라도 p 태그내에 다른 어떠한 값(=데이터상으로 필요한 값)이 존재하는 경우는 제거해선 안된다.
                int startIndex = textInTag.indexOf("<?xml:namespace");
                
                if (startIndex > -1) {
                    // "<?xml:namespace" 으로 시작하는 문자열이 있다면, 문자열 시작위치에서 부터 "/>" 으로 끝나는 문자열의 위치를 확인한다.
                    int endIndex = textInTag.indexOf("/>", startIndex);
                    
                    // "/>" 가 2개의 문자이므로, +2 를 한다.
                    endIndex = endIndex + 2;    
                    
                    // 전체 문자열의 시작부분부터 제거할 문자열 시작부분 전 까지 확인한다.
                    String tmp1 = textInTag.substring(0,startIndex);
                    
                    // 제거할 문자열 끝부분 이후부터 전체 문자열 마지막까지 확인한다.
                    String tmp2 = textInTag.substring(endIndex);
                    
                    // 제거할 문자열을 제외하고 문자열 앞부분과 뒷부분을 합친다.
                    textInTag = tmp1 + tmp2;
                }
                
                // p 태그 내의 텍스트가 공백일 경우 p 태그를 제거한다.
                if (textInTag.equals("")) {
                    outputDocument.remove(pElement);
                }
            }
            
            return outputDocument.toString();
        }
}
