/**
 * 
 */
package kr.ac.kaist.swrc.jhannanum.module.usn;

import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;

import kr.ac.kaist.swrc.jhannanum.module.Module;
import kr.ac.kaist.swrc.jhannanum.share.Code;

/**
 * @author Sangwon Park (hudoni@world.kaist.ac.kr), CILab, SWRC, Kaist
 *
 */
public class USNProcessor implements Module {
	final static private String MODULE_NAME = "USNProcessor";
	
	private String HA = null;
	private String AR = null;
	private String A_ = null;
	private String PV = null;
	private String XEU = null;
	private String DOB = null;
	private String GOB = null;
	private String EU = null;
	private String SU = null;
	private String NU = null;

	private String word = null;
	private String data = null;

	private String line = null;
	private String[] processing = new String[1000];
	private int p_end = 0;

	private String tmpword = null;
	private String tmptag = null;
	private String tmpstr = null;
	private String prevword = null;
	private String tmpmorph = null;
	private String buff = null;

	private BufferedReader in = null;
	private PrintWriter out = null;

	private void action() {
		int i;

		if (p_end==0)
			return;

		out.write(processing[0] + '\n');
		for (i = 1; i < p_end; i++) {
			out.write(String.format("\t%s\n", processing[i]));
		}

		out.write('\n');
		p_end=0;

		out.flush();
	}

	private int front_morph(String str) {
		int i = 0;

		tmpmorph = "";

		if (str == null) {
			return -1;
		}
		else if (str.length() == 0) {
			return -1;
		}

		while (i < str.length() && str.charAt(i) != '+') {
			if (str.charAt(i) == '\\') {
				tmpmorph += str.charAt(i++);
			}
			tmpmorph += str.charAt(i++);
		}

		if (i < str.length()) {
			i++;
		}
		return i;
	}

	private int front_wt(String str) {
		int i = 0;

		tmpword = "";

		if (str == null) {
			return -1;
		}
		else if (str.length() == 0) {
			return -1;
		}

		while (i < str.length() && str.charAt(i) != '/') {
			if (str.charAt(i) == '\\') {
				tmpword += str.charAt(i++);
			}
			tmpword += str.charAt(i++);
		}

		if (i < str.length()) {
			i++;
		}
		return i;
	}

	public String getName() {
		return MODULE_NAME;
	}

	public void initialize(Reader in, Writer out, String configFile) throws Exception {
		if (in != null) {
			this.in = new BufferedReader(in);
		} else {
			this.in = null;
		}

		if (out != null) {
			this.out = new PrintWriter(out);
		} else {
			this.out = null;
		}
	}
	
	private boolean is_pvowel(char c) {
		int i;

		for (i=0; i < PV.length(); i++) {
			if (PV.charAt(i) == c) {
				return true;
			}
		}
		return false;
	}

	private boolean is_xeu(char c) {
		int i;
		for (i = 0; i < XEU.length(); i++)
			if (XEU.charAt(i) == c)
				return true;
		return false;
	}

