/*

  JForm   : 검증할 모든 객체를 담는데 사용.
  JText   : 텍스트 데이터를 검증하는데 사용.
  JNumber : 숫자 데이터를 검증하는데 사용.
  JMoney  : 화폐 데이터를 검증하는데 사용.
  JSelect : Drop/Down 데이터를 검증하는데 사용.
  JCheck  : 체크박스와 라디오 버튼을 검증하는데 사용.
  JSsn    : 주민등록번호를 검증하는데 사용.
  JMail   : 이메일 주소를 검증하는데 사용.
  JDate   : 날짜 데이터를 검증하는데 사용.
  JFile   : 파일 업로드 데이터를 검증하는데 사용.

*/

var DAY_OF_WEEK = new Array("일","월","화","수","목","금","토");

function JForm() {

    /* Member field */
    this.children = new Array

    /* Member Method */
    this.add = jform_add;
    this.validate = jform_validate;

    return this;
}

function jform_add(child) {
    this.children[this.children.length] = child;
    return this;
}

function jform_validate() {
    for (var i = 0; i < this.children.length; i++) {
        if (!this.children[i].validate()) {
            return false;
        }
    }
    return true;
}

function JText(name, object) {

    /* Member Field */
    this.name = name;
    this.object = object;

    this.min;
    this.max;
    
    this.filterCheck;
    this.nullCheck = true;
    this.rangeCheck;

    /* Member Method */
    this.validate = jtext_validate;
    this.nullable = jtext_nullable;
    this.range = jtext_range;
    this.filter = jtext_filter;
    this.focus = jtext_focus;

    return this;
}

function jtext_validate() {

    var value = this.object.value;

    if (this.nullCheck && trimmed(value).length == 0) {
        alert(messages.get("JSM-1004", ul(this.name)));
        return this.focus();
    }
    
    if (this.rangeCheck && (trimmed(value).length != 0) && !checkCharacterSize(value, this.min, this.max)) {
        if (this.min == this.max) {
            messages.alert("JSM-1005", [this.name, this.min]);
        } else {
            messages.alert("JSM-1006", [this.name, this.min, this.max]);
        }
        return this.focus();
    }

    if (this.filterCheck && isSpecial(value)) {
        messages.alert("JSM-1007", [this.name]);
        return this.focus();
    }
    return true;
}

function jtext_nullable() {
    this.nullCheck = false;
    return this;
}

function jtext_range(min, max) {
    this.rangeCheck = true;
    this.min = min;
    this.max = max;
    return this;
}

function jtext_filter() {
    this.filterCheck = true;
    return this;
}

function jtext_focus() {
    this.object.focus();
    this.object.select();
    return false;
}

function JNumber(name, object) {

    /* Member Field */
    this.name = name;
    this.object = object;
    this.nullCheck = true;
    this.rangeCheck;
    
    this.min;
    this.max;

    /* Member Method */
    this.validate = jnumber_validate;
    this.nullable = jtext_nullable;
    this.range = jtext_range;
    this.focus = jtext_focus;
    
    return this;
}

function jnumber_validate() {

    var value = this.object.value;

    if (this.nullCheck && trimmed(value).length == 0) {
        messages.alert("JSM-1004", ul(this.name));
        return this.focus();
    }

    if (isNaN(value)) {
        messages.alert("JSM-1008", this.name);
        return this.focus();
    }
    
    if (this.rangeCheck && (trimmed(value).length != 0) && !checkNumberSize(value, this.min, this.max)) {
        if (this.min == this.max) {
            messages.alert("JSM-1009", [this.name, this.min]);
        } else {
            messages.alert("JSM-1010", [this.name, wa(this.min), this.max]);
        }
        return this.focus();
    }
    return true;
}

function JSelect(name, object) {

    /* Member Field */
    this.name = name;
    this.object = object;

    this.min;
    this.max;

    this.nullCheck = true;
    this.rangeCheck;
    
    /* Member Method */
    this.validate = jselect_validate;
    this.nullable = jtext_nullable;
    this.range = jtext_range;
    this.focus = jselect_focus;

    return this;
}

