/**
 * Utilities for basic functions.
 * 
 * Dependency : none
 */

// ---------------------------------------------------------------
// initialize
// ---------------------------------------------------------------
var Kf;
if (Kf == undefined) {
	Kf = {};
}
if (Kf.Lib == undefined) {
	Kf.Lib = {};
}
if (Kf.Lib.Basic == undefined) {
	Kf.Lib.Basic = {};
}

// ---------------------------------------------------------------
// String protptype : trim
// ---------------------------------------------------------------

String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g, "");
}

String.prototype.ltrim = function() {
	return this.replace(/^\s+/g, "");
}

String.prototype.rtrim = function() {
	return this.replace(/\s+$/g, "");
}

// ---------------------------------------------------------------
// Array prototype : add, remove
// ---------------------------------------------------------------

Array.prototype.add = function(item, index) {
	index = index || -1;
	if (0 <= index && index < this.length) {
		this.splice(index, 0, item);
	} else {
		this.push(item);
	}
};

Array.prototype.addSorted = function(item, fnCompare) {
	fnCompare = fnCompare || function(item1, item2) {
		return Kf.Lib.Basic.compare(item1, item2);
	};
	var index = -1;
	for (var i = 0; i < this.length; ++i) {
		if (fnCompare(item, this[i]) < 0) {
			index = i;
			break;
		}
	}
	this.add(item, index);
};

Array.prototype.remove = function(index) {
	if (0 <= index && index < this.length) {
		this.splice(index, 1);
	}
};

// ---------------------------------------------------------------
// Array prototype : numeric sort
// ---------------------------------------------------------------

Array.prototype.sortNum = function() {
	return this.sort(function(a, b) {
		return a - b;
	});
};

// ---------------------------------------------------------------
// Array prototype : function mapping
// ---------------------------------------------------------------

Array.prototype.map = function(f) {
	var returnArray = [];
	for (i = 0; i < this.length; i++) {
		returnArray.push(f(this[i]));
	}
	return returnArray;
}

// ---------------------------------------------------------------
// Array prototype : indexOf, contains
// ---------------------------------------------------------------

/**
 * item is value of checker function.
 */
Array.prototype.indexOf = function(item) {
	var fnCheck = function(value) {
		if (item instanceof Function) {
			return item(value);
		} else {
			return value == item;
		}
	};
	for (var i = 0; i < this.length; ++i) {
		if (fnCheck(this[i])) {
			return i;
		}
	}
	return -1;
};

Array.prototype.contains = function(item) {
	return this.indexOf(item) != -1;
};

// ---------------------------------------------------------------
// Array prototype : find
// ---------------------------------------------------------------

Array.prototype.find = function(searchStr) {
	var returnArray = false;
	for (i = 0; i < this.length; i++) {
		if (typeof(searchStr) == 'function') {
			if (searchStr.test(this[i])) {
				if (!returnArray) {
					returnArray = []
				}
				returnArray.push(i);
			}
		} else {
			if (this[i] === searchStr) {
				if (!returnArray) {
					returnArray = []
				}
				returnArray.push(i);
			}
		}
	}
	return returnArray;
}

// examples
//
// var tmp = [5,9,12,18,56,1,10,42,'blue',30,
// 7,97,53,33,30,35,27,30,'35','Ball', 'bubble'];
// // 0/1/2 /3 /4/5 /6 /7 /8 /9/10/11/12/13/14/15/16/17/ 18/ 19/ 20
// var thirty=tmp.find(30); // Returns 9, 14, 17
// var thirtyfive=tmp.find('35'); // Returns 18
// var thirtyfive=tmp.find(35); // Returns 15
// var haveBlue=tmp.find('blue'); // Returns 8
// var notFound=tmp.find('not there!'); // Returns false
// var regexp1=tmp.find(/^b/); // returns 8,20 (first letter starts with b)
// var regexp1=tmp.find(/^b/i); // returns 8,19,20 (same as above but ignore
// case)

// ---------------------------------------------------------------
// Date
// ---------------------------------------------------------------

Date.prototype.getYearEx = function() {
	var year = this.getYear();
	if (year < 1900) {
		year += 1900;
	}
	return year;
};

Date.prototype.getMonthEx = function() {
	return this.getMonth() + 1;
};

Date.prototype.getThisDay = function() {
	return new Date(this.getYearEx(), this.getMonth(), this.getDate());
}

Date.prototype.isSunday = function() {
	return this.getDay() == 0;
};

