/*-------------------------------------------------------------------+
 * 1. 파일명: valid.date.js
 * 2. 설  명: 일자, 시간에 대한 유효성 점검 함수를 정의한다.
 * 3. 의존성: string.js, date.js
 * 4. 작성일: 2006.10.11.
 -------------------------------------------------------------------*/


/**
 * 주어진 문자열 값이 유효한 날짜 형식인지를 확인하여
 * 유효하면 true를 돌려주고, 유효하지 않으면 적절한 오류 메시지를
 * 보여준 다음 false를 돌려준다.
 */
function checkYearMonth(dateStr) {
	// 아무값도 없으면 진행하지 않는다.
	if ( trim(dateStr) == "" ) return true;

	dateStr = removeChar(dateStr, DATE_DELIMETER);

	// 슬래쉬를 제거한 나머지 자릿수가 8자인지 검사한다.
	if (dateStr.length != 6) {
		alert("YYYYMM의 형식으로 입력해 주십시오.");
		return false;
	}

	// 숫자로만 구성되었는지 확인한다.
	if ( isNaN(dateStr) ) {
		alert("날짜에는 문자가 입력될 수 없습니다.");
		return false;
	}

	// 연도 4자리, 월 2자리로 자른다.
	var yearStr  = dateStr.substring(0, 4);
	var monthStr = dateStr.substring(4);


	// 연도 값이 1 ~ 9999 사이인지 점검한다.
	if ( yearStr < 1 || yearStr > 9999 ) {
		alert("연도는 1년 ~ 9999년 사이의 값을 입력해야 합니다.");
		return false;
	}

	// 월이 1~12월 사이인지 점검한다.
	if ( monthStr < 1 || monthStr > 12 ) {
		alert("월은 01월에서 12월 사이의 값입니다.");
		return false;
	}

	return true;
}


/**
 * Text형 입력폼의 문자열 값이 유효한 날짜 형식인지를 확인하여
 * 유효하면 연월 값 사이에 슬래쉬(/)를 넣은 문자열로 바꾼 후 true를 돌려주고,
 * 유효하지 않으면 적절한 오류 메시지를 보여준 다음 false를 돌려준다.
 */
function checkYearMonthObj(obj) {
	var dateStr = removeChar(obj.value, DATE_DELIMETER);

	var valid = true;

	// 빈 문자열이면 점검하지 않는다.
	if ( trim(dateStr) != "" ) {
		valid = checkYearMonth(dateStr);
		if ( valid ) {
			var yearStr  = dateStr.substring(0, 4);
			var monthStr = dateStr.substring(4);

			obj.value = yearStr + DATE_DELIMETER + monthStr;
		}
		else {
			obj.focus();
		}
	}

	return valid;
}


/**
 * Text형 입력폼 에 입력된 날짜가 유효한지 체크하여
 * 유효하면 YYYY/MM/DD의 형태로 변환하여 return
 * 하고, 유효하지 않으면 에러메세지 보여줌
 * (년월일 입력필드의 onblur event에 사용할것)
 *
 * @param obj Text형 입력폼 객체
 */
function checkDateObj(obj) {
	return checkDate(obj.value);
}


/**
 * 주어진 문자열값이 유효한 날짜값인지 점검하여
 * 유효하면 true를 돌려주고, 유효하지 않으면
 * 에러메세지를 보여주고 false를 돌려준다.
 * (년월일 입력필드의 onblur event에 사용할것)
 *
 * @param dateStr 날짜형값을 가지는 문자열
 */
function checkDate(dateStr, fieldName) {
	// 아무값도 없으면 진행하지 않는다.
	if ( trim(dateStr) == "" ) return true;

	/* 항목명이 없으면 "일자"을 사용. */
	if ( isEmpty(fieldName) ) fieldName = "일자";

	dateStr = removeChar(dateStr, DATE_DELIMETER);

	// 숫자로만 구성되었는지 확인한다.
	if ( isNaN(dateStr) ) {
		alert(fieldName + "의 값에는 문자가 입력될 수 없습니다.");
		return false;
	}

	// 구별자를 제거한 나머지 자릿수가 8자인지 검사한다.
	if (dateStr.length != 8) {
		alert(fieldName + "의 값을 YYYYMMDD의 형식으로 입력해 주십시오.");
		return false;
	}

	// 연도 4자리, 월 2자리, 일 2자리로 자른다.
	var yearStr  = parseInt(dateStr.substring(0, 4), 10);
	var monthStr = parseInt(dateStr.substring(4, 6), 10);
	var dayStr   = parseInt(dateStr.substring(6)   , 10);


	// 연도 값이 1900 ~ 2050 사이인지 점검한다.
	if ( yearStr < 1900 || yearStr > 2050 ) {
		alert(fieldName + "의 연도는 1900년 ~ 2050년 사이의 값을 입력해야 주십시오.");
		return false;
	}

	// 월이 1~12월 사이인지 점검한다.
	if ( monthStr < 1 || monthStr > 12 ) {
		alert(fieldName + "의 월을 01 ~ 12월 사이의 값으로 입력해 주십시오.");
		return false;
	}

	var lastDayOfMonth = 31;

	if ( monthStr == 2 ) {
		lastDayOfMonth = isLeapYear(yearStr) ? 29 : 28;
	}
	else if ( monthStr == 4
			|| monthStr == 6
			|| monthStr == 9
			|| monthStr == 11 ) {
		lastDayOfMonth = 30;
	}


	if ( dayStr < 1 || dayStr > lastDayOfMonth ) {
		var msg = ( monthStr == 2 ? yearStr + "년도의 " : "" )
				+ monthStr + "월에는 " + dayStr + "일이 없습니다.";
		showMessage(msg);
		return false;
	}

	return true;
}


