/**
 * @author Lee Yeong Cheon
 * @version 1.01, 07/12/13
 * @since javascript 1.5
 */

  var Exception = function(name, message, description, number) {
  	if(Browser.isMsie) {
	    var error = new Error();
	    error.name = Validate.isEmpty(name, "");
	    error.message = Validate.isEmpty(message, "");
	    error.description = Validate.isEmpty(description, "");
      if(!Validate.isEmpty(number)) error.number = number;
	    return error;
  	} else {
  		var msg = name + " - ";
  		if(!Validate.isEmpty(number)) msg += number + "\n\n";
  		msg += message + "\n\n";
  		msg += description;
      alert(msg);
  	}
  }

  // 객체의 타입과 값이 동일한 경우 true를 반환한다.
  Object.prototype.equals = function(object) {
    if(!(this instanceof eval((typeof object).toFirstUpperCase()))) return false;
    if(this == object) return true;
    return false;
  }

/*
  // 객체의 특정(event_type) 이벤트리스너에 handler를 등록한다.
  Object.prototype.addEvent = function(event_type, handler) {
    if(document.attachEvent) {
      this.attachEvent(event_type, handler);
    } else {
      this.addEventListener(event_type.replace(/^on/i,""), handler, false);
    }
  }

  // 객체의 특정(event_type) 이벤트리스너에 등록된 handler를 제거한다.
  Object.prototype.removeEvent = function(event_type, handler) {
    if(document.detachEvent) {
      this.detachEvent(event_type, handler);
    } else {
      this.removeEventListener(event_type.replace(/^on/i,""), handler, false);
    }
  }
*/

  // 값 없는 문자열인 경우 true를 반환, 그렇지 않은 경우 false를 반환한다.
  // 인자의 갯수가 1개이고 값 없는 문자열이 아닌 경우 해당 문자열을 반환한다.
  // 인자의 갯수가 1개이고 값 없는 문자열인 경우 첫번째 인자의 값을 반환한다.
  String.prototype.isEmpty = function(value) {
    var retValue = null;
    switch(arguments.length) {
      case 0 :
        if(this.length <= 0) retValue = true;
        else retValue = false;
        break;
      case 1 :
        retValue = this.isEmpty() ? value : this;
        break;
      default :
        throw Exception("Error", "지원하지 않는 기능 입니다.", "Usage \nString.isEmpty([value])");
    }
    return retValue;
  }

  // 공백문자로 이루어진 문자열인 경우만 true를 반환한다.
  String.prototype.isSpace = function() {
  	return Validate.isEmpty(this.match(/[^\s]+/g));
  }

  // 공백문자가 포함되어 있는 경우 true를 반환한다.
  String.prototype.hasSpace = function() {
  	return Validate.isEmpty(this.match(/\s+/g));
  }

  // 공백문자를 삭제한 문자열을 반환한다.
  String.prototype.removeSpace = function() {
  	return this.replace(/\s+/g,"");
  }

  // 숫자형 문자로 이루어진 문자열인 경우만 true를 반환한다.
  String.prototype.isNumber = function() {
  	return Validate.isEmpty(this.match(/[^\d]+/g));
  }

  // 숫자형 문자가 포함되어 있는 경우 true를 반환한다.
  String.prototype.hasNumber = function() {
  	return !Validate.isEmpty(this.match(/\d+/g));
  }

  // 숫자형 문자를 삭제한 문자열을 반환한다.
  String.prototype.removeNumber = function() {
    return this.replace(/\d+/g,"");
  }

  // 한글로 이루어진 문자열인 경우만 true를 반환한다.
  String.prototype.isKorean = function() {
    var regExp = new RegExp("[^"+String.fromCharCode(12593,45,12643,44032,45,55203)+"]+","gm");
    return Validate.isEmpty(this.match(regExp));
  }

  // 한글이 포함되어 있는 경우 true를 반환한다.
  String.prototype.hasKorean = function() {
    var regExp = new RegExp("["+String.fromCharCode(12593,45,12643,44032,45,55203)+"]+","gm");
    return !Validate.isEmpty(this.match(regExp));
  }

  // 한글을 삭제한 문자열을 반환한다.
  String.prototype.removeKorean = function() {
    var regExp = new RegExp("["+String.fromCharCode(12593,45,12643,44032,45,55203)+"]+","gm");
    return this.replace(regExp,"");
  }

  // 영문으로 이루어진 문자열인 경우만  true를 반환한다.
  String.prototype.isEnglish = function() {
    return Validate.isEmpty(this.match(/[^a-zA-Z]+/g));
  }

  // 영문이 포함되어 있는 경우 true를 반환한다.
  String.prototype.hasEnglish = function() {
    return !Validate.isEmpty(this.match(/[a-zA-Z]+/g));
  }

  // 영문을 삭제한 문자열을 반환한다.
  String.prototype.removeEnglish = function() {
    return this.replace(/[a-zA-Z]+/g,"");
  }

  // 문장 구성 문자(공백, 숫자, 한글, 영문)로 이루어진 문자열인 경우만 true를 반환한다.
  String.prototype.isWord = function() {
    var regExp = new RegExp("[^\s\da-zA-Z"+String.fromCharCode(12593,45,12643,44032,45,55203)+"]+","gm");
    return Validate.isEmpty(this.match(regExp));
  }

  // 문장 구성 문자(공백, 숫자, 한글, 영문)가 포함되어 있는 문자열인 경우 true를 반환한다.
  String.prototype.hasWord = function() {
    var regExp = new RegExp("[\s\da-zA-Z"+String.fromCharCode(12593,45,12643,44032,45,55203)+"]+","gm");
    return !Validate.isEmpty(this.match(regExp));
  }

  // 해당 문자열에서 문장 구성 문자(공백, 숫자, 한글, 영문)를 삭제한 문자열을 반환한다.
  String.prototype.removeWord = function() {
    var regExp = new RegExp("[\s\da-zA-Z"+String.fromCharCode(12593,45,12643,44032,45,55203)+"]+","gm");
    return this.replace(regExp,"");
  }

  // 특수문자(문장 구성 문자 이외의 문자)로 이루어진 문자열인 경우만  true를 반환한다.
  String.prototype.isSpecial = function() {
    var regExp = new RegExp("[\s\da-zA-Z"+String.fromCharCode(12593,45,12643,44032,45,55203)+"]+","gm");
    return Validate.isEmpty(this.match(regExp));
  }

  // 특수문자(문장 구성 문자 이외의 문자)가 포함되어 있는 문자열인 경우 true를 반환한다.  
  String.prototype.hasSpecial = function() {
    var regExp = new RegExp("[^\s\da-zA-Z"+String.fromCharCode(12593,45,12643,44032,45,55203)+"]+","gm");
    return !Validate.isEmpty(this.match(regExp));
  }

  // 해당 문자열에서 특수문자(문장 구성 문자 이외의 문자)를 삭제한 문자열을 반환한다.
  String.prototype.removeSpecial = function() {
    var regExp = new RegExp("[^\s\da-zA-Z"+String.fromCharCode(12593,45,12643,44032,45,55203)+"]+","gm");
    return this.replace(regExp,"");
  }

  // 선행문자가 일치 할 경우 true 반환 
  String.prototype.isPrefix = function(prefix) {
    var regExp = new RegExp("^"+prefix,"gm");
    return !Validate.isEmpty(value.match(regExp));
  }

  // 문자열 끝이 일치 할 경우 true 반환
  String.prototype.isSuffix = function(value, suffix) {
    var regExp = new RegExp(suffix+"$","gm");
    return !Validate.isEmpty(value.match(regExp));
  }

  // 정규식 패턴에 부합되는 경우 true를 반환한다.
  String.prototype.isRegexp = function(regExp) {
    return !Validate.isEmpty(this.match(regExp));
  }

  // %S 문자를 순차적으로 arguments의 값으로 치환한다.
  String.prototype.printf = function() {
    var retValue = this;
    for(var i = 0; i < arguments.length; i++) {
      retValue = retValue.replace(/%S/m,arguments[i]);
    }
    return retValue;
  }

  // 문자열 앞/뒤의 공백을 제거하여 반환한다.
  String.prototype.trim = function() {
    return this.replace(/(^\s+)|(\s+$)/gm,"");
  }

  // 문자열의 선두 문자를 대문자로 변경하여 반환한다.
  String.prototype.toFirstUpperCase = function() {
    var retValue = this;
    if(!retValue.isEmpty()) {
      retValue = retValue.charAt(0).toUpperCase()+retValue.slice(1);
    }
    return retValue;
  }

  // 대소문자 구별없이 값이 동일하면 true를 반환한다.
  String.prototype.equalsIgnoreCase = function(object) {
    if(typeof object != "string") return false;
    if(this != null && object != null) {
      return this.toUpperCase() == object.toUpperCase();
    } else if(this == object) {
      return true;
    } else {
      return false;
    }
  }

  // URL 주소 형식의 plain text를 "?" 이후의 파라미터 부분을 인코딩하여 반환한다.
  // 일반 문자열 일 경우 문자열 전체를 인코딩하여 반환한다. 
  String.prototype.encodeURI = function() {
    var retValue = "";
    var param = this;
    var index = this.indexOf("?");
    if(index >= 0) {
      retValue = this.substring(0,index+1);
      param = this.slice(index+1);
    }
    if(!param.isEmpty()) {
      param = param.replace(/&(([^&=]+)=)/gi,Char.US+"$1");
      var params = param.split(Char.US);
      for(i = 0; i < params.length; i++) {
        var index = params[i].indexOf("=");
        if(index >= 0) {
          var name = params[i].substring(0,index);
          var value = params[i].slice(index+1);
          if(i != 0) retValue += "&";
          retValue += encodeURIComponent(name)+"="+encodeURIComponent(value);
        } else {
          retValue += encodeURIComponent(params[i]);
        }
      }
    }
    return retValue;
  }

  // String.encodeURI()로 인코딩 된 값을 디코딩하여 반환한다.
  String.prototype.decodeURI = function() {
    var retValue = "";
    var param = this;
    var index = this.indexOf("?");
    if(index >= 0) {
      retValue = this.substring(0,index+1);
      param = this.slice(index+1);
    }
    if(!param.isEmpty()) {
      var params = param.split("&");
      for(i = 0; i < params.length; i++) {
        var index = params[i].indexOf("=");
        if(index >= 0) {
          var name = params[i].substring(0,index);
          var value = params[i].slice(index+1);
          if(i != 0) retValue += "&";
          retValue += decodeURIComponent(name)+"="+decodeURIComponent(value);
        } else {
          retValue += decodeURIComponent(params[i]);
        }
      }
    }
    return retValue;
  }

  // 스트링버퍼 객체 선언한다.
  var StringBuffer = Array;

  // 스트링버퍼에 문자열을 추가한다.
  StringBuffer.prototype.append = function(string) {
  	this.push(string);
  	return this;
  }

  // 스트링버퍼에 담아있는 문자열을 반환한다.
  StringBuffer.toString = function() {
    return this.join;
  }

  // 첫째날 요일을 반환 한다.
  Date.prototype.getFirstDay = function() {
    var tempDate = new Date(this.getFullYear(), this.getMonth(), 1);
    return tempDate.getDay();
  }

  // 마지막 날짜를 반환 한다.
  Date.prototype.getLastDate = function() {
    var tempDate = new Date(this.getFullYear(), this.getMonth()+1, 0);
    return tempDate.getDate();
  }

  // 주의 갯수를 반환 한다.
  Date.prototype.getWeeks = function() {
    var lastPosition = this.getFirstDay() + this.getLastDate();
    return parseInt((lastPosition / 7) + (lastPosition % 7 != 0 ? 1 : 0));
  }

  var Validate = {
  	// object가 null인 경우 true를 반환한다.
  	// 두번째 argument가 있을 경우 결과가 true 이면 두번째 argument를 반환한다. 
    isNull : function(object, value) {
      var retValue = null;
      switch(arguments.length) {
        case 1 :
          retValue = object == null ? true : false;
          break;
        case 2 :
          retValue = this.isNull(object) ? value : object;
          break;
        default :
          throw Exception("Error", "지원하지 않는 기능 입니다.", "Usage \nValidate.isNull(object[, value])");
      }
      return retValue;
    },

    // object가 null 이거나 문자열 또는 배열인 경우 길이가 0인 경우 true를 반환한다.
    // 두번째 argument가 있을 경우 결과가 true 이면 두번째 argument를 반환한다. 
    isEmpty : function(object, value) {
      var retValue = null;
      switch(arguments.length) {
        case 1 :
          retValue = (object == null || (typeof object == "string" && object.length <= 0)) ? true : false;
          break;
        case 2 :
          retValue = this.isEmpty(object) ? value : object;
          break;
        default :
          throw Exception("Error", "지원하지 않는 기능 입니다.", "Usage \nValidate.isEmpty(object[, value])");
      }
      return retValue;
    },

    // 유효한 주민등록번호인 경우만 true를 반환한다. [R]esident [R]egistration [N]umber
    isRRN : function(value) {
      var retValue = false;
      var weightCode = "234567892345";
      var keyValue = 0;
      if(!this.isEmpty(arguments[0]) && (arguments[0].length == 13) && this.isNumber(arguments[0])) {
        for(var i = 0; i < 12; i++) keyValue += (arguments[0].charAt(i) * weightCode.charAt(i));
        if(arguments[0].charAt(12) == (11-(keyValue%11))) retValue = true;
      }
      return retValue;
    }
  }

  var Cookie = {
  	// 쿠키에 값을 저장한다.
    set : function(key, value, expirehours) {
      var cookie = key + "=" + escape(value) + "; ";
      cookie += "path=/; ";
      if(!Validate.isNull(expirehours)) {
        var today = new Date();
        today.setTime(today.getTime() + (1000*60*60*expirehours));
        cookie += "expires=" + today.toGMTString() + ";";
      }
      document.cookie = cookie;
    },

    // 쿠키에서 key의 값을 찾아 반환한다. 존재하지 않는 경우 null을 반환한다.
    get : function(key) {
      var retValue = null;
      var cookie = document.cookie;
      var start_idx = cookie.indexOf(key + "=");
      if(start_idx >= 0) {
        start_idx += key.length + 1;
        var end_idx = cookie.indexOf(";", start_idx);
        if(end_idx < 0) end_idx = cookie.length;
        retValue = unescape(cookie.substring(start_idx,end_idx));
      }
      return retValue;
    },

    // 쿠키에서 key에 해당하는 값을 삭제한다.
    del : function(key) {
      var today = new Date();
      today.setTime(today.getTime()-100);
      document.cookie = key + "=; path=/; expires=" + today.toGMTString() + ";";
    }
  }

  // XMLHttpRequest Class Define
  var HttpRequest = Object;