Date.prototype.getLatestSunday = function() {
	var day = this.getDay();
	var time = this.getTime();
	return new Date(time - day * 24 * 60 * 60 * 1000);
};

Date.prototype.getYmdString = function() {
	var year = this.getYearEx();
	var month = this.getMonthEx();
	if (month < 10) {
		month = "0" + month;
	}
	var dd = this.getDate();
	if (dd < 10) {
		dd = "0" + dd;
	}
	return year + "/" + month + "/" + dd;
};

Date.prototype.getMdString = function() {
	var month = this.getMonth() + 1;
	var dd = this.getDate();
	return month + "/" + dd;
};

Date.prototype.getHmsString = function() {
	var hour = this.getHours();
	if (hour < 10) {
		hour = "0" + hour;
	}
	var min = this.getMinutes();
	if (min < 10) {
		min = "0" + min;
	}
	var sec = this.getSeconds();
	if (sec < 10) {
		sec = "0" + sec;
	}
	return hour + ":" + min + ":" + sec;
};

Date.prototype.getHmString = function() {
	var hour = this.getHours();
	var min = this.getMinutes();
	if (min < 10) {
		min = "0" + min;
	}
	return hour + ":" + min;
};

Date.prototype.isToday = function() {
	var today = new Date();
	return this.getYear() == today.getYear()
			&& this.getMonth() == today.getMonth()
			&& this.getDate() == today.getDate();
};

// ---------------------------------------------------------------
// static funciton : simple version of sprintf
// ---------------------------------------------------------------

Kf.Lib.Basic.sprintf = function() {
	var argv = Kf.Lib.Basic.sprintf.arguments;
	if (argv.length == 0)
		return "";
	var len = argv[0].length;
	var pos = 1, esc = false, r = "", c, s;
	for (var i = 0; i < len; i++) {
		c = argv[0].charAt(i);
		if (esc == false) {
			if (c == "%")
				esc = true;
			else
				r += c;
		} else {
			if (c == "%") {
				r += "%";
			} else if (c == "s") {
				s = argv[pos++];
				if (s != null)
					r += s.toString();
				else
					r += "%s";
			} else {
				r += "%" + c;
			}
			esc = false;
		}
	}
	if (esc)
		r += "%";
	return r;
}

// ---------------------------------------------------------------
// static : replace hmtl string
// ---------------------------------------------------------------

