﻿//<using>
//  nui/nui.js
//  nui/lang.js
//</using>

/**
 * Prototype classes of NUI
 * Copyright 2007, NetRanking.cn
 */

/**
 * Prototype method of "Object".
 */

/**
 * Walk throught the object's own property. execute an function
 * @method walkObject
 * @param vFunc {function} The function to execute.
 */
//Object.prototype.walkObject = function(vFunc) {
//    for (var name in this) {
//        if (this.hasOwnProperty(name)) {
//            vFunc(name);
//        }
//    }
//};
/**
 * Search the object. Stop seaching if the stop function return true
 * @method searchObject
 * @param vStopFunc {function} The stop function.
 */
//Object.prototype.searchObject = function(vStopFunc) {
//    for (var name in this) {
//        if (this.hasOwnProperty(name)) {
//            if(vStopFunc(name)) {
//                break;
//            }
//        }
//    }
//};
/**
 * Annex another object. e.t. get all the methods and attributes from another object.
 * @method annex
 * @param vObj {object} The object to be annexed.
 */
//Object.prototype.annex = function (vObj) {                                  //!!!!!!! This method should be tested!
//    if(vObj == null) {
//        return;
//    }
//    var self = this;                    // make self to bound to "this"
//    this.walkObject(function(vName) {
//        self[vName] = vObj[vName];
//    });
//    return this;
//};
/**
 * Clone the object     // 注意，该方法在克隆HashTable的时候失效，副本的getValue("key")和原始元素的getValue("key")指向同样的值
 * @method clone
 */
//Object.prototype.clone = function() {
//    function _clone(obj) {
//	    if(obj == null || typeof(obj) != 'object') {
//            return obj;
//        }

//        var retval = new obj.constructor();
//        for(var key in obj) {
//            if (obj.hasOwnProperty(key)) {        // 需要这个if？没有的话会把object.prototype.*都复制一遍
//                retval[key] = _clone(obj[key]);
//            }
//        }

//        return retval;
//    }
//    
//    var newObj = _clone(this);
//    return newObj;
//};
///**
// * Check whether the object containe the same values with vObj.
// * NOTE : "==" means two pointer point to the same object. This method means two pointers point to the different object
// * @method sameAs
// */
//Object.prototype.sameAs = function(vObj) {
//    function _same(objA, objB) {
//        if(objA === null) {
//            return (objB === null);
//        } else if(objB === null) {
//            return false;
//        } else {
//            if(typeof(objA) != "object") {
//                if(typeof(objB) != "object") {
//                    return (objA === objB);
//                } else {
//                    return false;
//                }
//            } else if(typeof(objB) != "object"){
//                return false;
//            } else {
//                for(var keyA in objA) {
//                    if (objA.hasOwnProperty(keyA)) {
//                        if(!_same(objA[keyA], objB[keyA])){
//                            return false;
//                        }
//                    }
//                }
//                for(var keyB in objB) {
//                    if (objB.hasOwnProperty(keyB)) {
//                        if(!_same(objA[keyB], objB[keyB])){
//                            return false;
//                        }
//                    }
//                }
//            }
//        }

//        return true;
//    }
//    
//    return _same(this, vObj);
//};
///**
// * Clone the object
// * @method remove
// * @param vName {string}. The name of the attribute to be removed
// */
//Object.prototype.remove = function(vName) {
//    delete this[vName];
//};
///**
// * Check if object has an attribute that is a certain value
// * @method hasValue
// * @param vValue {any type}. The value
// */
//Object.prototype.hasValue = function(vValue) {
//    var find = false,
//        self = this;
//    self.searchObject(function(vName) {
//        find = (self[vName] === vValue);
//        return find;
//    });
//    return find;
//};

/**
 * Prototype method of "String".
 */
/**
 * Use an object to supplant some substrings of the target string.
 * @method supplant
 * @param vObj {object} The object to supplant the string. The variables of vObj can be {string|number|boolean}.
 * @return {string} The result string
 */
String.prototype.supplant = function (vObj) { 
    var lang = NUI.Lang;
    return this.replace(/\{([^{}]*)\}/g, function (a, b) {
        var r = vObj[b];
        return (lang.isString(r) || lang.isNumber(r) || lang.isBoolean(r)) ? r : a;
    });
};
/**
 * @method trim
 * @return {string} The result string
 */
String.prototype.trim = function () {
    return this.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1");    //this.replace(/(^\s*)|(\s*$)/g, "")
};
/**
 * @method dump
 * @return {string} The result string
 */
String.prototype.dump = function() {
    return this.replace(/\\/g, "\\\\").replace(/\t/g, "\\t").replace(/\r/g, "\\r").replace(/\n/g, "\\n");
};
/**
 * @method map
 * @return {string} The result string
 */
String.prototype.map = function() {
    var retval = this;
    for (var i = 0; i < arguments.length; i++)
        retval = retval.replace(new RegExp("%" + (i + 1), "gm"), arguments[i]);
    return retval;
};
/**
 * @method controlId, controlIdStr, controlName, rootName, createControl
 * @return {string} The result string
 */
String.prototype.controlId = function () {
    var t = this.lastIndexOf("_");
    return parseInt(this.substr(t + 1));
};
String.prototype.controlIdStr = function () {
    var t = this.lastIndexOf("_");
    return this.substr(t + 1);
};
String.prototype.controlName = function() {
    var t = this.lastIndexOf("_");
    return this.substr(0, t);
};
String.prototype.rootName = function(vIndex) {
    if(vIndex==null) {
        return this.split("_")[0];
    }
    try {
        return this.split("_")[vIndex];
    } catch(ex) {
        return this.split("_")[0];
    }
};
String.prototype.createControl = function(id) {
    return this + "_" + id;
};
/**
 * @method htmlDecode                                               //!!!!!!! to be fixed!
 * @return {string} The result string
 */
