/**
 * @fileoverview Netville JavaScript Library
 * @author Netville R&D Institude
 * @version 1.0.1.
 * @since 2008.08.
 * 
 * - nv.Form.getCheckedValue 추가
 * - nv.Img.resizeImages null 처리
 */
 
// 최상위 namespace
var nv = {};

nvConfirm = false;

// ------------------------------------------------------------------------------------------------
// - 기본 기능
// ------------------------------------------------------------------------------------------------
/**
 * document.getElementById 간소화
 * 
 * @param {string} elementId 엘리먼트 id 속성값
 * @return 엘리먼트 객체 
 */
nv.$ = function(elementId) { return document.getElementById(elementId); };

// ------------------------------------------------------------------------------------------------
// - BrowserDetector 기능
// ------------------------------------------------------------------------------------------------
nv.BrowserDetector = function() {
    return {
        /**
         *  initialize method
         */
        initialize: function(){
            this.name = this.searchString(this.dataBrowser) || "An unknown browser";
            this.version = this.searchVersion(navigator.userAgent)
                || this.searchVersion(navigator.appVersion)
                || "an unknown version";
            this.os = this.searchString(this.dataOS) || "an unknown OS";
			this.lang = navigator.browserLanguage || navigator.language;
			this.locale = this.lang.indexOf('-') > -1 ? this.lang.substring(0, this.lang.indexOf('-')) : this.lang;			
			this.isIE = (this.name == "Explorer");
			
			//alert("browser=["+this.name+"], version=["+this.version+"], os=["+this.os+"], locale=["+this.locale+"], isIE=["+this.isIE+"]");
        },
		
		info: function() {
			return {NAME: this.name, VERSION: this.version, OS: this.os, LOCALE: this.locale, isIE: this.isIE}
		},
        
        searchString: function (data) {
            for (var i=0;i<data.length;i++)	{
                var dataString = data[i].string;
                var dataProp = data[i].prop;
                this.versionSearchString = data[i].versionSearch || data[i].identity;
                if (dataString) {
                    if (dataString.indexOf(data[i].subString) != -1)
                        return data[i].identity;
                }
                else if (dataProp)
                    return data[i].identity;
            }
        },
        
        searchVersion: function (dataString) {
            var index = dataString.indexOf(this.versionSearchString);
            if (index == -1) return;
            return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
        },
        dataBrowser: [
            {
                string: navigator.userAgent,
                subString: "Chrome",
                identity: "Chrome"
            },
            { 	string: navigator.userAgent,
                subString: "OmniWeb",
                versionSearch: "OmniWeb/",
                identity: "OmniWeb"
            },
            {
                string: navigator.vendor,
                subString: "Apple",
                identity: "Safari",
                versionSearch: "Version"
            },
            {
                prop: window.opera,
                identity: "Opera"
            },
            {
                string: navigator.vendor,
                subString: "iCab",
                identity: "iCab"
            },
            {
                string: navigator.vendor,
                subString: "KDE",
                identity: "Konqueror"
            },
            {
                string: navigator.userAgent,
                subString: "Firefox",
                identity: "Firefox"
            },
            {
                string: navigator.vendor,
                subString: "Camino",
                identity: "Camino"
            },
            {	// for newer Netscapes (6+)
                string: navigator.userAgent,
                subString: "Netscape",
                identity: "Netscape"
            },
            {
                string: navigator.userAgent,
                subString: "MSIE",
                identity: "Explorer",
                versionSearch: "MSIE"
            },
            {
                string: navigator.userAgent,
                subString: "Gecko",
                identity: "Mozilla",
                versionSearch: "rv"
            },
            { 	// for older Netscapes (4-)
                string: navigator.userAgent,
                subString: "Mozilla",
                identity: "Netscape",
                versionSearch: "Mozilla"
            }
        ],
        dataOS : [
            {
                string: navigator.platform,
                subString: "Win",
                identity: "Windows"
            },
            {
                string: navigator.platform,
                subString: "Mac",
                identity: "Mac"
            },
            {
                string: navigator.platform,
                subString: "Linux",
                identity: "Linux"
            }
        ]
    };
}();
// initialize
nv.BrowserDetector.initialize();





// ------------------------------------------------------------------------------------------------
// - Ajax 기능
// ------------------------------------------------------------------------------------------------
/**
 * XMLHttpRequest 호출
 * 
 * @param {string} url 요청 URL
 * @param {string} params 요청 파라미터
 * @param {function object} callback 콜백 함수 객체
 * @param {string} method (GET/POST)
 * @param {string} returnType 리턴 객체 타입 (TEXT/XML/BODY/JSON)
 * @param {object} variable 가변 데이터
 */
nv.Ajax = function(url, params, callback, method, returnType, variable) {
    this.url = url;
    this.params = params;
    this.callback = callback;
    this.method = method; 
    this.returnType = returnType;
    this.variable = variable;
    this.send();
}

/**
 * XHR 객체 획득
 * 
 * @return XHR 객체
 */
nv.Ajax.prototype.getXMLHttpRequest = function() {
    if(window.ActiveXObject) {
        try {
            return new ActiveXObject("Msxml2.XMLHTTP");
        } catch(e) {
            try { return new ActiveXObject("Microsoft.XMLHTTP"); }
            catch(e1) { return null; }
        }
    } else if(window.XMLHttpRequest) { return new XMLHttpRequest(); }
    else { return null; }
}

/**
 * Ajax 호출
 */
nv.Ajax.prototype.send = function() {
    this.req = this.getXMLHttpRequest();
    var httpMethod = this.method ? this.method : "GET";
    if(httpMethod != "GET" && httpMethod != "POST") {
        httpMethod = "GET";
    }
    var httpParams = (this.params == null || this.params == "") ? null : this.params;
    var httpUrl = this.url;
    if(httpMethod == "GET" && httpMethod != null) {
        httpUrl = httpUrl + "?" + httpParams;
    }
    this.req.open(httpMethod, httpUrl, true);
    this.req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    var request = this;
    this.req.onreadystatechange = function() {
        request.onStateChange.call(request);
    }
    this.req.send(httpMethod == "POST" ? httpParams : null);
}

/**
 * Ajax 상태 변경시 호출
 */
nv.Ajax.prototype.onStateChange = function() {
    if(this.req.readyState == 1) this.ajaxLoading(true);
    if(this.req.readyState == 4) {
        if(this.req.status == 200) {
            
            var resultObj = null;
            var type = this.returnType ? this.returnType : "TEXT"; 
            try {
                //alert(this.req.responseText);
                if(type == "XML") resultObj = this.req.responseXML;
                else if(type == "BODY") resultObj = this.req.responseBody;
                else if(type == "JSON") resultObj = eval("(" + this.req.responseText + ")");
                else resultObj = this.req.responseText;
            } catch(e) {
                this.ajaxLoading(false);
                alert("Response Error");
                return;
            }
            this.ajaxLoading(false);
            this.callback(resultObj, this.variable);
        }
    }
}

/**
 * Ajax 로딩표시
 * 
 * @param loadingFlag {boolean} 표시여부
 */