Kf.Lib.Basic.escapeHtmlString = function(str) {
	if (str == null) {
		return null;
	}
	str = str.replace(/&/g, "&amp;");
	str = str.replace(/\</g, "&lt;");
	str = str.replace(/\>/g, "&gt;");
	str = str.replace(/"/g, "&quot;");
	return str;
}

Kf.Lib.Basic.replaceLinkString = function(str) {
	str = str.replace(/((http|https):\/\/[0-9a-z-\/._?=&%\[\]~]+)/gi,
			"<a href='$1'>$1</a>");
	return str;
}

// ---------------------------------------------------------------
// static : equals, compare(for comparable obj)
// ---------------------------------------------------------------

Kf.Lib.Basic.equals = function(obj1, obj2) {
	if ((!(obj1 instanceof Object)) || (!(obj2 instanceof Object))) {
		return obj1 == obj2;
	}
	for (var key in obj1) {
		if (obj1[key] != obj2[key]) {
			return false;
		}
	}
	for (var key in obj2) {
		if (obj1[key] != obj2[key]) {
			return false;
		}
	}
	return true;
};

Kf.Lib.Basic.compare = function(obj1, obj2) {
	if (obj1 == obj2) {
		return 0;
	} else if (obj1 < obj2) {
		return -1;
	} else {
		return 1;
	}
}

// ---------------------------------------------------------------
// static : toJson, parseJson
// ---------------------------------------------------------------

Kf.Lib.Basic.toJson = function(object) {
	if (object === null) {
		return "null";
	}
	if (object === undefined) {
		return undefined;
	}
	var type = typeof(object);
	if (type == "boolean") {
		return String(object);
	}
	if (type == "number") {
		return isFinite(object) ? String(object) : undefined;
	}
	if (type == "string") {
		return '"' + Kf.Lib.Basic.toSafeStr(object) + '"';
	}
	if (object instanceof Function) {
		return undefined;
	}
	if (object instanceof Array) {
		var result = [];
		for (var i = 0; i < object.length; ++i) {
			var obj = Kf.Lib.Basic.toJson(object[i]);
			if (obj !== undefined) {
				result.push(obj);;
			}
		}
		return '[' + result.join(', ') + ']';
	} else if (object instanceof Object) {
		var result = [];
		for (var key in object) {
			var obj = Kf.Lib.Basic.toJson(object[key]);
			if (obj !== undefined) {
				result.push('"' + key + '":' + obj);
			}
		}
		return '{' + result.join(', ') + '}';
	} else {
		return undefined;
	}
};

Kf.Lib.Basic.parseJson = function(str) {
	// we want to allow the quote string such as "'ddd'" ....

	// if (/^[\],:{}\s]*$/.test(str.replace(/\\./g, '@').replace(
	// /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(:?[eE][+\-]?\d+)?/g,
	// ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
	return eval("(" + str + ")");
		// } else {
		// throw new SyntaxError('parseJson');
		// }

};

Kf.Lib.Basic.toJsonObj = function(object) {
	if (object === null || object === undefined) {
		return object;
	}
	var type = typeof(object);
	if (type == "boolean") {
		return object;
	}
	if (type == "number") {
		return isFinite(object) ? object : undefined;
	}
	if (type == "string") {
		return Kf.Lib.Basic.toSafeStr(object);
	}
	if (object instanceof Function) {
		return undefined;
	}
	if (object instanceof Array) {
		var result = [];
		for (var i = 0; i < object.length; ++i) {
			var obj = Kf.Lib.Basic.toJsonObj(object[i]);
			if (obj !== undefined) {
				result.push(obj);;
			}
		}
		return result;
	} else if (object instanceof Object) {
		var result = {};
		for (var key in object) {
			var obj = Kf.Lib.Basic.toJsonObj(object[key]);
			if (obj !== undefined) {
				result[key] = obj;
			}
		}
		return result;
	} else {
		return undefined;
	}
}

Kf.Lib.Basic.toSafeStr = function(m) {
	return function(str) {
		if (/["\\\x00-\x1f]/.test(str)) {
			return str.replace(/[\x00-\x1f\\"]/g, function(a) {
				var c = m[a];
				if (c) {
					return c;
				}
				c = a.charCodeAt();
				return '\\u00' + Math.floor(c / 16).toString(16)
						+ (c % 16).toString(16);
			});
		}
		return str;
	};
}({
	'\b' : '\\b',
	'\t' : '\\t',
	'\n' : '\\n',
	'\f' : '\\f',
	'\r' : '\\r',
	'"' : '\\"',
	'\\' : '\\\\'
});

Kf.Lib.Basic.inBaseType = function(object) {
	var type = typeof object;
	if (type == "boolean" || type == "number" || type == "string") {
		return true;
	}
	// if ((object instanceof Boolean) || (object instanceof Number)
	// || (object instanceof String)) {
	// return true;
	// }
	return false;
}

// not used
Kf.Lib.Basic.toStringEx = function(object) {
	if (object === null) {
		return "null";
	} else if (object === undefined) {
		return "undefined";
	}

	if (Kf.Lib.Basic.inBaseType(object)) {
		return "" + object;
	}

	if (object instanceof Function) {
		var abbrFunc = arguments[1];
		if (abbrFunc) {
			return "function";
		} else {
			return object.toString();
		}
	}

	if (object instanceof Array) {
		var results = [];
		for (var i = 0; i < object.length; ++i) {
			var value = Kf.Lib.Basic.toStringEx(object[i], true);
			results.push(value);;
		}
		return '[' + results.join(', ') + ']';
	} else if (object instanceof Object) {
		var results = [];
		for (var key in object) {
			var value = Kf.Lib.Basic.toStringEx(object[key], true);
			results.push(key + ':' + value);
		}
		return '{' + results.join(', ') + '}';
	} else {
		return "error in toStringEx()";
	}
};

// for debug
myalert = function(object, label) {
	var message;
	if (label != null) {
		message = label + ":" + Kf.Lib.Basic.toJson(object);
	} else {
		message = Kf.Lib.Basic.toJson(object);
	}
	alert(message);
};

mylog = function(object, label) {
	if (console == null || console.log == null) {
		return;
	}
    console.log(object);
    /*
	var message;
	if (label != null) {
		message = label + ":" + Kf.Lib.Basic.toJson(object);
	} else {
		message = Kf.Lib.Basic.toJson(object);
	}
	console.log(message);
    */
}