function jselect_validate() {

    var value = this.object.value;

    if (this.nullCheck && trimmed(value).length == 0) {
        messages.alert("JSM-1011", ul(this.name));
        return this.focus();
    }

    var number = isSelected(this.object);

    if (this.rangeCheck && number != 0 && (number < this.min || number > this.max)) {
        if (this.min == this.max) {
            messages.alert("JSM-1012", [this.name, this.min]);
        } else {
            messages.alert("JSM-1013", [this.name, wa(this.min), this.max]);
        }
        return this.focus();
    }

    return true;
}

function jselect_focus() {
    this.object.focus();
    return false;
}

function isSelected(item) {
    if (item == null) return 0;
    var result = 0;

    for (var i = 0; i < item.length; i++) {
        if (item[i].selected) {
            result++;
        }
    }
    return result;
}

function JCheck(name, object) {

    /* Member Field */
    this.name = name;
    this.object = object;
    
    this.min;
    this.max;

    this.nullCheck = true;
    this.rangeCheck;

    /* Member Method */
    this.validate = jcheck_validate;
    this.nullable = jtext_nullable;
    this.range = jtext_range;
    this.focus = jcheck_focus;

    return this;
}

function jcheck_validate() {

    var number = isChecked(this.object);
    if (this.nullCheck && number == 0) {
        messages.alert("JSM-1011", ul(this.name));
        return this.focus();
    }

    if (this.rangeCheck && number != 0 && (number < this.min || number > this.max)) {
        if (this.min == this.max) {
            messages.alert("JSM-1012", [this.name, this.min]);
        } else {
            messages.alert("JSM-1013", [this.name, wa(this.min), this.max]);
        }
        return this.focus();
    }
    return true;
}

function jcheck_focus() {
    return false;
}

function isSpecial(s) {
    for (i = 0; i < s.length; i++) {   
        /* Check that current character letter. */
        var c = s.charAt(i);
        if (c == "'" || c == "." || c == "\"") {
            return true;
        }
    }
    return false;
}

function isChecked(list) {
    if (list == null) return 0;
    var result = 0;

    /* list array의 데이터가 1인 경우 */
    if (list.checked) {
        return 1;
    }
    for (var i = 0; i < list.length; i++) {
        if (list[i].checked) {
            result++;
        }
    }
    return result;
}

function trimmed(value) {
    value = value.replace(/^\s+/, "");  /* remove leading white spaces */
    value = value.replace(/\s+$/g, ""); /* remove trailing while spaces */
    return value;
}

function checkCharacterSize(data, min, max) {
    var total = 0;

    for (var i = 0; i < data.length; i++) {
        var a = data.charAt(i);
        /* 한글인 경우 길이가 6 이다. */
        if (escape(a).length >= 6) {
            total = total + 2;
        } else {
            total = total + 1;
        }
    }
    return total >= min && total <= max;
}

function checkNumberSize(data, min, max) {
    if(max <= 0) {
        return data >= min;
    } else {
        return data >= min && data <= max;
    }
}

function JMoney(name, object) {

    /* Member Field */
    this.name = name;
    this.object = object;
    this.nullCheck = true;
    this.rangeCheck;
    
    this.min;
    this.max;

    /* Member Method */
    this.validate = jmoney_validate;
    this.nullable = jtext_nullable;
    this.range = jtext_range;
    this.focus = jtext_focus;

    return this;
}

function jmoney_validate() {

    var value = this.object.value;

    if (this.nullCheck && trimmed(value).length == 0) {
        messages.alert("JSM-1004", ul(this.name));
        return this.focus();
    }

    value = value.replace(/,|\s+/g, "");

    if (isNaN(value)) {
        messages.alert("JSM-1008", this.name);
        return this.focus();
    }

    if (this.rangeCheck && (trimmed(value).length != 0) && !checkNumberSize(value, this.min, this.max)) {
        if (this.min == this.max) {
            messages.alert("JSM-1014", [this.name, this.min]);
        } else {
            messages.alert("JSM-1015", [this.name, wa(this.min), this.min]);
        }
        return this.focus();
    }
    return true;
}

function JSsn(name, object) {

    /* Member Field */
    this.name = name;
    this.object = object;
    this.nullCheck = true;

    /* Member Method */
    this.validate = jssn_validate;
    this.nullable = jtext_nullable;
    this.focus = jtext_focus;

    return this;
}