nv.Ajax.prototype.ajaxLoading = function(loadingFlag) {
    var loadingDivName = "nv.ajaxLoadingDiv";
    if(loadingFlag) {
        var bodyElement = document.getElementsByTagName("body").item(0);
        var loadingDiv = document.createElement("div");
        loadingDiv.id = loadingDivName;
        loadingDiv.style.position = "absolute";
        loadingDiv.style.padding = "1px 1px 1px 1px";
        loadingDiv.style.fontFamily = "verdana";
        loadingDiv.style.color = "blue";
        loadingDiv.style.backgroundColor = "yellow";
        loadingDiv.style.fontSize = "10px";
        loadingDiv.style.right = "10px";
        loadingDiv.style.top = nv.UI.getClientXY().y + 10 + "px";
        loadingDiv.style.zIndex = "1000";            
        loadingDiv.appendChild(document.createTextNode("Loading.."));
        bodyElement.appendChild(loadingDiv);
        //nv.UI.setOpacity(loadingDiv, 0.5);
    } else {
        nv.Dom.removeNode(nv.$(loadingDivName));                
    }
}





// ------------------------------------------------------------------------------------------------
// - Dynamic Script 기능
// ------------------------------------------------------------------------------------------------
/**
 * 동적 스크립트 생성 호출
 * 
 * @param url 스크립트 URL
 */
nv.DynamicScript = function(url) {
    this.url = url;
    this.send();
}

/**
 * 동적 스크립트를 생성하여 head 엘리먼트에 추가
 */
nv.DynamicScript.prototype.send = function() {
    var head = document.getElementsByTagName("head").item(0);
    var script = document.createElement("script");
    script.src = this.url;
    head.appendChild(script);
}





// ------------------------------------------------------------------------------------------------
// - Event 기능
// ------------------------------------------------------------------------------------------------
nv.Event = {};

/**
 * 이벤트 등록
 * 
 * @param {element object} element 엘리먼트 객체
 * @param {string} name 이벤트명
 * @param {function object} observer 이벤트시 실행될 함수
 * @param {boolean} userCapture 캡쳐여부
 */
nv.Event.addListener = function(element, name, observer, useCapture) {
    useCapture = useCapture || false;
    if (element.addEventListener) {
        element.addEventListener(name, observer, useCapture);
    } else if (element.attachEvent) {
        element.attachEvent("on" + name, observer);
    }
}

/**
 * 이벤트 삭제
 * 
 * @param {element object} element 엘리먼트 객체
 * @param {string} name 이벤트명
 * @param {function object} observer 이벤트시 실행될 함수
 * @param {boolean} userCapture 캡쳐여부
 */
nv.Event.removeListener = function(element, name, observer, useCapture) {
    useCapture = useCapture || false;
    if (element.removeEventListener) {
        element.removeEventListener(name, observer, useCapture);
    } else if (element.detachEvent) {
        element.detachEvent("on" + name, observer);
    }
}

/**
 * 이벤트 출처 엘리먼트 획득
 * 
 * @param {event object} event 이벤트 객체
 * @return {element object} 엘리먼트 객체
 */
nv.Event.getTarget = function(event) {
    if (event == null) return null;
    if (event.target) return event.target;
    else if (event.srcElement) return event.srcElement;
    return null;
}    

/**
 * 마우스 이벤트 좌표 획득
 * 
 * @param {event object} event 이벤트 객체
 * @return {json object} 좌표 JSON 객체
 */
nv.Event.getMouseXY = function(event) {
    var mouseX = event.clientX;
    var mouseY = event.clientY;
    var dd = document.documentElement;
    var db = document.body;
    if (dd) {
        mouseX += dd.scrollLeft;
        mouseY += dd.scrollTop;
    } else if (db) {
        mouseX += db.scrollLeft;
        mouseY += db.scrollTop;
    }
    return {"x": mouseX, "y": mouseY};
}

/**
 * 이벤트 전파 중지
 * 
 * @param {event object} event 이벤트 객체
 */
nv.Event.stopPropagation = function(event) {
    if (event.stopPropagation) event.stopPropagation();
    else event.cancelBubble = true;
}

/**
 * 기본 이벤트 중지
 * 
 * @param {event object} event 이벤트 객체
 */
nv.Event.preventDefault = function(event) {
    if (event.preventDefault) event.preventDefault();
    else event.returnValue = false;
}

/**
 * 이벤트 중지
 * 
 * @param {event object} event 이벤트 객체
 */
nv.Event.stopEvent = function(event) {
    ajax.Event.stopPropagation(event);
    ajax.Event.preventDefault(event);
}

/**
 * this 문제 처리
 * 
 * @param {function object} func 함수 객체
 * @param {object} this 객체
 * @return {function object} this 문제 처리된 함수
 */
nv.Event.bindAsListener = function(func, obj) {
    return function() { return func.apply(obj, arguments); };
}

    



// ------------------------------------------------------------------------------------------------
// - UI 관련 기능
// ------------------------------------------------------------------------------------------------
nv.UI = {};

/**
 * 엘리먼트의 투명도를 조정
 * 
 * @param {element object} element 엘리먼트 객체
 * @param {float} opacity 투명도(0~1) ex. 0.75
 */
nv.UI.setOpacity = function(element, opacity) {
    if (element.filters) element.style.filter = "alpha(opacity=" + opacity * 100 + ")";
    else element.style.opacity = opacity;
}

/**
 * 스타일 속성 획득
 *  - 태그에 정의되지 않은 속성까지 획득한다.
 * 
 * @param {element object} element 엘리먼트 객체
 * @param {string} property 프로퍼티명
 * @return {string} 속성값
 */
nv.UI.getStyle = function(element, property) {
    var value = null;
    var dv = document.defaultView;
    if (property == "opacity" && element.filters) {  // IE opacity
        value = 1;
        try { value = element.filters.item("alpha").opacity / 100; }
        catch(e) {}
    } else if (element.style[property]) {
        value = element.style[property];
    } else if (element.currentStyle && element.currentStyle[property]) {
        value = element.currentStyle[property];
    } else if ( dv && dv.getComputedStyle ) {
        // 대문자를 소문자로 변환하고 그 앞에 "-"를 붙인다.
        var converted = "";
        for(i = 0, len = property.length;i < len; ++i) {
            if (property.charAt(i) == property.charAt(i).toUpperCase()) {
                converted = converted + "-" + property.charAt(i).toLowerCase();
            } else {
                converted = converted + property.charAt(i);
            }
        }
        if (dv.getComputedStyle(element, "").getPropertyValue(converted)) {
            value = dv.getComputedStyle(element, "").getPropertyValue(converted);
        }
    }
    return value;
}

/**
 * 엘리먼트의 좌표를 획득 
 * 
 * @param {element object} element 엘리먼트 객체
 * @return {json object} 엘리먼트 좌표 JSON 객체
 */
nv.UI.getXY = function(element) {
    // el은 문서에 포함되어 있어야 하고, 화면에 보여야 한다.
    if (element.parentNode === null || element.style.display == "none") {
        return false;
    }
    var parent = null;
    var pos = [];
    var box;
    if (document.getBoundingClientRect) { // gecko 엔진 기반
        box = document.getBoxObjectFor(element);
        pos = [box.x, box.y];
    } else { // 기타 브라우저
        pos = [element.offsetLeft, element.offsetTop];
        parent = element.offsetParent;
        if (parent != element) {
            while (parent) {
                pos[0] += parent.offsetLeft;
                pos[1] += parent.offsetTop;
                parent = parent.offsetParent;
            }
        }
        // 오페라와 사파리의 absolute postion의 경우
        // body의 offsetTop을 잘못 계산하므로 보정해야 한다.
        var ua = navigator.userAgent.toLowerCase();
        if (ua.indexOf("opera") != -1
            || ( ua.indexOf("safari") != -1
            && this.getStyle(element, "position") == "absolute" )
        ) {
            pos[1] -= document.body.offsetTop;
        }
    }
    
    if (element.parentNode) { parent = element.parentNode; }
    else { parent = null; }
    
    // body 또는 html 이외의 부모 노드 중에 스크롤되어 있는
    // 영역이 있다면 알맞게 처리한다.
    while (parent && parent.tagName != "BODY" && parent.tagName != "HTML") {
        pos[0] -= parent.scrollLeft;
        pos[1] -= parent.scrollTop;
        
        if (parent.parentNode) { parent = parent.parentNode; }
        else { parent = null; }
    }
    return {"x": pos[0], "y": pos[1]};
}

