/**
*
* @fileOverview  Definition for the base namespaces, classed and methods to use in the library
*
* @author WHL Member
*/

/**
* @namespace This is a base namespace for all classes/objects in library.
*/
var Whl = {};

/**
* Get DOM elements reply on Id
*
* @memberOf Whl
* @param {String} Element Id, can passed many element id
* @returns {Dom Element|Array}
*/
Whl.$ = function(element) {
	if (!Object.isUndefined(arguments)) {
		if (arguments.lenght > 1) {
			var elements = [];
			for (var i=0; i< arguments.lenght; i++) {
				elements.push(Whl.$(arguments[i]));
			}
			return elements;
		}
	}
	if (Object.isString(element)) {
		return document.getElementById(element);
	}
};

/**
*  Copy properties of a object for other object
*
* @lends Object
* @param {object} source object
* @param {object} destination object
* @returns {Object}
*/
Object.extend = function(destination, source) {
	for (var key in source) {
		destination[key] = source[key];
	}
	return destination;
};

/**
* Extend properties, methods for the built-in object : Object.
*/
(function() {
	Object.extend(Object, /** @lends Object */{
		/**
		* Get class name of object
		* @param {object} object
		* @returns {String} Class Name
		*/
		getClassName: function(object) {
			var objString = Object.prototype.toString.call(object);
			return objString.match(/^\[object\s(.*)\]$/)[1];
		},
		/**
		* Check the variable is underfined type or not.
		* @param {object} object
		* @returns {Boolean} Return true if object is of undefined type, otherwise return false
		*/
		isUndefined: function(object) {
			return (typeof object === 'undefined');
		},
		/**
		* Check the variable is number or not
		* @param {object} object
		* @returns {Boolean} Return true if object is of number type, otherwise return false
		*/
		isNumber: function(object) {
			return (Object.getClassName(object) === 'Number');
		},
		/**
		* Check the variable is string or not
		* @param {object} object
		* @returns {Boolean} Return true if object is of string type, otherwise return false
		*/
		isString: function(object) {
			return (Object.getClassName(object) === 'String');
		},
		/**
		* Check the variable is array or not
		* @param {object} object
		* @returns {Boolean} Return true if object is of array type, otherwise return false
		*/
		isArray: function(object) {
			return (Object.getClassName(object) === 'Array');
		},
		/**
		* Check the variable is a function or not
		* @param {object} object
		* @returns {Boolean} Return true if object is a function, otherwise return false
		*/
		isFunction: function(object) {
			return (typeof object === 'function');
		},
		isObject: function(object) {
			return (typeof object === 'object');
		},
		/**
		* Get all keys of the object
		* @param {object} object
		* @retuns {Array} Array keys
		*/
		getKeys: function(object) {
			var keys = [];
			for (var key in object) {
				keys.push(key);
			}
			return keys;
		},
		/**
		* Get all keys of the object
		* @param {object} object
		* @retuns {Array} Array keys
		*/
		getValues: function(object) {
			var values = [];
			for (var key in object) {
				values.push(object[key]);
			}
			return values;
		},
		/**
		 * Create a query string from an array|object with the key/value
		 * 
		 * @param {Object|Array} object
		 * @returns {String}
		 */
		createQueryString: function(object) {
		    var queryString = '';
		    if (this.isArray(object) || this.isObject(object)) {
		        for(var k in object) {
		            queryString += (queryString ? '&' : '') + k + "=" + object[k];
		        }
		    }
		    return queryString;
		},
		/**
		 * 
		 */
		isEmpty: function(object){
		    for(var i in object){
		        if(object.hasOwnProperty(i)) return false;
		    }
		    return true;
		}
		//More here ...

	});
})();

/**
* @namespace Whl.Class This object works as a static class that Contains properties, methods
* and classes that related to classes.
*/
Whl.Class = {};
/**
* Extend more functions for Whl.Class object
*/
Object.extend(Whl.Class, {
	/**
	* Inherit a class.
	* @memberOf Whl.Class
	* @param {Function} subClass Constructor function of sub class
	* @param {Function} superClass Constructor function of super class
	*/
	inherit: function(subClass, superClass){
		var F = function(){};
		F.prototype = superClass.prototype;
		subClass.prototype = new F();
		//Reset the constructor for subClass
		subClass.prototype.constructor = subClass;
		//Add superClass property for child Class so child can reference to parent class
		subClass.superClass = superClass.prototype;
		if(superClass.prototype.constructor == Object.prototype.constructor) {
			superClass.prototype.constructor = superClass;
		}
	},
	/**
	* Add new object for creating the namespace. Can add many namespaces
	* For example: Ns1.Ns2..... -> will add namespace Ns1, then add Ns2 to Ns1, ...
	* @memberOf Whl.Class
	* @param {String} namespace Namespace name
	* @returns {object}
	*/
	addNamespace: function(namespace) {
		if (!namespace) {
			return;
		}
		var ns = namespace.split('.');
		var target = null;
		for (var i=0; i<ns.length; i++) {
			if (target == null) {
				target = window[ns[i]] ? window[ns[i]] : window[ns[i]] = {};
			} else {
				target = target[ns[i]] ? target[ns[i]] : target[ns[i]] = {};
			}
		}
		return target;
	}
});

