/*
	sky.base.js
	2007-03-30 ~ 2007-05-25

	Seo, Jaehan <daddyofsky@gmail.com>

	Referred to
		ui javascript framework - gony <gonom9@gmail.com>
		Prototype javascript framework - Sam Stephenson <sam@conio.net>
		Swaf javascript framework - reizes <reizes@nate.com>
*/

// Class //////////////////////////////////////////////////////////////////////

	var Class = function() {
		var obj = function() {
			if (this.init) this.init.apply(this, arguments);
		}
		if (arguments[0]) Class.extend(obj.prototype, arguments[0]);
		return obj;
	}

	Class.extend = function(obj) {
		for(var i=1; i<arguments.length; i++) {
			if (arguments[i]) {
				for (var x in arguments[i]) {
					obj[x] = arguments[i][x];
				}
			}
		}
		return obj;
	}

// Extend Function ////////////////////////////////////////////////////////////

	Class.extend(Function.prototype, {
		bind : function(obj) {
			var func = this;
            var arg = $a(arguments); arg.shift();
			return function() {
				return func.apply(obj, arg.concat($a(arguments)));
			}
		},
		bindForEvent : function(obj) {
			var func = this;
			return function(e) {
				return func.call(obj, e);
			}
		}
	});

// Extend Array ///////////////////////////////////////////////////////////////

	Class.extend(Array.prototype, {
		exists : function(value) {
			for (var i=0; i<this.length; i++) {
				if (this[i] == value) return true;
			}
			return false;
		},
		search : function(value) {
			for (var i=0; i<this.length; i++) {
				if (this[i] == value) return i;
			}
			return -1;
		},
		copy : function(obj) {
			if (typeof obj == 'undefined') obj = this;
            if (typeof obj.length == 'undefined') obj = [obj];
			var ret = [];
			for (var i=0; i<obj.length; i++) {
				ret.push(obj[i]);
			}
			return ret;
		},
		filter : function(func, applyResult) {
			var ret = [];
			if (typeof func == 'boolean') {
				for (var i=0; i<this.length; i++) {
					if (!this[i] == !func) ret.push(this[i]);
				}
			} else if (typeof func == 'function') {
				if (applyResult) {
					for (var i=0; i<this.length; i++) {
						var result = func(this[i], i);
						if (result !== false) ret.push(result);
					}
				} else {
					for (var i=0; i<this.length; i++) {
						if (func(this[i], i)) ret.push(this[i]);
					}
				}
			} else {
				ret = this;
			}
			return ret;
		},
		each : function(func) {
			if (typeof func == 'function') {
				for (var i=0; i<this.length; i++) {
					this[i] = func(this[i], i);
				}
			} else {
				for (var i=0; i<this.length; i++) {
					this[i] = func;
				}
			}
			return this;
		},
        merge : function(obj) {
            for (var i=0; i<obj.length; i++) {
                if (!this.exists(obj[i])) {
                    this.push(obj[i]);
                }
            }
            return this;
        },
        intersect : function(obj) {
            var ret = [];
            for (var i=0; i<obj.length; i++) {
                if (this.exists(obj[i])) {
                    ret.push(obj[i]);
                }
            }
            return ret;
        },
        diff : function(obj) {
            var ret = [];
            for (var i=0; i<obj.length; i++) {
                if (!this.exists(obj[i])) {
                    ret.push(obj[i]);
                }
            }
            return ret;
        }
	});
	Array.prototype.has = Array.prototype.exists;