	private void morph_in(String str) throws Exception {
		int p, q;
		int i = 0;

		if (str.length() != 0 && str.charAt(0) == '\t')
			str = str.substring(1);

		tmpstr = "";
		prevword = "";

		// 형태소 분석 결과 1개의 모든 구셩 형태소에 대하여
		p = front_morph(str);
		while (p != -1) {
			q = front_wt(tmpmorph);

			if (q != -1 && q < tmpmorph.length()) {
				tmptag = tmpmorph.substring(q);
			} else {
				tmptag = "";
			}

			// 여기는 으,스,느 탈락 시키는 곳
			if(tmptag.length() != 0 && tmptag.charAt(0) == 'e') {
				int len = prevword.length();
				buff = Code.toTripleString(tmpword);

				if (strncmp(buff,A_,2)==0)		/* 어 -> 아*/
				{
					if(len-1<prevword.length() && len>=4 && prevword.charAt(len-1) == EU.charAt(1)	&&							// 어간 으
							!is_xeu(prevword.charAt(len-2))  &&
							((Code.isJungseong(prevword.charAt(len-3)) 
									&& is_pvowel(prevword.charAt(len-3))) ||
									(Code.isJongseong(prevword.charAt(len-3)) 
											&& is_pvowel(prevword.charAt(len-4))))) {
						buff = AR.substring(0, 2);
						tmpword = Code.toString(buff.toCharArray());
					} else if(len-1<prevword.length() && len>=3 && prevword.charAt(len-1)==DOB.charAt(2) &&
							(prevword.substring(len-3).equals(DOB) == false ||
									prevword.substring(len-3).equals(GOB) == false))
						; // ㅂ불규칙 음모듬을 위해
					else if(len-2<prevword.length() && len>=2 && prevword.substring(len-2).equals(HA))
						;
					else if(len-1<prevword.length() && len>=2 && ( (Code.isJungseong(prevword.charAt(len-1)) // 무종성
							&& is_pvowel(prevword.charAt(len-1))) ||
							(Code.isJongseong(prevword.charAt(len-1)) 			// 종성
									&& is_pvowel(prevword.charAt(len-2))) )) 
					{
						buff = AR.substring(0, 2);
						tmpword = Code.toString(buff.toCharArray());
					}
				}
				else if(buff.startsWith(EU.substring(0, 2)) || 	/* 으스느 탈락 */
						buff.startsWith(SU.substring(0, 4)) ||
						buff.startsWith(NU.substring(0, 4)))
				{
					if(len-1 < prevword.length() && len>=2 && (Code.isJungseong(prevword.charAt(len-1)) ||
							prevword.charAt(len-1) == 0x11AF))
						tmpword = Code.toString(buff.substring(2).toCharArray());
				}
				// if(tmpmorph.startsWith("어")))
			}
			tmpstr = tmpstr + tmpword + "/" + tmptag + "+";
			i = tmpstr.length();
			prevword = Code.toTripleString(tmpword);

			if (p < str.length()) {
				p += front_morph(str.substring(p));
			} else {
				p = -1;
			}
		}

		tmpstr = tmpstr.substring(0, tmpstr.length() - 1);

		for (i = 1; i < p_end; i++) {
			if (processing[i].equals(tmpstr)) {
				break;
			}
		}
		if (i >= p_end) {
			if (p_end == 1000) {
				throw new Exception("USNProcessor: out of index problem");
			}
			processing[p_end] = tmpstr;
			p_end++;
		}
	}


	public void run() throws Exception {
		p_end = 0;

		HA = Code.toTripleString("하");
		AR = Code.toTripleString("아");
		A_ = Code.toTripleString("어");
		PV = Code.toTripleString("ㅏㅑㅗ");
		XEU = Code.toTripleString("끄뜨쓰크트");
		DOB = Code.toTripleString("돕");
		GOB = Code.toTripleString("곱");
		EU = Code.toTripleString("으");
		SU = Code.toTripleString("습니");
		NU = Code.toTripleString("는다");

		String line = null;
		while ((line = in.readLine()) != null) {
			try {
			if (line.length() == 0) {
				action();
			} else if(line.charAt(0) == '\t') {
				morph_in(line);
			} else {
				word_in(line);
			}
			} catch (Exception e) {
				System.err.println("USNProcessor: Passed Sentence: " + line.replaceAll("EOS|BOS", ""));
			}
		}
		action();
	}

	public void setReader(Reader in) {
		if (in != null) {
			this.in = new BufferedReader(in);
		} else {
			this.in = null;
		}
	}

	public void setWriter(Writer out) {
		if (out != null) {
			this.out = new PrintWriter(out);
		} else {
			this.out = null;
		}
	}

	public void shutdown() {

	}

	private int strncmp(String s1, String s2, int len) {
		if (s1.length() < len) {
			return 1;
		} else if (s2.length() < len) {
			return -1;
		}
		int i1 = 0;
		int i2 = 0;

		while (len-- > 0) {
			if (s1.charAt(i1++) != s2.charAt(i2++)) {
				break;
			}
		}
		return s1.charAt(i1-1) - s2.charAt(i2-1);
	}

	private void word_in(String str) {
		if (p_end != 0) {
			action();
		}

		processing[0] = str;
		p_end=1;
	}
}