/**
* Extend properties, methods for the built-in class Function
*/
(function(){
	/**
	* Convert arguments to array
	* @param {Array} args
	* @returns {Array} Actual Array
	*/
	function toArray(args) {
		var array = [];
		for (var i=0; i<args.length; i++) {
			array.push(args[i]);
		}
		return array;
	}
	Object.extend(Function.prototype, /** @lends Function.prototype */ {
		/**
		* Add object for the function's current context
		* @param {object} object It will be this in function
		* @returns {Function} Return an annonymous function with object is the this context in function
		*/
		bind: function(object) {
			if (arguments.length < 2 && Object.isUndefined(arguments[0])) {
				return this;
			}
			var method = this;
			var args = Array.prototype.slice.call(arguments, 1);
			return function() {
				return method.apply(object, args.concat(toArray(arguments)));
			};
		},
		/**
		* Add object for the function's current context
		* @param {object} object It will be this object of function
		* @returns {Function} Return an annonymous function with object is the this context in function
		* and event object is passed throught the first parameter.
		*/
		bindEvent: function(object) {
			var method = this;
			var args = Array.prototype.slice.call(arguments, 1);
			return function(event) {
				var args1 = Array.prototype.slice.call(arguments, 1);
				args = args.concat(args1);
				return method.apply(object, args.concat([event || window.event]));
			};
		}

		//Add more methods for Function class ...
	});
})();

/**
* Add more methods for the built-in class: String.
*/
Object.extend(String.prototype, /** @lends String.prototype */ {
	/**
	* trim left and right whitespace of a string
	* @returns {String}
	*/
	trim: function() {
		return this.replace(/^\s+/g, '').replace(/\s+$/g,'');
	},
	/**
	* Validate email
	* @returns {Boolean}
	*/
	isEmail: function() {               
//		var regEx = new RegExp('^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]{2,6}$');
//		return regEx.test(this);
                return (this.search(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]{2,6}$/) == -1) ? false : true ;
	},

	/**
	* Auto-URL from a string
	* @param {String} val Raw name
	* @returns {String} URL
	*/
	autoUrl: function() {
		var url = this.replace(/[^0-9a-zA-Z_\-]/g, " ");
		url = url.replace(/\s\s+/g, " ").trim();
		url = url.replace(/\s/g, "_");
		return url;
	},
	/**
	* Auto-URL from a string
	* @param {String} val Raw name
	* @returns {String} URL
	*/
	autoUrl2: function() {
		var url = this.replace(/[^0-9a-zA-Z]/g, " ");
		url = url.replace(/\s\s+/g, " ").trim();
		url = url.replace(/\s/g, "-");
		return url.toLowerCase();
	},
	/**
	* Auto Upper Case from a string
	* @param {String} val Raw name
	* @returns {String} URL
	*/
	autoUpperCase: function() {
		var url = this.autoUrl();
		return url.toUpperCase();
	},
	/**
	* Compare with a string
	*
	* @param {String} str
	* @returns {Boolean}
	*/
	compare: function(str) {
		return (this == str);
	},
	/**
     * Convert a string to date value - format dd mmm yyy (eg: 01 Jan 2009)
     *
     * @returns Date
	 */
	toDate: function(){
	    return Date.toDate(this);
	}
});
/**
* Add more static methods for the built-in class: Number.
*/

/**
* Compare to number
*
* @lends Object
* @param {Number} num1
* @param {Number} num2
* @returns {Number} 0: Equal, < 0: This number is less than the number, > 0: Is greater than
*/
Number.compareFloat = function(num1, num2) {
	num1 = parseFloat(num1);
	num2 = parseFloat(num2);
	if (num1 == num2) return 0;
	else if (num1 < num2) return -1;
	else return 1;
};