// Extend String //////////////////////////////////////////////////////////////

	Class.extend(String.prototype, {
		trim : function() {
			return this.replace(/^\s+/, '').replace(/\s+$/, '');
		},
		stripTags : function() {
			return this.replace(/<\/?[^>]+>/gi, '');
		},
		validHTML : function() {
			var div = document.createElement('div');
			div.innerHTML = this;
			return div.innerHTML;
		},
		escapeHTML: function() {
			var div = document.createElement('div');
			var text = document.createTextNode(this);
			div.appendChild(text);
			return div.innerHTML;
		},
		unescapeHTML: function() {
			var div = document.createElement('div');
			div.innerHTML = this.stripTags();
			return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
		},
		decodeQuery : function(isUrl) {
			if (isUrl) {
				var tmp = this.substring(this.indexOf('?')+1).match(/^\??(.*)$/)[1].split('&');
			} else {
				var tmp = this.match(/^\??(.*)$/)[1].split('&');
			}
			var ret = {};
			for (var i=0; i<tmp.length; i++) {
				var pair = tmp[i].split('=');
				if (pair[0]) ret[pair[0]] = pair[1];
			}
			return ret;
		},
        encodeQuery : function(param, base) {
            var tmp = [];
            if (param instanceof Array) {
                for (var x=0; x<param.length; x++) {
                    var key = base ? base+'['+x+']' : x;
                    if (typeof param[x] == 'string' || typeof param[x] == 'number') {
                        tmp.push(key+'='+param[x]);
                    } else {
                        tmp.push(this.encodeQuery(param[x], key));
                    }
                }
            } else {
                for (var x in param) {
                    var key = base ? base+'['+x+']' : x;
                    if (typeof param[x] == 'string' || typeof param[x] == 'number') {
                        tmp.push(key+'='+param[x]);
                    } else {
                        tmp.push(this.encodeQuery(param[x], key));
                    }
                }
            }
            return tmp.join('&');
        }
	});
    String.prototype.parseQuery = String.prototype.decodeQuery;

// Event //////////////////////////////////////////////////////////////////////

	var Event = {
		addListener : function(obj, handler, func) {
            obj = $(obj);
			if (!(obj instanceof Array)) obj = [obj];
            for (var i=0; i<obj.length; i++) {
                if (obj[i].addEventListener) {
                    obj[i].addEventListener(handler, func, false);
                } else if(obj[i].attachEvent) {
                    obj[i].attachEvent('on'+handler, func);
                }
            }
		},
		delListener : function(obj, handler, func) {
            obj = $(obj);
			if (!(obj instanceof Array)) obj = [obj];
            for (var i=0; i<obj.length; i++) {
                if (obj[i].removeEventListener) {
                    obj[i].removeEventListener(handler, func, false);
                } else if(obj[i].detachEvent) {
                    obj[i].detachEvent('on'+handler, func);
                }
            }
		},
        stop : function(evt) {
			var e = evt || window.event;
            if (e.preventDefault) {
                e.preventDefault();
                e.stopPropagation();
            } else {
                e.returnValue = false;
                e.cancelBubble = true;
            }
        },
        element : function(evt) {
			var e = evt || window.event;
            return e.currentTarget || e.target || e.srcElement;
        },
        getPosition : function(evt, dx, dy) {
			var e = evt || window.event;
			var b = document.body;
            var pos = {
                x : e.pageX || e.clientX+b.scrollLeft-b.clientLeft,
                y : e.pageY || e.clientY+b.scrollTop-b.clientTop
            }
			if (typeof dx == 'number') pos.x += dx;
			if (typeof dy == 'number') pos.y += dy;
			return pos;
        },
		extend : function(evt) {
            if (typeof evt.initEvent != 'function' && typeof evt.keyCode != 'number') return false;
            if (evt.extended) return evt;
			var e = evt || window.event;
			var b = document.body;
            Class.extend(e, {
				extended : true,
				element  : Element.extend(e.currentTarget || e.target || e.srcElement),
				mouse    : {
					isLeft   : (e.which && e.button==0) || (e.button&1 != 0),
					isMiddle : (e.which && e.button==1) || (e.button&4 != 0),
					isRight  : (e.which && e.button==2) || (e.button&2 != 0)
				},
				key      : {
					isAlt   : e.altKey,
					isCtrl  : e.ctrlKey,
					isShift : e.shiftKey,
					isUp    : [38,104].exists(e.keyCode),
					isDown  : [40,98].exists(e.keyCode),
					isLeft  : [37,100].exists(e.keyCode),
					isRight : [39,102].exists(e.keyCode),
					isEnter : (e.keyCode==13),
					isTab : (e.keyCode==9)
				},
				stop     : function() {
					if (this.preventDefault) {
						this.preventDefault();
						this.stopPropagation();
					} else {
						this.returnValue = false;
						this.cancelBubble = true;
					}
				}
			});

            // Opera safe
            if (typeof e.x == 'undefined') {
                Class.extend(e, {
                    x : e.pageX || e.clientX+b.scrollLeft-b.clientLeft,
                    y : e.pageY || e.clientY+b.scrollTop-b.clientTop
                });
            }
			return e;
		}
	}
    Event.pos = Event.getPosition;