function jssn_validate() {

    var value = this.object.value;

    if (isNaN(value.replace(/-|\s+/g, ""))) {
        messages.alert("JSM-1008", this.name);
        return this.focus();
    }
    
    if (!this.nullCheck && trimmed(value).length == 0) {
        return true;
    }
    
    var year = value.substring(0, 2);
    var month = value.substring(2, 4);
    var day = value.substring(4, 6);
    var sex = value.substring(7, 8);
    
    if ((value.length != 14) || (year < 25 || month < 1 || month >12 || day < 1)) {
        messages.alert("JSM-1016", ul(this.name));
        return this.focus();
    }

    if ((sex != 1 && sex !=2 )) {
        messages.alert("JSM-1016", ul(this.name));
        return this.focus();
    }

    return true;
}

function ssn_validate(name, ssn) {

    var value = ssn;

    if (isNaN(value.replace(/-|\s+/g, ""))) {
        messages.alert("JSM-1008", name);
        return this.focus();
    }
    
    if (!this.nullCheck && trimmed(value).length == 0) {
        return true;
    }
    
    var year = value.substring(0, 2);
    var month = value.substring(2, 4);
    var day = value.substring(4, 6);
    var sex = value.substring(7, 8);
    
    if ((value.length != 14) || (year < 25 || month < 1 || month >12 || day < 1)) {
        messages.alert("JSM-1016", ul(name));
        return false;// this.focus();
    }

    if ((sex != 1 && sex !=2 )) {
        messages.alert("JSM-1016", ul(name));
        return false;// this.focus();
    }

    return true;
}

function JMail(name, object) {

    /* Member Field */
    this.name = name;
    this.object = object;

    this.nullCheck = true;

    /* Member Method */
    this.validate = jmail_validate;
    this.nullable = jtext_nullable;
    this.focus = jtext_focus;

    return this;
}

function jmail_validate() {

    var value = this.object.value;

    if (this.nullCheck && trimmed(value).length == 0) {
        messages.alert("JSM-1004", ul(this.name));
        return this.focus();
    }
    
    if (!this.nullCheck && trimmed(value).length == 0) {
        return true;
    }

    /* 이메일 주소의 허용되는 최대 크기 체크 */
    
    var re = new RegExp("(^[_0-9a-zA-Z-]+(\.[_0-9a-zA-Z-]+)*@[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*$)");
    if (!re.test(value)) {
        messages.alert("JSM-1017", un(this.name));
        return this.focus();
    }
    return true;
}

/**
 *    Date 타입 검증에 사용된다.
 */
function JDate(name, object, re) {

    /* Member Field */
    this.name = name;
    this.object = object;
     
    this.nullCheck = true;
    this.rangeCheck = false;
    
    this.date = null;
    
    if (re)  {
    	this.re = re;
    } else {
		this.re = /^\d{4}[-.\/]?\d{2}[-.\/]?\d{2}$/;
    }
    
    this.min = null; /* YYYYMMDD Format */
    this.max = null; /* YYYYMMDD Format */
    
    this.format = "YYYY년MM월DD일(DAY)";

    /* Member Method */
    this.validate = jdate_validate;
    this.nullable = jtext_nullable;
    this.focus = jtext_focus;
    this.range = jtext_range;
    
    this.toDate = jdate_toDate;
    this.parse = jdate_parse;
    this.toString = jdate_toString;
    
    this.getYear  = jdate_getYear;
    this.getMonth = jdate_getMonth;
    this.getDate  = jdate_getDate;    
    this.getDay = jdate_getDay;

    this.parse();
    
    return this;
}

/* 데이터 타입 유효성 테스트  */
function jdate_validate() {

    var value = this.object.value;

    if (this.nullCheck && trimmed(value).length == 0) {
        messages.alert("JSM-1004", ul(this.name));
        return this.focus();
    }
    
    if (!this.nullCheck && trimmed(value).length == 0) {
        return true;
    }
  
    if (this.date == null) {
        messages.alert("JSM-1018", wa(this.name));
        return this.focus();    
    } 
    
    if (this.rangeCheck) {
        var aDate = this.toDate();
        var minDate, maxDate;
        
        if (this.min != null) {
            minDate = new JDate().parse(this.min);
        } else {
            minDate = new JDate().parse("10000101");
        }
        if (this.max != null) {
            maxDate = new JDate().parse(this.max);
        } else {
            maxDate = new JDate().parse("99991231");
        }
        if (this.min == null && aDate > maxDate.toDate()) {
            messages.alert("JSM-1019", [this.name, maxDate]);
            return this.focus();
            
        } else if (this.max == null && aDate < minDate.toDate()) {
            messages.alert("JSM-1020", [this.name, minDate]);
            return this.focus();
        } else if (aDate > maxDate.toDate() || aDate < minDate.toDate()) {
            messages.alert("JSM-1021", [this.name, minDate, maxDate]);
            return this.focus();
        }
    }
    
    return true;
}