/**
 * 엘리먼트의 위치를 이동
 * 
 * @param {element object} element 엘리먼트 객체
 * @param {int} x x축 좌표
 * @param {int} y y축 좌표
 * @return {boolean} 이동여부
 */
nv.UI.setXY = function(element, x, y) {
    var pageXY = this.getXY(element);
    if (pageXY === false) { return false; }
    var position = this.getStyle(element, "position");
    if (!position || position == "static") {
        element.style.position = "relative";
    }
    var delta = {
        "x" : parseInt( this.getStyle(element, "left"), 10 ),
        "y" : parseInt( this.getStyle(element, "top"), 10 )
    };
    if ( isNaN(delta.x) ) { delta.x = 0; }
    if ( isNaN(delta.y) ) { delta.y = 0; }
    if (x != null) {
        element.style.left = (x - pageXY.x + delta.x) + "px";
    }
    if (y != null) {
        element.style.top = (y - pageXY.y + delta.y) + "px";
    }
    return true;
}

/**
 * 엘리먼트의 위치와 크기 획득
 * 
 * @param {element object} element 엘리먼트 객체
 * @return {json object} 위치값 JSON 객체
 */
nv.UI.getBounds = function(element) {
    var xy = this.getXY(element);
    return {
        "x" : xy.x,
        "y" : xy.y,
        "width" : element.offsetWidth,
        "height" : element.offsetHeight
    };
}    

/**
 * 클라이언트의 사이즈, 스크롤 위치 획득
 * 
 * @return 클라이언트 위치, 스크롤 JSON 객체 
 */
nv.UI.getClientXY = function() {
    var h = (window.innerHeight || self.innerHeight || document.documentElement.clientHeight || document.body.clientHeight);
	var w = (window.innerWidth || self.innerWidth || document.documentElement.clientWidth || document.body.clientWidth);
	var x = ((window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft));
	var y = ((window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop));

    return { "w": w, "h": h, "x": x, "y": y };
}

/**
 * 화면 중앙에 위치 시키기 위한 좌표 획득
 * 
 * @param width 가로 사이즈
 * @param height 세로 사이즈
 * 
 * @return 위치값 JSON 객체
 */
nv.UI.getCenterXY = function(width, height) {
    var clientXY = this.getClientXY();
    return { "x": ((clientXY.w/2) + clientXY.x) - (width/2),
        "y": ((clientXY.h/2) + clientXY.y) - (height/2) };
}

/**
 * 엘리먼트 객체를 화면 중앙에 표시
 * 
 * @param 엘리먼트 객체
 */
nv.UI.displayCenter = function(element) {
    var elementSize = this.getBounds(element);
    var centerXY = this.getCenterXY(elementSize.width, elementSize.height);
    element.style.position = "absolute";
    element.style.left = (centerXY.x > 0 ? centerXY.x : 20) + "px";
    element.style.top = (centerXY.y > 0 ? centerXY.y : 20) + "px";
}




// ------------------------------------------------------------------------------------------------
// - LightBox 관련 기능
// ------------------------------------------------------------------------------------------------
nv.LBox = {};

nv.LBox.lboxStatus = false;  // lightbox 상태 (true/false)
nv.LBox.bodyElement = null;  // body 엘리먼트 객체
nv.LBox.resizeTimer = null;  // lightbox 크기 자동조정 타이머
nv.LBox.boxDivSize = -1;  // lightbox contents 크기
    
/**
 * lightbox 생성
 * 
 * @param {string} htmlTxt 중앙에 표시할 HTML
 */
nv.LBox.on = function(htmlTxt, funcName) {
    if(!this.lboxStatus) {
        this.bodyElement = document.getElementsByTagName("body").item(0);
        
        var lboxElement = document.getElementById("nv.lboxElementDiv");
        if(!lboxElement) {
            // 박스 엘리먼트 생성
            var lboxElement = document.createElement("div");
            lboxElement.id = "nv.lboxElementDiv";
            lboxElement.style.position = "absolute"
            lboxElement.style.width = "0px";
            lboxElement.style.height = "0px";
            lboxElement.style.left = "0px";
            lboxElement.style.top = "0px";
            lboxElement.style.zIndex = "99999";
            this.bodyElement.appendChild(lboxElement);
            nv.UI.setOpacity(lboxElement, 0.35);
            lboxElement.style.backgroundColor = "#000";
            
            var funcObj = this;
            if(typeof(funcName) != 'undefined') {
                funcObj = funcName;
            }
            
            // click 이벤트 부여
            nv.Event.addListener(lboxElement, "click", nv.Event.bindAsListener(this.off, funcObj));
        } 

        this.lboxStatus = true;

        this.resizeBoxDiv();
        this.writeContents(htmlTxt);
        
        // 브라우저 크기 변경에 맞춰 변경
        this.resizeTimer = window.setInterval(nv.Event.bindAsListener(this.resizeBoxDiv, this), 300);
    }
}

/**
 * lightbox 크기를 자동 조정
 */
nv.LBox.resizeBoxDiv = function() {
    if(this.lboxStatus) {
        // 엘리먼트의 크기 획득
        var bodyBounds = nv.UI.getBounds(this.bodyElement);
        var elementWidth = parseInt(bodyBounds.width);
        var elementHeight = parseInt(bodyBounds.height);
        var elementMarginLeftRight = parseInt(nv.UI.getStyle(this.bodyElement, "marginLeft"))
                                   + parseInt(nv.UI.getStyle(this.bodyElement, "marginRight"));
        var elementMarginTopBottom = parseInt(nv.UI.getStyle(this.bodyElement, "marginTop"))
                                   + parseInt(nv.UI.getStyle(this.bodyElement, "marginBottom"));
        var lboxWidth = elementWidth + elementMarginLeftRight;
        var lboxHeight = elementHeight + elementMarginTopBottom;
        
        // body 영역의 크기가 화면보다 작을 경우 화면 크기로 대체 
        var clientXY = nv.UI.getClientXY();
        var clientWidth = clientXY.w + clientXY.x;
        var clientHeight = clientXY.h + clientXY.y; 
        if((clientWidth) > lboxWidth) lboxWidth = clientWidth;
        if((clientHeight) > lboxHeight) lboxHeight = clientHeight;

        // 크기 조정
        var lboxElement = document.getElementById("nv.lboxElementDiv");        
        if(lboxElement) {
            lboxElement.style.width = lboxWidth + "px";
            lboxElement.style.height = lboxHeight + "px";
        }
        
        // 컨텐츠 크기에 변화가 있을 경우 위치 재세팅
        if(this.boxDivSize != (elementWidth + elementHeight)) {
            // 화면 중앙에 표시
            var contentsElement = document.getElementById("nv.lboxContentsElementDiv");
            if(contentsElement) { 
                nv.UI.displayCenter(contentsElement);
                this.boxDivSize = elementWidth + elementHeight;
            }    
        }
        
    }
}