// Element ////////////////////////////////////////////////////////////////////

	var Element = {
        show : function(obj, display) {
            if (display != 'block' && display != 'inline') display = '';
            $(obj).style.display = display;
			if (obj.blocker) this.updateBlocker(obj);
        },
		hide : function(obj) {
			$(obj).style.display = 'none';
			if (obj.blocker) this.updateBlocker(obj);
        },
        toggle : function(obj, display) {
            this.visible(obj) ? this.hide(obj) : this.show(obj, display);
        },
        visible : function(obj) {
            return ($(obj).style.display != 'none');
        },
        getPosition : function(obj, dx, dy) {
			obj = $(obj)
            var x = obj.offsetLeft;
            var y = obj.offsetTop;
            var p = obj.offsetParent;
            while (p && p != document.body) {
                x += p.offsetLeft;
                y += p.offsetTop;
                p = p.offsetParent;
            }
			var pos = { x:x, y:y };
			if (typeof dx == 'number') pos.x += dx;
			if (typeof dy == 'number') pos.y += dy;
			return pos;
        },
        getCenter : function(obj, x, y) {
			var objPos = this.getPosition(obj);
			var objSize = this.getSize(obj);
			var docSize = Util.getClientSize();
			var docScroll = Util.getScrollOffset();
			var x = (typeof x == 'number') ? x : (x === false ? objPos.x : docScroll.x+(docSize.width-objSize.width)/2);
			var y = (typeof y == 'number') ? y : (y === false ? objPos.y : docScroll.y+(docSize.height-objSize.height)/2);
            return { x:x, y:y };            
        },
        setPosition : function(obj, posX, posY) {
			obj = $(obj)
			if (!obj.style.position) obj.style.position = 'absolute';
			if (arguments.length == 2) {
				obj.style.left = (typeof arguments[1].x == 'number') ? arguments[1].x + 'px' : arguments[1].x;
				obj.style.top = (typeof arguments[1].y == 'number') ? arguments[1].y + 'px' : arguments[1].y;
			} else {
				obj.style.left = (typeof posX == 'number') ? posX+'px' : posX;
				obj.style.top = (typeof posY == 'number') ? posY+'px' : posY;
			}
			if (obj.blocker) this.updateBlocker(obj);
        },
        getSize : function(obj) {
			obj = $(obj)
            var w = obj.offsetWidth || obj.scrollWidth;
            var h = obj.offsetHeight || obj.scrollHeight;
            return { width:w, height:h };
        },
        setSize : function(obj, width, height) {
			obj = $(obj)
			if (arguments.length == 2) {
				obj.style.width = (typeof arguments[1].width == 'number') ? arguments[1].width + 'px' : arguments[1].width;
				obj.style.height = (typeof arguments[1].height == 'number') ? arguments[1].height + 'px' : arguments[1].height;
			} else {
				width = parseInt(width, 10) || 0;
				height = parseInt(height, 10) || 0;
				obj.style.width = (typeof width == 'number') ? width + 'px' : width;
				obj.style.height = (typeof height == 'number') ? height + 'px' : height;
			}
			if (obj.blocker) this.updateBlocker(obj);
		},
        getStyle : function(obj, name) {
            return $(obj).style[name];
        },
        setStyle : function(obj, style, value) {
            obj = $(obj);
            if (arguments.length == 3) {
				if (style == 'opacity') {
					if (Util.isIE) {
						obj.style['filter'] = 'alpha(opacity='+ (parseFloat(value)*100) + ')';
					} else {
						obj.style['opacity'] = value;
					}
				} else {
	                obj.style[style] = value;
				}
            } else {
                Class.extend(obj.style, style);
            }
		},
        classExists : function(obj, className) {
            return $(obj).className.split(/\s+/).exists(className);
        },
        setClass : function(obj, className) {
            $(obj).className = className;
		},
        addClass : function(obj, className) {
            obj = $(obj);
            if (!this.classExists(obj, className)) (obj.className+=' '+className).replace(/^\s+/,'');
		},
        delClass : function(obj, className) {
            obj = $(obj);
            obj.className = obj.className.replace(new RegExp('(^|\\s+)'+className+'($|\\s+)','g'),'');
        },
        getRect : function(obj) {
            var p = this.getPosition(obj);
            var s = this.getSize(obj);
            return { left:p.x, top:p.y, right:p.x+s.width, bottom:p.y+s.height };
        },
        hitTest : function(obj, target) {
            var o = this.getRect(obj);
            var t = this.getRect(target);
            return !(o.left > t.right || o.right < t.left || o.top > t.bottom || o.bottom < t.top);
        },
        inTest : function(obj, target) {
            var o = this.getRect(obj);
            var t = this.getRect(target);
            return (o.left >= t.left && o.right <= t.right && o.top >= t.top && o.bottom <= t.bottom);
        },
        addBefore : function(obj, src) {
            obj.parentNode.insertBefore(src, obj);
        },
        addAfter : function(obj, src) {
            if (obj.nextSibling) {
                obj.parentNode.insertBefore(src, obj.nextSibling);
            } else {
                obj.parentNode.appendChild(src);
            }
        },
        clone : function(obj, deep) {
            return obj.cloneNode(deep);
        },
        remove : function(obj) {
            obj.parentNode.removeChild(obj);
        },
		attachBlocker : function(obj, group) {
			if (!Util.isIE) return; // IE only
			if (!obj.blocker) {
				var iframeId = '__blocker_' + (group || 'default');
				var iframe = $(iframeId);
				if (!iframe) {
					iframe = $c('iframe');
					iframe.setAttribute('src', 'about:blank');
					iframe.setAttribute('id', iframeId);
					iframe.setAttribute('frameBorder', '0');
					this.setStyle(iframe, {
						position : 'absolute',
						width : '0px',
						height : '0px',
						filter : 'alpha(opacity=0)'
					});
					document.body.appendChild(iframe);
				}
				obj.blocker = iframe;
			}
		},
		updateBlocker : function(obj) {
			var iframe = obj.blocker;
			var display = this.getStyle(obj, 'display');
			if (display == 'none') {
				this.hide(iframe);
			} else {
				this.show(iframe);
				this.setPosition(iframe, this.getPosition(obj));
				this.setSize(iframe, this.getSize(obj));
				var zIndex = this.getStyle(obj, 'zIndex');
				if (!zIndex) {
					zIndex = 1000;
					this.setStyle(obj, 'zIndex', zIndex)
				}
				this.setStyle(iframe, 'zIndex', zIndex-1);
			}
		},
        extend : function(obj) {
            obj = $(obj);
			if (obj.extended) return obj;
            for (var func in this) {
				if (func == 'extend') continue;
                obj[func] = this[func].bind(this, obj);
            }
            obj.extended = true;
            return obj;
        }
	}
    Element.pos = Element.getPosition;
    Element.moveTo = Element.setPosition;