/**
* Convert a number to Date object
*
* @returns {Object} the Date object
*/
Number.prototype.toDate = function() {
	return(new Date(this*1000));
};
/**
* Add more static methods for the built-in class: Date.
*/
/**
* Compare two string date
*
* @lend Date
* @param {String} date1
* @param {String} date2
* @param {Number} type 1: the input date in format mm dd yyyy, 0: dd mm yyyy
* @returns {Number} 0: Equal, < 0: Lest than, > 0: greater than
*/
Date.compareDate = function(date1, date2, type) {
	if (!type) type=0;
	var dateInput=(type==1)?1:0;
	var dateType=new Array();
	dateType[0]=/^\d{1,2}(\-|\/|\.|\s)\d{1,2}(\-|\/|\.|\s)\d+$/;    //date format dd mm yyyy
	dateType[1]=/^\d{1,2}(\-|\/|\.|\s)\d{1,2}(\-|\/|\.|\s)\d+$/;    //date format mm dd yyyy

	if (date1.search(dateType[dateInput])==-1||date2.search(dateType[dateInput])==-1) throw 'Invalid date';

	var seperator1=(date1.indexOf("-")!=-1)?"-":(date1.indexOf("/")!=-1)?"/":(date1.indexOf(".")!=-1)?".":(date1.indexOf(" ")!=-1)?" ":"";
	var seperator2=(date2.indexOf("-")!=-1)?"-":(date2.indexOf("/")!=-1)?"/":(date2.indexOf(".")!=-1)?".":(date2.indexOf(" ")!=-1)?" ":"";

	if (seperator1==""||seperator2=="") throw 'Invalid date';

	var dateArr1=date1.split(seperator1);
	var dateArr2=date2.split(seperator2);

	if (dateArr1.length!=3||dateArr2.length!=3) throw 'Invalid date';

	if (dateInput==1){
		var year1 = dateArr1[2];
		var year2 = dateArr2[2];
		var month1 = dateArr1[0];
		var month2 = dateArr2[0];
		var day1 = dateArr1[1];
		var day2 = dateArr2[1];
	}else{
		var year1 = dateArr1[2];
		var year2 = dateArr2[2];
		var month1 = dateArr1[1];
		var month2 = dateArr2[1];
		var day1 = dateArr1[0];
		var day2 = dateArr2[0];
	}
	var result = null;
	result = Number.compareFloat(year1, year2);
	if (result != 0) return result;
	result = Number.compareFloat(month1, month2);
	if (result != 0) return result;
	result = Number.compareFloat(day1, day2);
	if (result != 0) return result;
	return 0;
};

/**
* Compare two string date with the format dd mm yyy (eg: 01 Jan 2009)
*
* @lend Date
* @param {String} date1
* @param {String} date2
* @returns {Number} 0: Equal, < 0: Lest than, > 0: greater than
*/
Date.compareDate2 = function(date1, date2) {
	var format = /^\d{1,2}\s[A-Z][a-z]{2}\s[0-9]{4}$/;
	if (date1.search(format) == -1 || date2.search(format) == -1) throw 'Invalid Date';
	date1 = date1.split(' ');
	date2 = date2.split(' ');
	var shortMonth = {Jan: 1, Feb: 2, Mar: 3, Apr: 4, May: 5, Jun: 6, Jul: 7, Aug: 8, Sep: 9, Oct: 10, Nov: 11, Dec: 12};
	for( var key in shortMonth) {
		if (key == date1[1]) {
			date1[1] = shortMonth[key];
			break;
		}
	}
	for( var key in shortMonth) {
		if (key == date2[1]) {
			date2[1] = shortMonth[key];
			break;
		}
	}
	var result = null;
	result = Number.compareFloat(date1[2], date2[2]);
	if (result != 0) return result;
	result = Number.compareFloat(date1[1], date2[1]);
	if (result != 0) return result;
	result = Number.compareFloat(date1[0], date2[0]);
	if (result != 0) return result;
	return 0;
};

/**
* Convert a string to date value - format dd mmm yyy (eg: 01 Jan 2009)
*
* @lend Date
* @param {String} strDate
* @param {String} date2
* @returns {Number} 0: error, > 0: date value
*/
Date.toDate = function(strDate) {
    var shortMonth = {Jan: 1, Feb: 2, Mar: 3, Apr: 4, May: 5, Jun: 6, Jul: 7, Aug: 8, Sep: 9, Oct: 10, Nov: 11, Dec: 12};
    var resDate = new Date();
    var arrDate = strDate.match(/^([0-9]{1,2})\s+([A-Za-z]{3})\s+([0-9]{4})$/);
    if(arrDate && !Object.isUndefined(shortMonth[arrDate[2]])){
        resDate.setFullYear(arrDate[3], shortMonth[arrDate[2]] - 1, arrDate[1]);
    }
    return resDate;
};