/**
 * lightbox 중앙에 컨텐츠 표시
 * 
 * @param {string} htmlTxt 중앙에 표시할 HTML
 */
nv.LBox.writeContents = function(htmlTxt) {
    if(this.lboxStatus) {
        var contentsElement = document.getElementById("nv.lboxContentsElementDiv");
        if(!contentsElement) {
            contentsElement = document.createElement("div");
            contentsElement.id = "nv.lboxContentsElementDiv";
            contentsElement.style.position = "absolute";
            //contentsElement.style.backgroundColor = "white";
            contentsElement.style.zIndex = "999999";
            contentsElement.style.padding = "0px";
            this.bodyElement.appendChild(contentsElement);
        }
        nv.UI.setOpacity(contentsElement, 0);
        contentsElement.innerHTML = htmlTxt;
        
        // 화면 중앙에 표시
        nv.UI.displayCenter(contentsElement);
        nv.UI.setOpacity(contentsElement, 1);
    }
}

/**
 * lightbox를 제거
 */
nv.LBox.off = function() {
    if(this.lboxStatus) {
        // div 영역 제거
        nv.Dom.removeNode(document.getElementById("nv.lboxContentsElementDiv"));
        nv.Dom.removeNode(document.getElementById("nv.lboxElementDiv"));
         // 초기화
        window.clearInterval(this.resizeTimer);
        this.lboxStatus = false;
        this.bodyElement = null;
        this.boxDivSize = -1;
    }
}
    




// ------------------------------------------------------------------------------------------------
// - 팝업 관련 기능
// ------------------------------------------------------------------------------------------------
nv.Popup = {};

/**
 * 화면 중앙에 팝업 생성
 * 
 * @param url 팝업 URL
 * @param name 팝업명
 * @param width 가로크기
 * @param height 세로크기
 * @param scroll yes/no
 * @param resizable yes/no
 */    
nv.Popup.open = function(url, name, width, height, scrollbars, resizable) {
    if(!scrollbars) scrollbars = "no";
    if(!resizable) resizable = "no";
    window.open(url, name,
            "width=" + width + ", height=" + height
            + ", left=" + (screen.width/2-parseInt(width)/2) + ", top=" + (screen.height/2-parseInt(height)/2)
            + ", scrollbars=" + scrollbars + ", resizable=" + resizable
            + ", toolbar=no, directories=no, status=no, menubar=no");
}

/**
 * 팝업 사이즈 자동 조정
 */
nv.Popup.autoResize = function(popupObj) {
    // TODO 정리할것
    if (document.layers) { 
        var sinist = screen.width / 2 - outerWidth / 2; 
        var toppo = screen.height / 2 - outerHeight / 2; 
    } else {
        var sinist = screen.width / 2 - document.body.offsetWidth / 2; 
        var toppo = -75 + screen.height / 2 - document.body.offsetHeight / 2; 
    } 
    self.moveTo(sinist, toppo);  
}





// ------------------------------------------------------------------------------------------------
// - DOM 기능 .. http://www.w3schools.com/dom/
// ------------------------------------------------------------------------------------------------
nv.Dom = {};

/**
 * 노드 삭제
 * 
 * @param {node object} node 노드 객체
 */ 
nv.Dom.removeNode = function(node) {
    if(node && node.parentNode)
        node.parentNode.removeChild(node);
}

/**
 * 노드 교체
 * 
 * @param {node object} oldNode 이전 노드 객체
 * @param {node object} newNode 새 노드 객체
 */
nv.Dom.replaceNode = function(oldNode, newNode) {
    if(oldNode && oldNode.parentNode)
        oldNode.parentNode.replaceChild(newNode, oldNode);
}

/**
 * 하위 노드 모두 삭제
 * 
 * @param {node object} node 노드 객체
 */
nv.Dom.removeChildNodes = function(node) {
    // innerHTML 형태의 삭제
    // if(node) node.innerHTML = "";
    
    /* 노드형태의 삭제 */
    while(node && node.childNodes.length > 0) {
        var childNode = node.childNodes.item(0);
        this.removeNode(childNode);
    }
}

/**
 * class명으로 노드 찾기
 * 
 * @param {node object} rootNode
 * @param {string} className
 * @param {array} resultContainer
 * @return {array} node 배열
 */
nv.Dom.getNodeListByClassName = function(rootNode, className, resultContainer) {
	if (!rootNode) return null;
	if (!resultContainer) resultContainer = [];
	var classNames;
	if (rootNode.className) {
		classNames = rootNode.className.split(" ");
		for (var i=0; i < classNames.length; i++) {
			if (classNames[i] == className) resultContainer.push(rootNode);
		}
	}
    // 자식노드가 있을경우 재귀호출
	if (rootNode.childNodes) {
        for (var j = 0; j < rootNode.childNodes.length; j++) {
			this.getNodeListByClassName(rootNode.childNodes.item(j), className, resultContainer);
		}				
	}
    return resultContainer;
}





// ------------------------------------------------------------------------------------------------
// - 폼체크 기능 (from TLEJavaScript) 
// - http://kldp.net/projects/tle
// - http://javacan.madvirus.net/main/content/read.tle?contentId=111
// ------------------------------------------------------------------------------------------------
// confirm object
var nvConfirm;

/*
 * Confirm 체크 클래스
 * 
 * @param {class} 선언된 validator class
 */
nv.Confirm = function(validator) {
    this.validator = validator;
}

/*
 * Confirm 실행
 */
nv.Confirm.prototype.submit = function () {
    if(this.validator) {
        this.validator.checkForm.action = this.validator.confirmAction;
        this.validator.checkForm.method = this.validator.confirmMethod;
        this.validator.checkForm.submit();
    } else {
        alert('validator class is not invalid.');
    }
}

/**
 * 폼체크 클래스
 *  - checkForm 없을 경우 id로 체크함
 *  - alertFunc 없을 경우 alert() 경고창  
 * 
 * @param {form object} checkForm 체크할 폼
 * @param {function object} alertFunc 경고창을 표시할 함수 
 */
nv.Validator = function(checkForm, alertFunc) {
    this.checkForm = checkForm;
    this.validateObjectArray = new Array();
    this.alertFunc = alertFunc;  // 경고창 함수
}

/*
 * confirm 검사 시 발생되는 메시지
 * 
 * @param {string} 경고메시지
 */
nv.Validator.prototype.setConfirmMessage = function (confirmMessage) {
    this.confirmMessage = confirmMessage;
}

/*
 * confirm 검사 후 이동할 action
 * 
 * @param {string} action 경로
 * @param {string} action method post/get
 */
nv.Validator.prototype.setConfirmAction = function (confirmAction, confirmMethod, buttonType, cancelHref, secondButtonType) {
    this.confirmAction = confirmAction;
    this.confirmMethod = confirmMethod;
    this.buttonType = buttonType;
    this.cancelHref = cancelHref;
    this.secondButtonType = secondButtonType;
}

/**
 * 유효성 객체
 * 
 * @param {string} identifier id 또는 name
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부
 */
nv.Validator.prototype.ValidateObject = function(identifier, errorMessage, focusFlag) {
    this.identifier = identifier;
    this.errorMessage = errorMessage;
    this.focusFlag = focusFlag;
}