// Util ///////////////////////////////////////////////////////////////////////

	var Util = {
		// brower 
        isIE : (window.navigator.userAgent.search(/msie/i) != -1),
        isFF : (window.navigator.userAgent.search(/firefox/i) != -1),
        isOpera : (window.navigator.userAgent.search(/opera/i) != -1),
        isSafari : (window.navigator.userAgent.search(/safari/i) != -1),
        userAgent : window.navigator.userAgent,
        appName : (new RegExp('(msie |firefox/|opera/|safari/)([0-9.]+)', 'i')).exec(window.navigator.userAgent)[1].slice(0, -1),
        appVersion : (new RegExp('(msie |firefox/|opera/|safari/)([0-9.]+)', 'i')).exec(window.navigator.userAgent)[2],
		// window, document
        getClientSize : function(win) {
            if (!win) win = self;
            var w = win.innerWidth || win.document.body.clientWidth;
            var h = win.innerHeight || win.document.body.clientHeight;
            return { width:w, height:h };
        },
        getDocSize : function(win) {
            if (!win) win = self;
			var docSize = Element.getSize(win.document.body);
			var w = Math.max(win.document.body.scrollWidth, docSize.width);
            var h = Math.max(win.document.body.scrollHeight, docSize.height);
            return { width:w, height:h };
        },
        getScrollOffset : function(win) {
            if (!win) win = self;
            var x = win.pageXOffset || win.document.body.scrollLeft || 0;
            var y = win.pageYOffset || win.document.body.scrollTop || 0;
            return { x:x, y:y };
        },
		getDocumentWindow : function(doc) {
			return doc.defaultView || doc.parentWindow;
		},
		// iframe
		getIframeDoc : function(iframe) {
			if (iframe.contentWindow) {
				return iframe.contentWindow.document;
			} else if (iframe.contentDocument) {
                return iframe.contentDocument.documentElement;
			} else {
				return null;
			}
		},
		getIframeDocSize : function(iframe) {
			iframe = $(iframe);
			var doc = this.getIframeDoc(iframe);
			var win = this.getDocumentWindow(doc);
			return this.getDocSize(win);
		},
		autoResizeIframe : function(iframe, noWidth, noHeight) {
			iframe = $(iframe);
			var objSize = Element.getSize(iframe);
			var docSize = this.getIframeDocSize(iframe);
			var width = noWidth ? objSize.width : docSize.width;
			var height = noHeight ? objSize.height : docSize.height;
			Element.setSize(iframe, width, height);
		},
        // math
        random : function(min, max) {
            if (typeof min == 'number' && typeof max == 'number') {
                return Math.floor(Math.random() * (max-min) + min);
            } else {
                return Math.floor(Math.random() * 10);
            }
        },
        randomId : function(cipher, prefix) {
            if (typeof cipher != 'number') {
                cipher = 7;
            } else if (cipher > 15) {
                cipher = 15;
            }
            var min = parseInt('100000000000000'.substr(0, cipher), 10);
            var max = parseInt('999999999999999'.substr(0, cipher), 10);
            return (prefix) ? prefix+'_'+Util.random(min, max) : Util.random(min, max);
        },
        // cookie
        getCookie : function(name) {
            var re = new RegExp(name + '=([^;]+)');
            var value = re.exec(document.cookie);
            return (value != null) ? unescape(value[1]) : null;
        },
        setCookie : function(name, value, expire, path, domain) {
            expire = parseInt(expire, 10);
            if (!path) path = '/';
            if (expire) {
                var today = new Date();
                var expiry = new Date(today.getTime() + expire * 1000);
                var cookie = name + '=' + escape(value) + '; expires=' + expiry.toGMTString() + '; path=' + path;
            } else {
                var cookie = name + '=' + escape(value) + '; path=' + path;
            }
            if (domain) cookie += '; domain=' + domain;
            document.cookie = cookie;
        },
        dump : function(obj) {
            if (obj.toString && (typeof obj == 'string' || typeof obj == 'number' || obj instanceof Array)) {
                return obj.toString();
            } else {
                var str = '';
                for (x in obj) {
                    str += x + ' : ' + obj[x] + "\n";
                }
                return str;
            }
        }
    }