/*
  HttpRequest.prototype.getXMLHttpRequest = function() {
    var request = null;
    if(window.ActiveXObject) {
      try {
        request = new ActiveXObject("Msxml2.XMLHTTP");
      } catch(e) {
        try {
          request = new ActiveXObject("Microsoft.XMLHTTP");
        } catch(ex) {
          request = null;
        }
      }
    } else if(window.XMLHttpRequest) {
      request = new XMLHttpRequest();
    } else {
      request = null;
    }
    return request;
  }

  HttpRequest.prototype.sendRequest = function(isAsync,method,uri,param,callback) {
    var request = this.getXMLHttpRequest();
    if(Validate.isNull(request)) {
      alert(Message.XMLHttpRequest.nonsupported);
      return null;
    }
    if(typeof isAsync != "boolean") {
      isAsync = (Validate.isEmpty(isAsync) || Validate.isEmpty(isAsync.match(/^(true|false)$/gi))) ? true : eval(isAsync.match(/^(true|false)$/gi).toString().toLowerCase());
    }
    method = (Validate.isEmpty(method) || Validate.isEmpty(method.match(/^(get|post)$/gi))) ? "get" : method.match(/^(get|post)$/gi).toString().toLowerCase();
    if(!Validate.isEmpty(callback)) {
      var execute_callback = function() {
          if(request.readyState == 4) {
            switch(request.status) {
              case 200 :
                if(typeof callback == "function") {
                  callback(request);
                } else if(typeof callback == "string") {
                  eval(callback);
                }
                break;
              default :
                alert("Error "+request.status+" "+request.statusText);
            }
          }
      };
      if(Browser.isSafari||Browser.isMozes||Browser.isOpera) {
        request.onload = execute_callback;
      } else {
        request.onreadystatechange = execute_callback;
      }
    } else {
      if(Browser.isSafari||Browser.isMozes||Browser.isOpera) {
        request.onload = function(){};
      } else {
        request.onreadystatechange = function(){};
      }
    }
    param = param.encodeURI();
    if(method == "get") {
      if(!Validate.isEmpty(param)) uri += "?" + param;
      param = "";
    }
    request.open(method,uri,isAsync);
    if(window.opera && typeof request.setRequestHeader == "function");
    request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
    request.send(param);
    return request;
  }
*/

  // 브라우저 정보
  var Browser = {
    isMsie      : !Validate.isEmpty(navigator.userAgent.match(/MSIE/gi)),
    isMozes     : !Validate.isEmpty(navigator.userAgent.match(/Gecko/gi)),
    isOpera     : !Validate.isEmpty(navigator.userAgent.match(/Opera/gi)),
    isKhtml     : !Validate.isEmpty(navigator.userAgent.match(/KHTML/gi)),
    isSafari    : !Validate.isEmpty(navigator.userAgent.match(/AppleWebKit/gi)),
    isFirefox   : !Validate.isEmpty(navigator.userAgent.match(/Firefox/gi)),
    isNetscape  : !Validate.isEmpty(navigator.userAgent.match(/Netscape/gi)),
    name        : navigator.userAgent.match(/(MSIE)|(Opera)|(Safari)|(Firefox)|(Netscape)/gi).toString(),
    version     : navigator.userAgent.match(/(MSIE [\d\.]*)|(Opera\/[\d\.]*)|(Firefox\/[\d\.]*)|(Netscape\/[\d\.]*)/gi).toString().replace(/[^\d\.]*/gi,"")
  }