/* Date 파싱  */
/* 날짜 데이터 인지 검증한다. 일차적으로는 정규식을 이용한다. */
/* 년,월,일 사이의 Delimiter는 ".-/" 중 하나이거나 빈문자을 사용한다. */
/* Date Object를 초기화하여 데이터가 적합한지 체크한다. */
function jdate_parse() {
    var value = this.object;
    if (jdate_parse.arguments.length > 0) {
        value = jdate_parse.arguments[0];
    } else if (this.object && typeof this.object=="object") {
        value = this.object.value;
    } else {
        this.date = new Date();
        return this;
    }
    
    this.date = null;
    if (value.search(this.re) >= 0) {
        value = value.replace(/[-.\/]/g,"");
        var aDate = new Date(value.substring(0,4),value.substring(4,6)-1,value.substring(6,8));
        if (   aDate.getFullYear()  == Math.abs(value.substring(0,4))
            && aDate.getMonth() == Math.abs(value.substring(4,6))-1 
            && aDate.getDate()  == Math.abs(value.substring(6,8)) ) {
            this.date = aDate;
        }
    }
    return this;
}

/* Date 타입으로 변환 */
function jdate_toDate() {
    return this.date;
}

function jdate_getYear() {
    return this.date == null ? 1000 : this.date.getFullYear();
}

function jdate_getMonth() {
    var num = (this.date == null ? 0 : this.date.getMonth()+1);
    return (num < 10 ? '0' + new String(num) : num);
}

function jdate_getDate() {
    var num = (this.date == null ? 0 : this.date.getDate());
    return (num < 10 ? '0' + new String(num) : num);
}

function jdate_getDay() {
    return (this.date == null ? DAY_OF_WEEK[0] : DAY_OF_WEEK[this.date.getDay()]);
}


/* 스트링으로 변환  */
function jdate_toString() {
    var formatString = this.format;
    if (jdate_toString.arguments.length > 0) {
        formatString = jdate_toString.arguments[0];
    }
    var str = formatString.replace(/YYYY/g , this.getYear());
    str = str.replace(/MM/g , this.getMonth());
    str = str.replace(/DD/g , this.getDate());
    str = str.replace(/DAY/g , this.getDay());
    str = str.replace(/yy/g , new String(this.getYear()).substring(2,4));
    return str;
}


/* 파일업로딩시 입력파일에 대한 검증을 실시한다.  */
function JFile(name, type) {
    /* Member Field */
    this.name = name;
    this.object = document.forms[0].j_file;
    this.type = type;

    this.nullCheck = true;
    this.allowedExtension;
    this.disallowedExtension;

    this.nullable = jtext_nullable;
    this.extension = jfile_extension;
    this.xExtension = jfile_xExtension;
    this.validate = jfile_validate;

    return this;
}

/*확장명 체크*/
function jfile_extension(array) {
    this.allowedExtension = array;
    return this;
}

/*입력금지된 확장명 체크*/
function jfile_xExtension(array) {
    this.disallowedExtension = array;
    return this;
}