// Special functions //////////////////////////////////////////////////////////

	// get element by id
	function $(obj) {
		if (obj instanceof Array) {
			var ret = [];
			for (var i=0; i<obj.length; i++) {
				ret.push((typeof obj[i] == 'string') ? document.getElementById(obj[i]) : obj[i]);
			}
			return ret;
		} else {
			return (typeof obj == 'string') ? document.getElementById(obj) : obj;
		}
	}
	function $$(id, range) {
		var p = /([#]+)/.exec(id);
		if (p[1]) {
			var cipher = p[1].length;
			var pattern = p[1];
		} else{
			var cipher = 1;
			var pattern = '#';
		}
		var zero = pattern.replace(/#/g, '0');
		if (range instanceof Array) {
			var start = range[0];
			var end = range[1] || false;
		} else if (arguments.length == 3) {
			var start = arguments[1];
			var end = arguments[2];
		} else {
			var start = 0;
			var end = range;
		}
		var loop = (end) ? end : Math.pow(10, cipher) - 1;
		var ret = [];
		for (var i=start; i<loop; i++) {
			var el = document.getElementById(id.replace(pattern, (zero+i).slice(-cipher)));
			if (el) {
				ret.push(el);
			} else if (!end && i>0) {
				break;
			}
		}
		return ret;
	}

    // extend
    function $e(obj) {
        if (typeof obj == 'string' || (typeof obj.nodeType == 'number' && obj.nodeType == 1)) {
            obj = Element.extend(obj);
        } else if (typeof obj.initEvent == 'function' || typeof obj.keyCode == 'number') {
            obj = Event.extend(obj);
        } else {
            obj = Class.extend.apply(Class, arguments);
        }
        return obj;
    }

	// array function
	$a = Array.prototype.copy;
	function $array(obj) {
		return (obj instanceof Array) ? obj : [obj];
	}

    // event function
	$l = Event.addListener;
	$lx = Event.delListener;

	// create element
	function $c(tag) {
		return document.createElement(tag);
	}

	// get form
	function $form(name) {
        if (typeof name == 'string') {
    		return document.forms[name] || document.getElementById(name);
        } else {
            return name;
        }
	}

	// get form element value
	function $v(obj) {
		obj = $(obj);
		if (obj.type) {
			var type = obj.type;
		} else if (obj.length) {
			var type = obj[0] ? obj[0].type : false;
		} else {
			var type = false;
		}
		if (!type) return false;

		switch (type.toLowerCase()) {
			case 'radio' :
				if (!obj.length) obj = [obj];
				var value = $a(obj).filter(function(e) { return e.checked ? e.value : false; }, true);
				value = (value.length) ? value[0] : '';
				break;
			case 'checkbox' :
				if (!obj.length) obj = [obj];
				var value = $a(obj).filter(function(e) { return e.checked ? e.value : false; }, true);
				break;
			case 'select-one' :
				var value = $a(obj.options).filter(function(e) { return e.selected ? e.value : false; }, true);
				value = (value.length) ? value[0] : '';
				break;
			case 'select-multiple' :
				var value = $a(obj.options).filter(function(e) { return e.selected ? e.value : false; }, true);
                break;
			default :
				var value = $a(obj).each(function(e) { return e.value; });
				if (value.length == 1) value = value[0];
				break;
		}
		return value;
	}

	// get selected option object
	function $select(obj) {
		obj = $(obj);
		if (typeof obj.options == 'undefined') return false;
		var option = $a(obj.options).filter(function(e) { return e.selected ? e : false; }, true);
		if (obj.type.toLowerCase() == 'select-one') option = (option.length) ? option[0] : false;
		return option;
	}