/**
 * id 또는 name으로 엘리먼트 객체를 획득
 * 
 * @param {string} identifier id 또는 name
 * @return {element object} 엘리먼트 객체
 */
nv.Validator.prototype.getElement = function(identifier) {
    if(this.checkForm && this.checkForm.nodeName == "FORM") {
        return this.checkForm[identifier];
    } else {
        return document.getElementById(identifier);
    }
}

/**
 * 유효성 검사
 * 
 * @return {boolean} 유효성 검사결과
 */
nv.Validator.prototype.validate = function() {
    for(var i=0; i<this.validateObjectArray.length; i++) {
        var validateObject = this.validateObjectArray[i];
        if(!validateObject.validate()) {
            
            if(this.alertFunc) this.alertFunc(validateObject.errorMessage);
            else alert(validateObject.errorMessage); 
            if(validateObject.focusFlag) {
                this.getElement(validateObject.identifier).focus();
            }
            this.validateObjectArray = new Array();
            return false;
        }
    }
    this.validateObjectArray = new Array();
    return true;
}

/**
 * 유효성 검사
 * 
 * @return {boolean} 유효성 검사결과
 */
nv.Validator.prototype.confirmValidate = function(confirmFunc) {
    this.validate();
    if(confirmFunc) {
        nvConfirm = new nv.Confirm(this);
        confirmFunc(this.confirmMessage, this.buttonType, this.cancelHref, this.secondButtonType);    
    }
}

/**
 * 입력된 값이 비교할 값과 동일한지 검사.
 * 
 * @param {string} identifier id 또는 name
 * @param {string} 비교할 identifier id 또는 name
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부
 */    
nv.Validator.prototype.checkObjectValueRequired = function(identifier, compareIdentifier, errorMessage, focusFlag) {
    var checkElement = this.getElement(identifier); 
    var checkCompareElement = this.getElement(compareIdentifier);
    var validateObject = new this.ValidateObject(identifier, errorMessage, focusFlag);
    validateObject.validate = function() {
        return (checkElement.value) == (checkCompareElement.value);
    }
    this.validateObjectArray.push(validateObject);
}

/**
 * 숫자가 큰지 작은지 여부를 검사한다.
 * 
 * @param {int} sourceValue 비교 대상 값
 * @param {int} targetValue 비교 할 값
 * @param {boolean} minMax true - min, false - max
 * @param {string} errorMessage 에러메시지
 */    
nv.Validator.prototype.checkMinMaxNumberSize = function(sourceValue, targetValue, minMax, errorMessage) {
    var validateObject = new this.ValidateObject(null, errorMessage, false);
    validateObject.validate = function() {
        if(minMax) {
            return sourceValue >= targetValue;
        } else {
            return sourceValue < targetValue;
        }
    }
    this.validateObjectArray.push(validateObject);
}

/**
 * <select>에서 선택한 옵션의 인덱스가 firstIdx보다 크거나 같은 지 검사한다.
 * 
 * @param {string} identifier id 또는 name
 * @param {int} firstIdx 옵션인덱스
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부
 */
nv.Validator.prototype.checkAtLeastOneSelected = function(identifier, errorMessage, focusFlag) {
    var checkElement = this.getElement(identifier);
    var validateObject = new this.ValidateObject(identifier, errorMessage, focusFlag);
    validateObject.validate = function() {
        var idx = checkElement.selectedIndex;
        return idx > 0;
    }
    this.validateObjectArray.push(validateObject);
}

/**
 * checkbox나 radio 입력 요소의 선택된 값이 비교할 값과 일치하는 지 검사.
 * 
 * @param {string} identifier id 또는 name
 * @param {string} compareValue 비교할값
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부
 */
nv.Validator.prototype.checkAtLeastValueOneChecked = function(identifier, compareValue, errorMessage, focusFlag) {
    var validateObject = new this.ValidateObject(null, errorMessage, false);
    validateObject.validate = function() {
        var ele = document.getElementsByName(identifier);
        var eleValue = '';
        for (var idxe = 0 ; idxe < ele.length ; idxe++) {
            if (ele[idxe].checked == true) {
                eleValue = ele[idxe].value;
            }
        }
        
        return compareValue == eleValue;
    }
    this.validateObjectArray.push(validateObject);
}

/**
 * 값을 입력했는지의 여부를 검사
 * 
 * @param {string} identifier id 또는 name
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부
 */    
nv.Validator.prototype.checkRequired = function(identifier, errorMessage, focusFlag) {
    var checkElement = this.getElement(identifier); 
    var validateObject = new this.ValidateObject(identifier, errorMessage, focusFlag);
    validateObject.validate = function() {
        return (checkElement.value).replace(/^\s*/, "").replace(/\s*$/, "") != "";
    }
    this.validateObjectArray.push(validateObject);
}

/**
 * 입력된 값이 비교할 값과 동일한지 검사.
 * 
 * @param {string} identifier id 또는 name
 * @param {string} value 비교할 값
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부
 */    
nv.Validator.prototype.checkValueRequired = function(identifier, value, errorMessage, focusFlag) {
    var checkElement = this.getElement(identifier); 
    var validateObject = new this.ValidateObject(identifier, errorMessage, focusFlag);
    validateObject.validate = function() {
        return (checkElement.value) == value;
    }
    this.validateObjectArray.push(validateObject);
}

/**
 * 값의 길이가 maxLength보다 작거나 같은지 검사
 * 
 * @param {string} identifier id 또는 name
 * @param {int} maxLength 체크값
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부 
 */
nv.Validator.prototype.checkMaxLength = function(identifier, maxLength, errorMessage, focusFlag) {
    var checkElement = this.getElement(identifier); 
    var validateObject = new this.ValidateObject(identifier, errorMessage, focusFlag);
    validateObject.validate = function() {
    	var stringValue = checkElement.value;
    	
    	var nbytes = 0;
    
    	for (i=0; i<stringValue.length; i++) {
    		var ch = stringValue.charAt(i);
    		if(escape(ch).length > 4) {
    			nbytes += 2;
    		} else if (ch == '\n') {
    			if (stringValue.charAt(i-1) != '\r') {
    				nbytes += 1;
    			}
    		} else if (ch == '<' || ch == '>') {
    			nbytes += 4;
    		} else {
    			nbytes += 1;
    		}
    	}	

    	return (nbytes <= (maxLength));    
    	        
    }
    this.validateObjectArray.push(validateObject);
}


/**
 * 값의 길이가 minLength보다 크거나 같은지 검사
 * 
 * @param {string} identifier id 또는 name
 * @param {int} minLength 체크값
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부
 */
nv.Validator.prototype.checkMinLength = function(identifier, minLength, errorMessage, focusFlag) {
    var checkElement = this.getElement(identifier); 
    var validateObject = new this.ValidateObject(identifier, errorMessage, focusFlag);
    validateObject.validate = function() {
        
    	var stringValue = checkElement.value;
    	
    	var nbytes = 0;
    	for (i=0; i<stringValue.length; i++) {
    		var ch = stringValue.charAt(i);
    		if(escape(ch).length > 4) {
    			nbytes += 2;
    		} else if (ch == '\n') {
    			if (stringValue.charAt(i-1) != '\r') {
    				nbytes += 1;
    			}
    		} else if (ch == '<' || ch == '>') {
    			nbytes += 4;
    		} else {
    			nbytes += 1;
    		}
    	}
	
    	return (nbytes >= (minLength*2));        
        
    }
    this.validateObjectArray.push(validateObject);
}