function jfile_validate() {

	/*만땅 채운 upload를 수정할때 object는 없다. */
	if (!this.object) {
		return true;
	}

	/*IE 버그로 인한 입력값 정확성 체크 */
	var re = /^[a-z]:\\(.){0,300}$/i;
	if (!this.object.length) {
		var temp = this.object;
		this.object = new Array();
		this.object[0] = temp;
	}
	for (var i = 0; i < this.object.length; i++) {
        if (this.type) {            
            var extension = this.object[i].value;
            if (extension != "" && !extension.match(re)) {
            	messages.alert("JSM-1022");
            	this.object[i].focus();
        		return false;
            }
        }
    }
    
    if (this.nullCheck) {
        var countInputName = "j_file_count";
        if (this.type) {
            countInputName += "_" + this.type;
        }
        var countInput = document.forms[0][countInputName];
        if (!countInput || countInput.value < 1) {
            messages.alert("JSM-1023", this.name);
            return false;
        }
    }
    if (this.allowedExtension) {
        var passed = true;
        for (var i = 0; i < this.object.length; i++) {
            if (this.type) {
                var spanNode = this.object[i].nextSibling;
                if (!spanNode || spanNode.getElementsByTagName("input")[0].value != this.type) {
                    continue;
                }
            }
            var extension = this.object[i].value;
            if (trimmed(extension).length == 0) {
                continue;
            }
            var index = extension.lastIndexOf(".");
            if (index == -1) {
                passed = false;
                break;
            }
            extension = extension.substring(index + 1).toLowerCase();
            for(var j = 0; j < this.allowedExtension.length ; j++) {
                if (this.allowedExtension[j].toLowerCase() == extension) {
                    break;
                }
                if (j == this.allowedExtension.length - 1) {
                    passed = false;
                }
            }
        }
        if (!passed) {
            messages.alert("JSM-1024", [this.name, this.allowedExtension.join(", ")]);
            return false;
        }
    }
    if (this.disallowedExtension) {
        var passed = true;
        for (var i = 0; i < this.object.length; i++) {
            if (this.type) {
                var spanNode = this.object[i].nextSibling;
                if (!spanNode || spanNode.getElementsByTagName("input")[0].value != this.type) {
                    continue;
                }
            }
            var extension = this.object[i].value;
            if (trimmed(extension).length == 0) {
                continue;
            }
            var index = extension.lastIndexOf(".");
            if (index == -1) {
                break;
            }
            extension = extension.substring(index + 1).toLowerCase();
            for(var j = 0; j < this.disallowedExtension.length ; j++) {
                if (this.disallowedExtension[j].toLowerCase() == extension) {
                	passed = false;
                    break;
                }
                if (j == this.disallowedExtension.length - 1) {
                    passed = true;
                }
            }
        }
        if (!passed) {
            messages.alert("JSM-1025", [this.name, this.disallowedExtension.join(", ")]);
            return false;
        }
    }    
    return true;
}


/**
 *    Crontab Expression 타입 검증에 사용된다.
 */
function JCronExpression(name, object) {

    /* Member Field */
    this.name = name;
    this.object = object;
     
    this.nullCheck = true;
    
	this.re = new RegExp("^(((([0-9]|[0-5][0-9]),)*([0-9]|[0-5][0-9]))|(([0-9]|[0-5][0-9])(/|-)([0-9]|[0-5][0-9]))|([\\?])|([\\*]))[\\s](((([0-9]|[0-5][0-9]),)*([0-9]|[0-5][0-9]))|(([0-9]|[0-5][0-9])(/|-)([0-9]|[0-5][0-9]))|([\\?])|([\\*]))[\\s](((([0-9]|[0-1][0-9]|[2][0-3]),)*([0-9]|[0-1][0-9]|[2][0-3]))|(([0-9]|[0-1][0-9]|[2][0-3])(/|-)([0-9]|[0-1][0-9]|[2][0-3]))|([\\?])|([\\*]))[\\s](((([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]),)*([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?)|(([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(/|-)([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?)|(L)|([\\?])|([\\*]))[\\s](((([1-9]|0[1-9]|1[0-2]),)*([1-9]|0[1-9]|1[0-2]))|(([1-9]|0[1-9]|1[0-2])(/|-)([1-9]|0[1-9]|1[0-2]))|(((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC),)*(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))|((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-|/)(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))|([\\?])|([\\*]))[\\s]((([1-7],)*([1-7]))|([1-7](/|-)([1-7]))|(((MON|TUE|WED|THU|FRI|SAT|SUN),)*(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?)|((MON|TUE|WED|THU|FRI|SAT|SUN)(-|/)(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?)|(([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))?(L)?)|([1-7]#([1-7])?)|([\\?])|([\\*]))([\\s]19[7-9][0-9]|20[0-9]{2})?$");       
    
    /* Member Method */
    this.validate = jcron_validate;
    this.nullable = jtext_nullable;
    this.focus = jtext_focus;
    
    return this;
}

