
Function.prototype.curry = function() {
	var slice = Array.prototype.slice,
		args  = slice.apply(arguments),
		that  = this;
	return function() {
		return that.apply(null, args.concat(slice.apply(arguments)));
	};
};

/* To generate Function-type Class specified by "spec".
 * Each property is unnecessary.
 * @param Object spec
 *   Function spec.superClass       ... superClass (Function-type) class or object initializer.
 *   Function spec.create ... executed only when namespace prepared successfully.
 *   Object spec.static        ... namespace which specified to the class.
 *   Object spec.private       ... namespace which you can access only in a method.
 *   Object spec.public        ... namespace which anyone can access.
 */
var funClass;
funClass = (function (my, spec) {
	spec.private = spec.private || {};
	spec.public  = spec.public  || {};
	spec.static  = spec.static  || {};

	var id = my.id++;
	spec.static.__getClassId  = spec.static.__getClassId  || function () {return id;};
	spec.public.__getClassId  = spec.public.__getClassId  || function () {return id;};
	spec.static.__hasInstance = spec.public.__hasInstance || function (i) {
		return i instanceof Object
			&& i.hasOwnProperty("getClassId")
			&& "function" === typeof i.getClassId
			&& i.getClassId() === id;
	};
	spec.static.__poorCopy = spec.static.__poorCopy || function () {
		var that = {
			public : (spec.superClass ? spec.superClass.poorCopy.apply(null, arguments) : {})
		};
		if (spec.create) {spec.create.curry(that).apply(null, arguments);}
		return that;
	};

	function funClass() {
		var that = spec.superClass ? spec.superClass.apply(null, arguments) : {};
		var $ = function (name) {
			//if (class.hasOwnProperty(name)) return class[name];
			if ($.private.hasOwnProperty(name)) return $.private[name];
			else if ($.public.hasOwnProperty(name))  return $.public[name];
			else if ($.static.hasOwnProperty(name))  return $.static[name];
			else return (void 0);
		};
		$.static  = funClass;
		$.public  = that;
		$.private = {};

		var key;
		for (key in spec.public) if (spec.public.hasOwnProperty(key)) {
			if ("function" === typeof spec.public[key]) {
				if (key.slice(0, 2) === "__") {
					$.public[key.slice(2)] = spec.public[key];
				} else {
					$.public[key] = spec.public[key].curry($);
				}
			} else {
				that[key] = that[key] || spec.public[key];
			}
		}
		for (key in spec.private) if (spec.private.hasOwnProperty(key)) {
			if ("function" === typeof spec.private[key]) {
				if (key.slice(0, 2) === "__") {
					$.private[key.slice(2)] = spec.private[key];
				} else {
					$.private[key] = spec.private[key].curry($);
				}
			} else {
				$.private[key] = spec.private[key];
			}
		}
		delete key;
		
		if (spec.create) spec.create.curry($).apply(null, arguments);
		return that;
	};

	var key;
	for (key in spec.static) if (spec.static.hasOwnProperty(key)) {
		if ("function" === typeof spec.static[key]) {
			if (key.slice(0, 2) === "__") {
				funClass[key.slice(2)] = spec.static[key];
			} else {
				funClass[key] = spec.static[key].curry(funClass);
			}
		} else {
			funClass[key] = spec.static[key];
		}
	}
	delete key;

	return funClass;
}).curry({id:0});