/**
 * 주어진 일자값이 유효한지 검사하여 유효하면 true,
 * 오류 메세지를 보여주고 false를 돌려 준다.
 *
 * @param dateStr 일자형의 문자열.
 * @param filedName 유효성을 검증하려는 항목명.
 * @return 유효여부.
 */
function validateDate(dateStr, fieldName) {
	return checkDate(dateStr);
}


/**
 * 주어진 객체의 값이 유효한 일자인지 검사하여,
 * 유효하면 true, 그렇지 않으면 오류 메세지를 보여주고
 * false를 돌려 준다.
 *
 * @param obj 일자형의 문자열을 값으로 가지는 객체.
 * @param filedName 유효성을 검증하려는 항목명.
 * @return 유효여부.
 */
function validateDateObj(obj, fieldName) {
	var isValid = validateDate(obj.value, fieldName);

	if ( ! isValid ) obj.focus();

	return isValid;
}



/**
 * 주어진 객체의 값이 유효한 일자이면
 * 객체의 값을 형식화한다.
 */
function formatDateStrObjIfValid(obj, fieldName) {
	var dateStr = removeChar(obj.value, DATE_DELIMETER);

	var valid = true;

	valid = checkDate(dateStr, fieldName);
	if ( valid ) {
		formatDateStrObj(obj);
	}
	else {
		obj.focus();
	}

	return valid;
}

/**
 * 두개의 연월(yyyy/MM형식) 문자열을 비교하여 앞 연월이 뒤 연월과
 * 같으면 0, 앞 연월이 뒤 연월보다 빠르면 1, 앞 연월이 뒤 연월보다
 * 느리면 -1을 돌려 준다.
 *
 * @param yearMonth1  앞 연월
 * @param yearMonth2  뒤 연월
 */
function compareYearMonth(yearMonth1, yearMonth2) {
	var result = 0;

	yearMonth1 = removeChar(yearMonth1, DATE_DELIMETER);
	yearMonth2 = removeChar(yearMonth2, DATE_DELIMETER);

	if ( yearMonth1 < yearMonth2 ) {
		result = 1;
	}
	else if ( yearMonth1 > yearMonth2 ) {
		result = -1;
	}

	return result;
}


/**
 * 두개의 Text형 입력폼의 연월(yyyy/MM형식) 문자열 값을 비교하여
 * 앞 연월이 뒤 연월과 같으면 0, 앞 연월이 뒤 연월보다 빠르면 1,
 * 앞 연월이 뒤 연월보다 느리면 -1을 돌려 준다.
 *
 * @param obj1  앞 연월값을 가지는 Text형 입력폼
 * @param obj2  뒤 연월값을 가지는 Text형 입력폼
 */
function compareYearMonthObj(obj1, obj2) {
	return compareYearMonth(obj1.value, obj2.value);
}


/**
 * 두개의 날짜 문자열을 비교하여 첫번째 파라미터(date1)의
 * 날짜 값이 두번째 파라미터(date2)의 날짜 값과 비교하여
 * 이르면 1을, 같으면 0을, 늦으면 -1을 돌려 준다.
 * date1은 값이 있고, date2는 값이 없으면 -1,
 * date1은 값이 없고, date2는 값이 있으면 1 이다.
 *
 * @param date1 yyyyMMdd형식의 날짜형 문자열.
 * @param date2 yyyyMMdd형식의 날짜형 문자열.
 */
function compareDate(date1, date2) {
	date1 = removeChar(date1, DATE_DELIMETER);
	date2 = removeChar(date2, DATE_DELIMETER);

	var result = 0;

	if ( date1 < date2 ) {
		result = 1;
	}
	else if ( date1 > date2 ) {
		result = -1;
	}

	return result;
}