function jcron_validate() {

    var value = this.object.value;

    if (this.nullCheck && trimmed(value).length == 0) {
        messages.alert("JSM-1004", this.name);
        return this.focus();
    }
    
    if (!this.nullCheck && trimmed(value).length == 0) {
        return true;
    }
        
    if (!this.re.test(value)) {
    	messages.alert("JSM-1026", wa(this.name));
    	return this.focus();
    }
    
    return true;
}

/**
 *  Textarea에 NewLine으로 구분된 Properties 타입 검증에 사용된다.
 */
function JProperties(name, object, requiredProps) {

    /* Member Field */
    this.name = name;
    this.object = object;
     
    this.nullCheck = true;
    
    /* 콤마(,)로 구분된 필수필드명*/
    this.requiredProps = requiredProps;
   	this.re = new RegExp("^[_0-9a-zA-Z-\.]+=");
    
    /* Member Method */
    this.validate = jproperties_validate;
    this.nullable = jtext_nullable;
    this.focus = jtext_focus;
    
    return this;
}

function jproperties_validate() {

    var value = this.object.value;
    var props = new Array();

    if (this.nullCheck && trimmed(value).length == 0) {
        messages.alert("JSM-1004", this.name);
        return this.focus();
    }
    
    if (!this.requiredProps && !this.nullCheck && trimmed(value).length == 0) {
        return true;
    }
    
    var lines = trimmed(value).split("\n");
    for(var i=0; i < lines.length ; i++) {
    	if (!this.re.test(lines[i])) {
    		messages.alert("JSM-1027", [this.name, un(lines[i])]);
    		return this.focus();
    	} else {
    		var idx = lines[i].indexOf("=");
    		props[lines[i].substring(0,idx)] = lines[i].substring(idx+1,lines[i].length);
    	}
    }
    
    if(this.requiredProps) {
    	var rProps = this.requiredProps.split(",");
    	for(var i=0; i<rProps.length ; i++) {
    		if(!props[rProps[i]]) {
        		messages.alert("JSM-1028", [this.name, ka(rProps[i])]);
    			return this.focus();
    		}
    	}
    }
    
    return true;
}

/* 내부함수 (한글 종성체크) */
function isJongsong(wd) {

    var INDETERMINATE = 0;
    var NOJONGSONG = 1;
    var JONGSONG = 2;

    word = new String(wd);                    /* 숫자가 들어오는 등에 대비해 무조건 문자열로 바꿈 */
    numStr1 = "013678lmnLMN";                 /* '조' 전까지는 0이 받침이 있는걸로 나옴 --; */
    numStr2 = "2459aefhijkoqrsuvwxyzAEFHIJKOQRSUVWXYZ";
    /* bdgpt들은 읽기에 따라 받침이 있기도 하고 없기도 한다고 판단. */
    /* 대문자는 단독으로 읽을 때를 감안하면 받침 있다고 확정되는 것이 더 적음. */
    
    if (word == null || word.length < 1) {
        return INDETERMINATE;
    }
    
    lastChar = word.charAt(word.length - 1);
    lastCharCode = word.charCodeAt(word.length - 1);
    
    if (numStr1.indexOf(lastChar) > -1) {
        return JONGSONG;
    }else if (numStr2.indexOf(lastChar) > -1) {
        return NOJONGSONG;
    }
    
    if (lastCharCode<0xac00 || lastCharCode>0xda0c) {
        return INDETERMINATE;
    }
    else{
        lastjongseong = (lastCharCode - 0xAC00) % (21*28) % 28  ;
        
        if (lastjongseong == 0){
            return NOJONGSONG;
        }else{
            return JONGSONG;
        }
    }
}

/* 내부함수 (을/를) */
function ul(s) {
    var ul0 = new Array("(을)를", "를", "을");
    return s + ul0[isJongsong(s)];
}

/* 내부함수 (이/가) */
function ka(s){
    var ka0 = new Array("(이)가", "가", "이");
    return s + ka0[isJongsong(s)];
}

/* 내부함수 (은/는) */
function un(s){
    var un0 = new Array("(은)는", "는", "은");
    return s + un0[isJongsong(s)];
}

/* 내부함수 (와/과) */
function wa(s){
    var arr = new Array("(와)과", "와", "과");
    return s + arr[isJongsong(s)];
}