/**
 * 값의 바이트 길이가 maxLength보다 작거나 같은지 검사
 * 
 * @param {string} identifier id 또는 name
 * @param {int} maxLength 체크값
 * @param {int} kbyte 한글바이트수
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부
 */
nv.Validator.prototype.checkMaxLengthByte = function(identifier, maxLength, kbyte, errorMessage, focusFlag) {
    var checkElement = this.getElement(identifier); 
    var validateObject = new this.ValidateObject(identifier, errorMessage, focusFlag);
    validateObject.validate = function() {
        var stringValue = checkElement.value;
        if(!kbyte) kbyte = 2; 
        var nbytes = stringValue.length + ((escape(stringValue)+"%u").match(/%u/g).length)*(kbyte-1) - 1
        return nbytes <= maxLength;
    }
    this.validateObjectArray.push(validateObject);
}

/**
 * 값이 정규표현식에 해당하는 지 검사
 * 
 * @param {string} identifier id 또는 name
 * @param {string} regex 정규표현식
 * @param {boolean} includeFlag 정규표현식 해당여부 포함되어야할때 true
 * @param {boolean} focusFlag 포커스여부
 */
nv.Validator.prototype.checkRegex = function(identifier, regex, includeFlag, errorMessage, focusFlag) {
    var checkElement = this.getElement(identifier); 
    var validateObject = new this.ValidateObject(identifier, errorMessage, focusFlag);
    validateObject.validate = function() {
        var str = checkElement.value;
        if(str.length == 0) return true;
        if(includeFlag) return str.search(regex) != -1;
        else return str.search(regex) == -1;
    }
    this.validateObjectArray.push(validateObject);
}

/**
 * 값이 알파벳과 0~9사이의 숫자만 포함하는 지 검사
 * 
 * @param {string} identifier id 또는 name
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부
 */
nv.Validator.prototype.checkAlphaNum = function(identifier, errorMessage, focusFlag) {
    this.checkRegex(identifier, /^[a-zA-Z0-9]+$/, true, errorMessage, focusFlag);
}

/**
 * 값이 0~9 사이의 문자만 포함하는 지 검사
 * 
 * @param {string} identifier id 또는 name
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부
 */
nv.Validator.prototype.checkOnlyNumber = function(identifier, errorMessage, focusFlag) {
    this.checkRegex(identifier, /^[0-9]+$/, true, errorMessage, focusFlag);
}

/**
 * 값이 올바른 이메일 주소인지 검사
 * 
 * @param {string} identifier id 또는 name
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부 
 */
nv.Validator.prototype.checkEmail = function(identifier, errorMessage, focusFlag) {
    this.checkRegex(identifier, /^((\w|[\-\.])+)@((\w|[\-\.])+)\.([A-Za-z]+)$/, true, errorMessage, focusFlag);
}

/**
 * 올바른 주소인지 검사
 * 
 * @param {string} identifier id 또는 name
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부
 */