/**
* Display date as string
*
* @returns {String} dd mmm yyyy
*/
Date.prototype.toDateStringExt = function(){
	var shortMonth = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
	if (this.valueOf()==0) return('');
	return(this.getDate()+' '+shortMonth[this.getMonth()]+' '+this.getFullYear());
};

/**
* Display date/time as string
*
* @returns {String} dd mmm yyyy
*/
Date.prototype.toDateTimeString = function(){
	if (this.valueOf()==0) return('');
	return(this.toDateStringExt()+' '+this.getHours()+':'+this.getMinutes()+':'+this.getSeconds());
};

/**
* Add more Class, functions for namespace Whl
*/
(function (){
	Object.extend(Whl, {
		/**
		* Get Token from current form
		*
		* @returns {String}
		*/
		getToken: function() {
			return ('token=' + $('#token').val());
		},
		/**
		* Is response has error
		*
		* @param {String} response
		* @returns {Boolean}
		*/
		isErrReq: function(response) {
			return (response.indexOf('WRN:') != -1);
		},
		/**
		* Is response has an synchronization data message
		*
		* @param {String} response
		* @returns {Boolean}
		*/
		isSync: function(response) {
			return (response.indexOf('SYNC:') != -1);
		},
		/**
		* Check the data is a valid json format
		*
		* @param {String} data
		* @retuns {Boolean}
		*/
		isJson: function(data) {
			return (data.search(/^(\{(.*)\}|\[(.*)\])$/) != -1 );
		},
		getScrollY: function() {
			var scrollY = 0;
			if (document.documentElement && document.documentElement.scrollTop) {
				scrollY = document.documentElement.scrollTop;
			} else if(document.body && document.body.scrollTop) {
				scrollY = document.body.scrollTop;
			} else if(window.pageYOffset) {
				scrollY = window.pageYOffset;
			} else if(window.scrollY) {
				scrollY = window.scrollY;
			}
			return scrollY;
		},
		/**
		* Get Cookie with the name applied
		*
		* @param {String} name
		* @returns {String|null}
		*/
		getCookie: function(name) {
			if (document.cookie.length > 0) {
				var start = document.cookie.indexOf(name + "=");
				if (start != -1) {
					start = start + name.length + 1;
					var end = document.cookie.indexOf(";", start);
					if (end == -1) end = document.cookie.length;
					return unescape(document.cookie.substring(start, end));
				}
			}
			return null;
		},
		/**
		 * Set cookie with value
		 * 
		 * @param {String} name
		 * @Param {String} value
		 * @param {Number} days
		 * @returns {Object} Whl Object
		 */
		setCookie: function(name, value, days) {
		    days = (typeof days == 'undefined') ? 7 : days;
		    var date = new Date();
		    date.setTime(date.getTime()+(days*24*60*60*1000));
		    var expires = "; expires="+date.toGMTString();
		    document.cookie = name+"="+value+expires+"; path=/";
		    return this;
		},
		/**
		 * Delete the cookie
		 * 
		 * @param {String} name
		 * @returns {Object} Whl object
		 */
		deleteCookie: function(name) {
		    this.setCookie(name, '', -1);
		    return this;
		},
		/**
		* View the details of content
		*
		* @returns {void}
		*/
		getMore: function() {
			$('.cont-more').each(function() {
				var id = this.id.split('-');
				$(this).click(function(event) {
					event.preventDefault();
					$('#' + id[1] + '-detail').removeClass('ui-hide').show();
					$(this).remove();
				});
			});
		},

		/**
		* Show/hide content
		*
		* @param {Object}: default {controlHideClass:'no-class',controlShowClass:'point'}
		* @returns {void}
		*/
		toggleContent: function(options) {				
			options = $.extend({hideClass:'point01', showClass:'point', prefix: 'toggle-'}, options);
			$('.' + options.showClass).each(function() {
			    $(this).css('cursor','pointer');
			    $(this).click(function(event) {
			        event.preventDefault();
			        var id = this.id.substring(options.prefix.length, this.id.length);
	                if ($(this).hasClass(options.showClass)) {
	                    $(this).removeClass(options.showClass).addClass(options.hideClass);
	                    $("#" + id).hide();
	                } else {
	                    $(this).removeClass(options.hideClass).addClass(options.showClass);
	                    $("#" + id).show();
	                }
			    });
			});
		},
		//Add more functions, class for Whl .... here
		/**
		* Random a number from 0 to number
		*
		* @param {Number} number
		* @returns {Number}
		*/
		rand: function(number) {
			return Math.round(Math.random() * number);
		}
	});
})();