String.prototype.htmlDecode = function () {
    return this.replace(/&amp;/, "&").replace(/&lt;/, "<").replace(/&gt;/, ">")
        .replace(/&nbsp;/, " ").replace(/\<br \/\>/, "\r\n");
};
/**
 * @method htmlEncode                                               //!!!!!!! to be fixed!
 * @return {string} The result string
 */
String.prototype.htmlEncode = function () {
    return this.replace(/&/, "&amp;").replace(/\</, "&lt;").replace(/\>/, "&gt;")
        .replace(/\s/, "&nbsp;").replace(/\\r\\n/, "<br \/>");
};
/**
 * @method contain                                               //!!!!!!! to be fixed!
 * @return {boolean}
 */
String.prototype.contain = function (vSubStr) {
    if(vSubStr == null) {
        return false;
    }
    return (this.indexOf(vSubStr) >= 0);
};

/**
 * Prototype method of "Array".
 */
/**
 * Tell whether an element is in this array.
 * @method contain
 * @param vElement The element.
 * @return {boolean}
 */
Array.prototype.contain = function (vElement) { 
    var len = this.length;
    for(var i=0; i<len; i++) {
        if(this[i]==vElement) {
            return true;
        }
    }
    return false;
};
/**
 * Insert an unique element into the array
 * @param vElement The element.
 */
Array.prototype.insertUnique = function(vElement) {
    if(this.contain(vElement))
        return;
    this[this.length] = vElement;
};
/**
 * Check whether the index is legal ( >=0 && <length)
 * @param vIndex {number}. The index to be checked
 */
Array.prototype.isIndexLegal = function(vIndex) {
    return (NUI.Lang.isNumber(vIndex) && vIndex >= 0 && vIndex < this.length);
};
/**
 * Add an element into the array at some position
 * @param vPosition {int}.
 * @param vElemt {}
 */
Array.prototype.addAt = function(vPosition, vElemt) {
    if(!this.isIndexLegal(vPosition) && vPosition!=this.length) {
        return false;
    }
    this.splice(vPosition, 0, vElemt);
    return true;
};
/**
 * Add an array into the array at some position, if the position is not given, add at the end of the array.
 * @param vArray {}
 * @param vPosition {int}.
 */
Array.prototype.addRangeAt = function(vArray, vPosition) {
    if(vArray == null || !NUI.Lang.isArray(vArray)) {
        return false;
    }
    var pos = vPosition;
    if(pos == null) {
        pos = this.length;
    }
    if(!this.isIndexLegal(pos) && pos!=this.length) {
        return false;
    }
    for(var i=vArray.length-1; i>=0; i--) {
        this.splice(pos, 0, vArray[i]);
    }
    return true;
};
/**
 * Update an element in the array at some position
 * @param vPosition {int}.
 * @param vNewElemt {}
 */
Array.prototype.update = function(vPosition, vNewElemt) {
    if(!this.isIndexLegal(vPosition)) {
        return false;
    }
    this[vPosition] = vNewElemt;
    return true;
};

/**
 * Remove a target element in an array
 * @param vObj {object}. The element to be removed
 */
Array.prototype.remove = function(vObj) {
    var len = this.length;
    for(var i=0; i<len; i++) {
        if(this[i] == vObj) {
            this.splice(i, 1);
            i --;
            len --;
        }
    }
};
/**
 * Remove a target element in an array
 * @param vPosition {int}. The index element to be removed
 */
Array.prototype.removeAt = function(vPosition) {
    if(!this.isIndexLegal(vPosition)) {
        return false;
    }
    this.splice(vPosition, 1);
    return true;
};
/**
 * Get an element's index
 * @param vObj {object}. The target element
 * @param {int}. The index of the element. If the element is not exist, return -1
 */
Array.prototype.getIndex = function(vObj) {
    var len = this.length;
    for(var i=0; i<len; i++) {
        if(this[i] == vObj) {
            return i;
        }
    }
    return -1;
};
/**
 * Trim an array. 
 * For trimRight: If array[i] .. array[length-1]==null, remove array[i] .. array[length-1]
 */
Array.prototype.trimRight = function() {
    var i = this.length-1;
    for(; i>=0; i--) {
        if(this[i] != null) {
            break;
        }
    }
    this.splice(i+1, this.length-i-1);
    return this;
};
Array.prototype.trimLeft = function() {
    var i = 0;
    for(; i<this.length; i++) {
        if(this[i] != null) {
            break;
        }
    }
    this.splice(0, i);
    return this;
};
Array.prototype.trim = function() {
    this.trimLeft();
    this.trimRight();
    return this;
};

/**
 * Prototype method of "Event".
 */
/*
 * Realize "event" and "srcElement" in firfox.
 * @variable event
 * @variable srcElement
 */
if (window.addEventListener) {
    if (window.navigator.userAgent.indexOf("Safari") < 0) {
	    window.constructor.prototype.__defineGetter__("event",function() {
	        var o = arguments.callee.caller;
            var e; 
            while (o != null) { 
                e = o.arguments[0]; 
                if (e && (e.constructor == Event || e.constructor == MouseEvent || e.constructor == KeyboardEvent)) return e; 
                o = o.caller; 
            }
            return null;
	    });
	}
	Event.prototype.__defineGetter__("srcElement",function(){
	    return this.target;
	});
}

var Element = {
    show : function(obj) {
        if (typeof(obj) == "string")
            obj = NUI.Util.DomService.getNode(obj);
        obj.style.display = "";
    },
    hide : function(obj) {
        if (typeof(obj) == "string")
            obj = NUI.Util.DomService.getNode(obj);
        obj.style.display = "none";
    }
};