nv.Validator.prototype.checkUrl = function(identifier, errorMessage, focusFlag) {
    this.checkRegex(identifier, /^(?:(?:ftp|https?):\/\/)?(?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)+(?:com|edu|biz|org|gov|int|info|mil|net|name|museum|coop|aero|[a-z][a-z])\b(?:\d+)?(?:\/[^;"'<>()\[\]{}\s\x7f-\xff]*(?:[.,?]+[^;"'<>()\[\]{}\s\x7f-\xff]+)*)?/, true, errorMessage, focusFlag);
}

/**
 * 특수문자 검사
 * 
 * @param {string} identifier id 또는 name
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부 
 */
nv.Validator.prototype.checkSpecialChar = function(identifier, errorMessage, focusFlag) {
    this.checkRegex(identifier, /[~!@\#$%^&*\()\-=+_']/, false, errorMessage, focusFlag);
}

/**
 * 공백 검사
 *  
 * @param {string} identifier id 또는 name
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부 
 */
nv.Validator.prototype.checkWhiteSpace = function(identifier, errorMessage, focusFlag) {
    this.checkRegex(identifier, /\s/g, false, errorMessage, focusFlag);
}

/**
 * <select>에서 선택한 옵션의 인덱스가 firstIdx보다 크거나 같은 지 검사한다.
 * 
 * @param {string} identifier id 또는 name
 * @param {int} firstIdx 옵션인덱스
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부
 */
nv.Validator.prototype.checkSelected = function(identifier, firstIdx, errorMessage, focusFlag) {
    var checkElement = this.getElement(identifier);
    var validateObject = new this.ValidateObject(identifier, errorMessage, focusFlag);
    validateObject.validate = function() {
        var idx = checkElement.selectedIndex;
        return idx >= firstIdx;
    }
    this.validateObjectArray.push(validateObject);
}

/**
 * checkbox나 radio 입력 요소가 최소한 1개 이상 선택됐는지 검사
 * 
 * @param {string} identifier id 또는 name
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부
 */
nv.Validator.prototype.checkAtLeastOneChecked = function(identifier, errorMessage, focusFlag) {
    var validateObject = new this.ValidateObject(null, errorMessage, false);
    validateObject.validate = function() {
        var ele = document.getElementsByName(identifier);
        for (var idxe = 0 ; idxe < ele.length ; idxe++) {
            if (ele[idxe].checked == true) return true;
        }
        return false;
    }
    this.validateObjectArray.push(validateObject);
}

/**
 * 특정 문자열이 포함되었는지 검사
 * 
 * @param {string} identifier id 또는 name
 * @param {string} checkContainText 포함 문자열
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부
 */
nv.Validator.prototype.checkContains = function(identifier, checkContainText, errorMessage, focusFlag) {
    var checkElement = this.getElement(identifier); 
    var validateObject = new this.ValidateObject(identifier, errorMessage, false);
    validateObject.validate = function() {
        return checkElement.value.indexOf(checkContainText) == -1;
    }
    this.validateObjectArray.push(validateObject);
}    

/**
 * 값이 알파벳과 0~9사이의 숫자만 포함하는 지 검사
 * 
 * @param {string} identifier id 또는 name
 * @param {string} errorMessage 에러메시지
 * @param {boolean} focusFlag 포커스여부
 */
nv.Validator.prototype.checkAlphaNumBlank = function(identifier, errorMessage, focusFlag) {
    this.checkRegex(identifier, /^[a-zA-Z0-9\s]+$/, true, errorMessage, focusFlag);
}



// ------------------------------------------------------------------------------------------------
// - 폼 요소 관련 기능
// ------------------------------------------------------------------------------------------------
nv.Form = {};

/**
 * Form 모든 파라메터 값을 가져온다.
 * Ajax로 form.submit() 효과를 표현하고자 할 경우
 * 
 * @param {form docForm} Form 객체
 */
nv.Form.getFormQueryString = function(docForm){

	if (docForm == null) 	return null;
	var submitContent = '';
	var formElem;
	for (i = 0; i < docForm.elements.length; i++) {

		formElem = docForm.elements[i];

		switch (formElem.type) {
			case 'text':
			case 'hidden':
			case 'password':
			case 'select-one':
				submitContent += formElem.name + '=' + encodeURIComponent(formElem.value) + '&'
				break;
		    case 'textarea':
		        submitContent += formElem.name + '=' + encodeURIComponent(formElem.value) + '&'
			case 'radio': // Radio buttons
				if (formElem.checked) {
					submitContent += formElem.name + '=' + formElem.value + '&'
				}
				break;
			case 'checkbox': // Checkboxes
				if (formElem.checked) {
				
					submitContent += formElem.name + '=' + formElem.value + '&';
				}
				break;
		}
	}
	if (submitContent.length > 0) submitContent = submitContent.substr(0, submitContent.length - 1);
	return submitContent;
}
/**
 * 특정 값을 가지고 있는 셀렉트박스 옵션을 선택
 * 
 * @param {element object} element 엘리먼트 객체
 * @param {string} value 셀렉트 옵션 값
 */
nv.Form.setSelectBoxValue = function(element, value) {
    if(!element) return;
    for(var i=0; i<element.options.length; i++) {
        if(element.options[i].value == value) {
            element.options[i].selected = true;
            return;
        }
    }
}
/**
 * 특정 값을 가지고 있는 라디오박스 옵션을 선택
 * 
 * @param {element object} element 엘리먼트 객체
 * @param {string} value 옵션 값
 */
nv.Form.setRadioBoxValue = function(element, value) {
    
    if (!element) return;
    
    for(var i=0; i<element.length; i++) {
        if(element[i].value == value) {
            element[i].checked = true;
            return;
        }
    }    
}
/**
 * 체크박스 모두선택, 모두해제
 *
 * @param {element object} element 체크박스 엘리먼트 배열
 * @param {boolean} checkFlag true(모두선택)/false(모두해제)
 */
nv.Form.checkAllCheckBox = function(objName, checkFlag) {
    var objArray = document.getElementsByName(objName)
    for(i=0; i<objArray.length; i++) {
        objArray[i].checked = checkFlag;
    }
}
 
/**
 * 값이 선택되었는지 여부
 * 
 * @param {string} objName 엘리먼트 name 값 
 * @return {boolean} 체크여부 
 */
nv.Form.isChecked = function(objName){
    // getElementsByName 은 배열로 return 함 
    var obj = document.getElementsByName(objName)
    var flagChecked = false;
    for(i=0; i<obj.length; i++) {
        if (obj[i].checked) {
            flagChecked = true;
            break;
        }
    }
    return flagChecked;
}

/**
 * 값을 선택
 * 
 * @param {string} objName 객체 name 값 
 * @param {string} checkValue 체크할 값
 */     
nv.Form.setChecked = function(objName, checkValue) {
    // getElementsByName 은 배열로 return 함 
    var obj = document.getElementsByName(objName)
    for(i=0; i<obj.length; i++) {
        if (obj[i].value == checkValue) {
            obj[i].checked = true;
            break;
        }
    }
}

/**
 * disable 처리
 * @param {string} objName 객체 name 값
 * @param {boolean} diabledValue true 또는 false 
 */  
nv.Form.setDisabled = function(objName, diabledValue) {
    // getElementsByName 은 배열로 return 함 
    var obj = document.getElementsByName(objName)
    for(i=0; i<obj.length; i++) {
        obj[i].disabled = diabledValue;
    }        
}

/**
 * 체크된 값을 반환한다.
 * @param {string} objName 객체명
 * @return {string} 체크된 엘리먼트 value
 */
nv.Form.getCheckedValue = function(objName) {
    var obj = document.getElementsByName(objName)
    for (i=0; i<obj.length; i++) {
        if (obj[i].checked) {
            return obj[i].value;
            break;
        }
    }
}





// ------------------------------------------------------------------------------------------------
// - 문자 관련 기능
// ------------------------------------------------------------------------------------------------
nv.Str = {};

/**
 * 문자열 trim 처리
 * 
 * @param {string} str 문자열
 * @return {string} 결과 문자열
 */
nv.Str.trim = function(str) {
    return str.replace(/^\s\s*/, "").replace(/\s\s*$/, "");
}

/**
 * 문자열 교체
 * 
 * @param {string} str 문자열
 * @param {string} searchStr 검색문자열
 * @param {string} replaceStr 교체문자열
 * @return {string} 결과 문자열
 */
nv.Str.replaceAll = function(str, searchStr, replaceStr) {
    return str.replace(new RegExp(searchStr, "g"), replaceStr);
}

/**
 * 문자열을 정한 길이만큼 자른다.
 * 
 * @param {string} str 문자열
 * @param {int} len 문자열길이
 * @param {string} ellipsis 말줄임표
 * @return {string} 자른 문자열
 */
nv.Str.cutString = function(str, len, ellipsis) {
    ellipsis = ellipsis ? ellipsis : "..";
    if(str.length > len) return str.substring(0, len) + ellipsis;
    else return str;
}

/**
 * HTML 태그 제거
 * 
 * @param {string} str 문자열
 * @return {string} 결과 문자열
 */
nv.Str.removeHTMLTags = function(str) {
    str = str.replace(/&(lt|gt);/g, function (strMatch, p1){return (p1 == "lt") ? "<" : ">";});
    return str.replace(/<\/?[^>]+(>|$)/g, "");
}

/**
 * 특수문자 제거
 * 
 * @param {string} str 문자열
 * @return {string} 결과 문자열
 */
nv.Str.removeSpecialChar = function(str) {
    return str.replace(/[~!@\#$%^&Г*\()\\<'>\[\]\-=+_'{};:`\".?\/]/gi, "");
}

/**
 * 숫자여부 확인
 * @param {string} str 문자열
 * @return {boolean} 결과
 */
nv.Str.isNumeric=function(str) {
        
   if(str.length == 0) return true;
   return str.search(/^[0-9]+$/) != -1;
    
}

nv.Str.isAlphaNum=function(str) {
   if(str.length == 0) return true;
   return str.search(/^[a-zA-Z0-9]+$/) != -1;
}

nv.Str.isProfile=function(str) {
   if(str.length == 0) return true;
   return str.search(/^(\s|[a-zA-Z0-9])+$/) != -1;
}

nv.Str.isEmail=function(str) {
   if(str.length == 0) return true;
   return str.search(/^((\w|[\-\.])+)@((\w|[\-\.])+)\.([A-Za-z]+)$/) != -1;
}

nv.Str.getLength=function(str) {

    	var stringValue = str;
    	
    	var nbytes = 0;
    
    	for (i=0; i<stringValue.length; i++) {
    		var ch = stringValue.charAt(i);
    		if(escape(ch).length > 4) {
    			nbytes += 2;
    		} else if (ch == '\n') {
    			if (stringValue.charAt(i-1) != '\r') {
    				nbytes += 1;
    			}
    		} else if (ch == '<' || ch == '>') {
    			nbytes += 4;
    		} else {
    			nbytes += 1;
    		}
    	}	

    	return nbytes;    
}


// ------------------------------------------------------------------------------------------------
// - 숫자 관련 기능
// ------------------------------------------------------------------------------------------------
nv.Num = {};

/**
 * 파일 크기의 단위를 변경
 * 
 * @param {int} fileSize 파일사이즈
 * @return {string} 변경된 파일사이즈
 */
nv.Num.convertFileSize = function(fileSize) {
    fileSize = parseInt(fileSize);
    var convertedSize = 0;
    if((1024*1024*1024) < fileSize)
       convertedSize = Math.floor((fileSize/1024/1024/1024)*100)/100 + "GB";
    else if((1024*1024) < fileSize)
       convertedSize = Math.floor((fileSize/1024/1024)*100)/100 + "MB";
    else if(1024 < fileSize)
       convertedSize = Math.floor((fileSize/1024)*100)/100 + "KB";
    else
       convertedSize = fileSize + "Byte";
    return convertedSize;
}

/**
 * 세자리수에 comma(,) 적용
 * 
 * @param {string} num 변경할 숫자
 * @return {string} 변경된 문자
 */
nv.Num.setDigitComma = function(num) {
    return num.toString().replace(/(\d)(?=(?:\d{3})+(?!\d))/g, "$1,"); 
}





// ------------------------------------------------------------------------------------------------
// - 날짜 관련 기능
// ------------------------------------------------------------------------------------------------
nv.Dt = {};

/**
 * 월의 1일의 요일을 획득
 * 
 * @param {int} year 년
 * @param {int} month 월
 * @return {int} 0:일요일 ~ 6:토요일
 */
nv.Dt.getFirstDay = function(year, month) {
    return new Date(year, month-1, 1).getDay();
}

/**
 * 월의 마지막 일을 획득
 * 
 * @param {int} year 년
 * @param {int} month 월
 * @return {int} 해당 월의 마지막 일
 */
nv.Dt.getLastDate = function(year, month) {
    var date = new Date(year, month, 1);
    date.setDate(0);
    return date.getDate();
}

// a global month names array
var gsMonthNames = new Array(
    'Jan',
    'Feb',
    'Mar',
    'Apr',
    'May',
    'Jun',
    'Jul',
    'Aug',
    'Sep',
    'Oct',
    'Nov',
    'Dec'
);
 
// a global day names array
var gsDayNames = new Array(
    'Sun',
    'Mon',
    'Tuey',
    'Wed',
    'Thu',
    'Fri',
    'Sat'
);

// the date format prototype
Date.prototype.format = function(f)
{
    if (!this.valueOf())
        return '&nbsp;';
 
    var d = this;
 
    return f.replace(/(yyyy|mmmm|mmm|mm|dddd|ddd|dd|hh|nn|ss|a\/p)/gi,

        function($1)
        {
            switch ($1)
            {
            case 'yyyy': return d.getFullYear();
            case 'mmmm': return gsMonthNames[d.getMonth()];
            case 'mmm':  return gsMonthNames[d.getMonth()].substr(0, 3);
            case 'MM':   return (d.getMonth() + 1).zf(2);
            case 'dddd': return gsDayNames[d.getDay()];
            case 'ddd':  return gsDayNames[d.getDay()].substr(0, 3);
            case 'dd':   return d.getDate().zf(2);
            case 'hh':   return ((h = d.getHours() % 12) ? h : 12).zf(2);
            case 'nn':   return d.getMinutes().zf(2);
            case 'ss':   return d.getSeconds().zf(2);
            case 'a/p':  return d.getHours() < 12 ? 'a' : 'p';
            }
        }  
    );
}

// Zero-Fill
String.prototype.zf = function(l) { return '0'.string(l - this.length) + this; }

//As you can see, it depends on the string prototype, an VB-like string concatenator:

// VB-like string
String.prototype.string = function(l) { var s = '', i = 0; while (i++ < l) { s += this; } return s; }

/*
Just bear in mind there's no check for the l (length) parameter, so you must always provide a number, and finally, you must create a number prototype for it (kind of an override) in order to use it directly on numbers:
*/
Number.prototype.zf = function(l) { return this.toString().zf(l); }

// ------------------------------------------------------------------------------------------------
// - 이미지 관련 기능
// ------------------------------------------------------------------------------------------------
nv.Img = {};

/**
 * 이미지의 가로, 세로와 리사이즈할 가로 세로를 받아
 * 계산된 가로 세로 사이즈를 획득
 * 
 * @param {int} imgWidth 이미지 가로 사이즈
 * @param {int} imgWidth 이미지 세로 사이즈
 * @param {int} maxWidth 최대 가로 사이즈
 * @param {int} maxHeight 최대 세로 사이즈
 * @return {json object} 리사이즈된 가로 세로 JSON 객체
 */
nv.Img.getResizeWH = function(imgWidth, imgHeight, maxWidth, maxHeight) {
    var width = imgWidth;
    var height = imgHeight;
    if(maxWidth && imgWidth > maxWidth) {
        var widthRatio = maxWidth/imgWidth;
        width = imgWidth * widthRatio;
        height = imgHeight * widthRatio;
    }
    if(maxHeight && height > maxHeight) {
        var heightRatio = maxHeight/height;
        width = width * heightRatio;
        height = height * heightRatio;
    }

    return { "w" : width, "h" : height };
}

/**
 * 특정 엘리먼트 내의 이미지를 리사이징
 * 
 * @param {element object} element 엘리먼트 객체
 * @param {int} maxWidth 가로 사이즈 제한
 * @param {int} maxHeight 세로 사이즈 제한
 * @param {boolean} cursorFlag 마우스온 커서표시 여부
 * @param {string} title 마우스온 팝업 텍스트
 */
nv.Img.resizeImages = function(element, maxWidth, maxHeight, cursorFlag, title) {
    if(!element) return;
    var imgList = element.getElementsByTagName("img");
    for(var i=0; i<imgList.length; i++) {
        var imgObj = imgList[i];
        var imgWidth = imgObj.width;
        var imgHeight = imgObj.height;
    
        var resizeWH = this.getResizeWH(imgWidth, imgHeight, maxWidth, maxHeight);
        imgObj.style.width = resizeWH.w + "px";
        imgObj.style.height = resizeWH.h + "px";
        
        imgObj.setAttribute("originalWidth", imgWidth);
        imgObj.setAttribute("originalHeight", imgHeight);
        if(title) imgObj.setAttribute("title", title);
        if(cursorFlag) imgObj.style.cursor = "pointer";
    }
}





// ------------------------------------------------------------------------------------------------
// - 쿠키 관련 기능
// ------------------------------------------------------------------------------------------------
nv.Cookie = {};

/**
 * 쿠키 생성
 * 
 * @param {string} name 쿠키명
 * @param {string} value 쿠키값
 * @param {string} expires 유효일
 * @param {string} path
 * @param {string} domain
 * @param {string} secure
 */
nv.Cookie.setCookie = function(name, value, expires, path, domain, secure) {
    document.cookie = name + "=" + escape(value) +
        ((expires) ? "; expires=" + expires.toGMTString() : "") +
        ((path) ? "; path=" + path : "") +
        ((domain) ? "; domain=" + domain : "") +
        ((secure) ? "; secure" : "");
}

/**
 * 쿠키 조회
 * 
 * @param {string} name 쿠키명
 * @return
 */
nv.Cookie.getCookie = function(name) {
    var dc = document.cookie;
    var prefix = name + "=";
    var begin = dc.indexOf("; " + prefix);
    if (begin == -1) {
        begin = dc.indexOf(prefix);
        if (begin != 0) return null;
    } else {
        begin += 2;
    }
    var end = document.cookie.indexOf(";", begin);
    if (end == -1) {
        end = dc.length;
    }
    return unescape(dc.substring(begin + prefix.length, end));
}

/**
 * 쿠키 삭제
 * 
 * @param {string} name 쿠키명
 * @param {string} path
 * @param {string} domain
 */
nv.Cookie.deleteCookie = function(name, path, domain) {
    if(this.getCookie(name)) {
        document.cookie = name + "=" + 
                          ((path) ? "; path=" + path : "") +
                          ((domain) ? "; domain=" + domain : "") +
                          "; expires=Thu, 01-Jan-70 00:00:01 GMT";
    }
}