(function($){
var nnp = {

	getProps: function(o){
		var tmp = '';
		for(var p in o){tmp += p + ': ' + o[p] + '\n';}
		return tmp;
	},
	
	// array

	reorderArray: function(arr){
		var tmp = [];
		for(var i=1, len=arguments.length; i<len; i++)
		tmp.push(arr[arguments[i]]);
		return tmp;
	},
	
	removeIndex: function(arr){
		var tmp = [];
		loop: for(var i=0, len=arr.length; i<len; i++){
			for(var j=1, len2=arguments.length; j<len2; j++)
			if (i == arguments[j]) continue loop;
			tmp.push(arr[i]);
		}
		return tmp;
	},
	
	cloneArray: function(arr){
		return $.merge([], arr);
	},
	
	testArray: function(arr, callback){
		for(var i=0, l=arr.length; i<l; i++){
			if(callback(arr[i])){return arr[i];}
		} 
		return false;
	},
	
	// string
	
	uppercaseFirstLetter: function(str){
		return str.charAt(0).toUpperCase() + str.slice(1);
	},
	
	strLoopConcat: function(str, loop){
		var ret = '';
		for(var i=0; i<loop; i++){ret+=str;}
		return ret;
	},
	
	replaceDiacritics: function(s){
		var s,
		chars = ['A','a','E','e','I','i','O','o','U','u','N','n','C','c'],
		diacritics = [
			/[\300-\306]/g, /[\340-\346]/g, // A, a
			/[\310-\313]/g, /[\350-\353]/g, // E, e
			/[\314-\317]/g, /[\354-\357]/g, // I, i
			/[\322-\330]/g, /[\362-\370]/g, // O, o
			/[\331-\334]/g, /[\371-\374]/g,  // U, u
			/[\321]/g, /[\361]/g, // N, n
			/[\307]/g, /[\347]/g, // C, c
		];
		for (var i=0, len=diacritics.length; i<len; i++) 
		s = s.replace(diacritics[i],chars[i]);
		return s;
	},
	
	convertForUrl: function(s){
		return this.replaceDiacritics(s).replace(/\W+/g, '-').toLowerCase();
	},
	
	convertForCssFiles: function(s){
		return this.replaceDiacritics(s).replace(/\W+/g, '-').replace('_', '-').toLowerCase();
	},
	
	// utils

	getClassStartsWith: function(el, prefix){
		var el = nnp.jquerify(el);
		var re = new RegExp(eval('/([\\w-]?)' + prefix + '[\\w-]*/'));
		if((tmp = el.attr('class')) && (tmp = tmp.match(re)) && !tmp[1])
		return tmp[0];
		return false;
	}, 
	
	removeClassStartsWith: function(el, prefix){
		var c = this.getClassStartsWith(el, prefix);
		if(c) nnp.jquerify(el).removeClass(c);
		return this;
	},
	
	getHtmlData: function(jsTag, index){
		if(!jsTag || !jsTag.match(/^js/)) return false;
		var index = index, jsTag = jsTag.split('-'); jsTag.shift();
		if(jsTag.length == 1) index = 0;
		return !isNaN(index) ? jsTag[index] : jsTag;
	},
	
	getJsTagData: function(el, prefix, index){
		var jsTag = this.getClassStartsWith(el, prefix);
		if(!jsTag || !jsTag.match(/^js/)) return false;
		var index = index, jsTag = jsTag.split('-'); jsTag.shift();
		if(jsTag.length == 1) index = 0;
		return !isNaN(index) ? jsTag[index] : jsTag;
	},
	
	each: function(arr, fn){
		for(var i=0, len=arr.length; i<len; i++){
			var ret = fn.call(arr[i], i);
			if(ret === true) continue;
			if(ret === false) break;
		}
		return this;
	},
	
	eachR: function(arr, fn){
		for(var i=arr.length-1; i>=0; i--){
			var ret = fn.call(arr[i], i);
			if(ret === true) continue;
			if(ret === false) break;
		}
		return this;
	},
	
	jquerify: function(el){
		return el.jquery ? el : $(el);
	},

	// ajax
	
	ws: function(o){ // webservice
		var a, self = this, s = o.success, e = o.error;
		return $.ajax($.extend(o, {
			success: function(data, status){
				a = this;
				self.enumerate(
				'EStatus.' + self.EStatus_ws,
				data.responseStatus,
				function(status){
					status == 'WS_SUCCESS'
					? s.call(a, data, status)
					: e.call(a, data, status, 'application');
				});
			},
			error: function(xhr, status, error){
				e.call(this, error, status, 'external');
			}
		}));
	},
	
	wsGet: function(url, data, callback, type){
		if($.isFunction(data)){callback = data; data = {};}
		return nnp.ws({
			type: 'GET',
			url: url,
			data: data,
			success: callback,
			error: callback,
			dataType: type
		});
	},
	
	wsPost: function(url, data, callback, type){
		if($.isFunction(data)){callback = data; data = {};}
		return nnp.ws({
			type: 'POST',
			url: url,
			data: data,
			success: callback,
			error: callback,
			dataType: type
		});
	},

	// enumerator
	
	/**
	* // enumerator
	* config.e{ 
	*     const1: 1,
	*     const2: 2,
	*     const3: 3
	* };
	*
	* // EX 1: 'e'
	* nnp.enumerate('e'); // 'error'
	* nnp.enumerate('e', true); // 'error'
	* nnp.enumerate('e', 1); // 'error'
	* nnp.enumerate('e', 1, function(val){
	*     // this = config['e']
	*     return this.const1 == val
	* }); // true
	* 
	* // EX 2: 'e.const1'
	* nnp.enumerate('e.const1', 1); // true
	* nnp.enumerate('e.const1', 2); // false
	* nnp.enumerate('e.const1', 2, 
	*     function(bool, val){return bool+' '+val}
	* ); // 'false 2'
	* nnp.enumerate('e.const1', 1, 
	*     function(bool, val){return 'ok'}, // success
	*     function(bool, val){return 'ko'}  // failure
	* ); // 'ok'
	* 
	* // EX 3: 'e.const1|const3'
	* nnp.enumerate('e.const1|const3', 3); // 'const3'
	* nnp.enumerate('e.const1|const3', 2); // false
	* nnp.enumerate('e.const1|const3', 2, 
	*     function(cst, val){return cst ? 'good' : 'bad'}
	* ); // 'bad'
	*/
	
	enumerate: function(ns, val, success, failure){
		var val = parseInt(val);
		if(isNaN(val)){nnp.logError('nnp.enumerate()', 0); return 'error';}
		var ns = ns.match(/^(\w+)(?:\.((?:\w+(\|))*\w+))?$/);
		if(!ns){nnp.logError('nnp.enumerate()', 1); return 'error';}
		var enumerate = config[ns[1]];
		if(!ns[2]){return success.call(enumerate, val);}
		ns = !ns[3] // no pipes
		? enumerate[ns[2]] == val
		: nnp.testArray(ns[2].split('|'), function(item){
			return enumerate[item] == val;
		});
		return !success ? ns : (ns || !ns && !failure)
		? success.call(enumerate, ns, val)
		: failure.call(enumerate, ns, val);
	},
	
	EStatus_ws: [
		'WS_SUCCESS',
		'WS_FAILURE_DATA', 
		'WS_FAILURE_SQL', 
		'WS_FAILURE_LOGOFF', 
		'WS_FAILURE_INI', 
		'WS_FAILURE_SELECT'
	].join('|'),
	
	EStatus_fup: [
		'UPLOAD_SUCCESS',
		'UPLOAD_FAILURE',
		'UPLOAD_SIZE_FAILURE',
		'UPLOAD_FORMAT_FAILURE'
	].join('|'),
	
	EStatus: function(val, success, failure){
		return this.enumerate('EStatus.WS_SUCCESS', val, success, failure); 
	},

	getWSEStatus: function(code){
		return nnp.enumerate('EStatus.'+this.EStatus_ws, code);
	},
	
	getFUPEStatus: function(code){
		return nnp.enumerate('EStatus.'+this.EStatus_fup, code);
	}
		
};

nnp.log = function(context, key, val){
	if(!config.debug() || !window.console){return}
	return console.info(val !== undefined 
		? context + '\n' + key + ': ' + val	
		: context + '\n' + key
	);
};

nnp.logEStatus = function(context, code){
	return this.log(
		context,
		'EStatus: ' + 
		code + ' -> ' + 
		nnp.getWSEStatus(code)
	);
};

nnp.logError = function(context, id, type){
	if(!config.debug() || !window.console){return}
	var msg = context;
	if(type){msg += ' - ' + type + ' error'}
	msg += ' - ' + (isNaN(parseInt(id)) ? id : config.error(id));
	return console.error(msg);
};

if(config.blackbird){
$('head').append(
'<script type="text/javascript" src="' + config.path.misc + '/blackbird/blackbird.js"></script>' + 
'<link type="text/css" rel="Stylesheet" href="' + config.path.misc + '/blackbird/blackbird.css" />'
)}

// namespaces
nnp.formElement = {};

// John Resig Simple JavaScript Inheritance API : 
// http://ejohn.org/blog/simple-javascript-inheritance/
nnp.Class = function(){
	var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
	var Class = function(){};
	Class.extend = function(prop){
		var _super = this.prototype;
		initializing = true;
		var prototype = new this();
		initializing = false;
		for (var name in prop){
			prototype[name] = typeof prop[name] == "function" &&
			typeof _super[name] == "function" && fnTest.test(prop[name]) ?
			(function(name, fn){
				return function(){
					var tmp = this._super;
					this._super = _super[name];
					var ret = fn.apply(this, arguments);       
					this._super = tmp;
					return ret;
				};
			})(name, prop[name]) :
			prop[name];
		}
		function Class(){
			if ( !initializing && this.init )
			this.init.apply(this, arguments);
		}
		Class.prototype = prototype;
		Class.constructor = Class;
		Class.extend = arguments.callee;
		return Class;
	};
	return Class;
}();

if(window.nnp) $.extend(window.nnp, nnp);
else window.nnp = nnp;

})(jQuery);