/**
 * 두개의 날짜 문자열을 비교하여 첫번째 파라미터(obj1)의
 * 날짜 값이 두번째 파라미터(obj2)의 날짜 값과 비교하여
 * 이르면 1을, 같으면 0을, 늦으면 -1을 돌려 준다.
 * obj1은 값이 있고, obj2는 값이 없으면 -1,
 * obj1은 값이 없고, obj2는 값이 있으면 1 이다.
 *
 * @param obj1 Text형 입력폼 객체
 * @param obj2 Text형 입력폼 객체
 */
function compareDateObj(obj1, obj2) {
	return compareDate(obj1.value, obj2.value);
}


/**
 * 기간을 나타내는 두 개의 객체의 일자값의 유효성을 검증하여
 * 유효하면 true를 돌려주고, 유효하지 않으면 오류메세지를
 * 보여준 다음 false를 돌려 준다.
 *
 * @param rearDateStrObj  앞 일자 문자열 값을 갖는 객체.
 * @param foreDateStrObj 뒤 일자 문자열 값을 갖는 객체.
 * @param fieldName   항목명.
 * @param allowSameDate 동일일 허용여부. 없으면 허용(true).
 * @return 유효하면 true, 그렇지 않으면 false.
 */
function validateTermObj(rearDateStrObj, foreDateStrObj, fieldName, allowSameDate) {
	if ( fieldName == undefined ) fieldName = "기간";

	if ( allowSameDate == undefined ) allowSameDate = true;

	/* 각각 유효한 일자인지 검사한다. */
	if ( ! validateDateObj(rearDateStrObj, fieldName + " 앞일자") ) return false;

	if ( ! validateDateObj(foreDateStrObj, fieldName + " 뒤일자") ) return false;

	/* 둘 중 한 일자라도 없으면 true를 돌려 주고 끝낸다. */
	if ( isEmptyObj(rearDateStrObj) || isEmptyObj(foreDateStrObj) ) return true;

	/* 앞 일자와 뒤 일자를 비교한다. */
	var result = compareDateObj(rearDateStrObj, foreDateStrObj);

	/* 같은 일자를 허용하면 0이상 하지 않으면 1이상 이어야 한다. */
	if ( allowSameDate && result < 0 ) {
		showMessage(fieldName + " 뒤 일자는 앞 일자와 같거나 늦은 일자 이어야 합니다.");
		rearDateStrObj.focus();
		return false;
	}
	else if ( ! allowSameDate && result < 1 ) {
		showMessage(fieldName + " 뒤 일자는 앞 일자보다 늦은 일자 이어야 합니다.");
		rearDateStrObj.focus();
		return false;
	}

	/* 여기까지 왔으면 유효하다. */
	return true;
}


/**
 * Text형 입력폼에 입력된 시간(시+분)이 유효한지
 * 체크하여 유효하면 hh24:mi의 형태로 변환하여
 * return하고, 유효하지 않으면 에러메세지를
 * 보여줌(시간 입력필드의 onblur event에 사용)
 */
function checkTimeObj(obj) {
	var timeStr = obj.value;

	var valid = true;

	// 빈 문자열이면 점검하지 않는다.
	if ( trim(timeStr) != "" ) {
		valid = checkTime(timeStr);

		if ( valid ) {
			var hourStr   = timeStr.substring(0, 2);
			var minuteStr = timeStr.substring(2);

			obj.value = hourStr + ":" + minuteStr;
		}
		else {
			obj.focus();
		}
	}

	return valid;
}


/**
 * Text형 입력폼에 입력된 시간(시+분)이 유효한지
 * 체크하여 유효하면 hh24:mi의 형태로 변환하여
 * return하고, 유효하지 않으면 에러메세지를
 * 보여줌(시간 입력필드의 onblur event에 사용)
 *
 * @param timeStr  HHmm 형식의 시간형 문자열
 */
function checkTime(timeStr) {
	if ( trim(timeStr) == "" ) return true;

	timeStr = removeChar(timeStr, ':');

	// 길이가 4인지 점검한다.
	if ( timeStr.length != 4 ) {
		alert("형식이 맞지 않습니다. \"HHmm\" 형태의 숫자로 입력해 주십시오.");
		return false;
	}

	// 숫자로만 구성되었는지 점검한다.
	if ( isNaN(timeStr) ) {
		alert("문자열은 입력할 수 없습니다. \"HHmm\" 형태의 숫자로 입력해 주십시오.");
		return false;
	}

	// 시간 2자리, 분 2자리로 분리한다.
	var hourStr   = timeStr.substring(0, 2);
	var minuteStr = timeStr.substring(2);

	if ( hourStr < 0 || hourStr > 23 ) {
		alert("시간 값은 00에서 23 사이의 값이어야 합니다.");
		return false;
	}


	if ( minuteStr < 0 || minuteStr > 59 ) {
		alert("분 값은 00에서 59 사이의 값이어야 합니다.");
		return false;
	}

	return true;
}


