/**
 * ThinkNet JavaScript Framework
 * 
 * @author ThinkNet Co., Ltd.
 * @version 0.3.1
 */


/**
 * $: Extended document.getElementById function, simplified from prototype.js
 * 
 * @param {Object} element = String, Object or array of both
 */
function $(element) {
    if (arguments.length > 1) {
        for (var i = 0, elements = [], length = arguments.length; i < length; i++) {
            elements.push($(arguments[i]));
        }
        return elements;
    }
    if (typeof element == 'string') {
        element = document.getElementById(element);
    }
    return element;
}

( 
    function () {
        
        if(!!!window['tn']) {
            window['tn'] = {};
        }

        var Util = function () {
            var __isIE = function () {
                if (window.addEventListener) {
                    return false;
                } else {
                    return true;
                }
            }();
            
            return {
                
                version: '0.2',
                
                isIE: __isIE,
                
                /**
                 * tieEvent: Attach event to element with "this" assignment
                 * 
                 * @param {Object} el = Element to attach event to
                 * @param {String} ev = Event name (exclude 'on')
                 * @param {Object} o = Object to be "this" when called fn
                 * @param {Function} fn = Function to call as event handler
                 */
                tieEvent: function (el, ev, o, fn) {
                    function wrapfn(o, fn) {
                        return function (e) {
                            fn.call(o, e); 
                        };
                    }
                    
                    if(__isIE) {
                        el.attachEvent("on" + ev, wrapfn(o, fn));   
                    } else {
                        el.addEventListener(ev, wrapfn(o, fn), false); 
                    }      
                },
                
                /**
                 * stopEvent: Stop event propagation and default event handler
                 * 
                 * @param {Object} e = Event object
                 */
                stopEvent: function (e) {
                    if(e.stopPropagation) {
                        e.preventDefault();
                        e.stopPropagation();
                    } else {
                        e.returnValue = false;
                        e.cancelBubble = true;
                    }
                },

                /**
                 * setOpacity: Set element opacity (runtimely created)
                 * 
                 * @param {Object} el = Element to set opacity
                 * @param {Number} opc = Opacity value
                 */
                setOpacity: function () {
                    if(__isIE) {
                        return function(el, opc){
                            el.style.filter = 'alpha(opacity=' + Math.round(opc*100) +', style=0, enabled=1)';
                        };  
                    } else {
                        return function(el, opc){
                            el.style.MozOpacity = opc;
                            el.style.opacity    = opc;
                        };  
                    }
                }(),

                /**
                 * setStyles: Set element style with given style object
                 * 
                 * @param {Object} el = Element to be set
                 * @param {Object} styleObj = Style object
                 */
                setStyles: function (el, styleObj) {
                    if(!el) return;
                    
                    var s = el.style;
                    
                    for(var i in styleObj) {
                        if( i == "opacity" ){			
                            Util.setOpacity(el, styleObj[i]);
                        } else {
                            s[i] = styleObj[i];
                        }
                    }
                    
                    return el;
                },
                
                /**
                 * setInterval: Set closure function as interval
                 * 
                 * @param {Object} o = Object to be "this" when called fn
                 * @param {Function} fn = Function to call as event handler
                 * @param {Integer} interval = Interval in milliseconds
                 */
                setInterval: function (o, fn, interval) {
                    function wrapfn(o, fn) {
                        return function () {
                            fn.call(o);
                        }
                    }
                    return window.setInterval(wrapfn(o, fn), interval);
                },

                /**
                 * toFixed: Fixed Decimal Ex. toFixed(100.045772900230924239, 8) => 100.04577290
                 * 
                 * @param {Decimal} num = Decimal Number
                 * @param {Number} pre = Number of Decimal
                 */
                toFixed: function (num, pre) {
                    function toFixed(numb, pre){
                        numb *= Math.pow(10, pre);
                        numb = (Math.round(numb, pre) + (((numb - Math.round(numb, pre))>=0.5)?1:0)) / Math.pow(10, pre);
                        return numb.toFixed(pre);
                    }
                    
                    return toFixed(num, pre);
                },
                
                /**
                 * Right: Set String Right Ex. str = "Hello World" => right(str, 3) >> "rld"
                 * @author B. Devington Rayan (http://www.devx.com/tips/Tip/15222).
                 * @param {String} str  = String Or Word
                 * @param {Number} n    = Number Of Character
                 */
                right: function (str, n) {
                    if (n <= 0)
                       return "";
                    else if (n > String(str).length)
                       return str;
                    else {
                       var iLen = String(str).length;
                       return String(str).substring(iLen, iLen - n);
                    }
                },
                /**
                 * Left: Set String Left Ex. str = "Hello World" => left(str, 3) >> "Hel"
                 * @author B. Devington Rayan (http://www.devx.com/tips/Tip/15222).
                 * @param {String} str  = String Or Word
                 * @param {Number} n    = Number Of Character
                 */
                left: function (str, n) {
                    if (n <= 0)
                        return "";
                    else if (n > String(str).length)
                        return str;
                    else
                        return String(str).substring(0,n);
                }
            };
        }();
        
        var Event = function () {
            return {
                version: '0.1.1',
                
                /**
                 * addEventListener: Attach event to any object
                 * 
                 * @param {Object} obj = Object to be binded with event
                 * @param {String} ev = Event name
                 * @param {Object} o = Object to be "this" when called fn
                 * @param {Function} fn = Function to be called as event handler
                 * @param {AnyType} p = Optional parameter
                 */
                addListener: function (obj, ev, o, fn, p) {
                    if(!!!obj['listeners']) {
                        obj['listeners'] = {};
                    }
                    if(!!!obj.listeners[ev]) {
                        obj.listeners[ev] = [];
                    }
                    
                    var index = obj.listeners[ev].length;
                    obj.listeners[ev][index] = [o, fn, p];
                    
                    return index;
                },
                
                /**
                 * fire: Trigger event 
                 * 
                 * All event listeners will be executed when call this method
                 * 
                 * @param {Object} obj = Object binded with event
                 * @param {String} ev = Event name
                 * @param {AnyType} p = Optional parameter
                 */
                fire: function (obj, ev, p) {
                    if(!!obj['listeners'] && !!obj['listeners'][ev]) {
                        for(var i = 0; i < obj['listeners'][ev].length; i++) {
                            obj['listeners'][ev][i][1].call(obj['listeners'][ev][i][0], p, obj['listeners'][ev][i][2]);
                        }
                    }
                }
                
            };
        }();
        
        var Map = function() {
            return {
                version: '0.1',
                
                /**
                 * LatLng: Class for coordinate (latitude and longitude)
                 * 
                 * @param {Decimal} lat = Latitude
                 * @param {Decimal} lng = Longitude
                 */
                LatLng: function (lat, lng) {
                    this.lat = lat || 0;
                    this.lng = lng || 0;
                },
                
                /**
                 * Point: Class for point (x, y in pixel)
                 * 
                 * @param {Interger} x = x
                 * @param {Interger} y = y
                 */
                Point: function (x, y) {
                    this.x = x || 0;
                    this.y = y || 0;
                },
                
                /**
                 * Size: Class for Map Size (w, h)
                 * 
                 * @param {Interger} w = width
                 * @param {Interger} h = height
                 */
                Size: function (w, h) {
                    this.w = w || 0;
                    this.h = h || 0;
                },

                /**
                 * Border: Class for Map Boundary (nt, et, st, wt)
                 * 
                 * @param {Lat} nt = LatTop
                 * @param {Lng} et = LngRight
                 * @param {Lat} st = LatBottom
                 * @param {Lng} wt = LngLeft
                 */
                Boundary: function (nt, et, st, wt) {
                    this.nt = nt || 0;
                    this.et = et || 0;
                    this.st = st || 0;
                    this.wt = wt || 0;
                }, 
                
                /**
                 * Block: Class for Map Block (row, col)
                 * 
                 * @param {number} row = Row Block
                 * @param {number} col = Col Block
                 */
                Block: function (row, col) {
                    this.row = row || 0;
                    this.col = col || 0;
                }
            };
        }();
        
        tn['util'] = Util;
        tn['event'] = Event;
        tn['map'] = Map;
    }
)();