// formatting and validation
// functions which names start with an underscore are internal - do not call them
ncbiformatter = {
	_positionFormat: new RegExp("^[ \t]*([0-9]*(?:\,[0-9]{3})*(?:[\.][0-9]+)?)[ ]*(K|M)?(?:bp?)?|^[ \t]*0*", "i"),
	// partial format
//	_positionFormat2: new RegExp("^[ \t]*([0-9,]*([\.][0-9]*)?)[ ]*(K|M)?(?:bp?)?[ ]*", "i"),
	_positionFormat2: new RegExp("^[ \t]*([0-9]*(?:\,[0-9]{3})*(?:\,[0-9]*)?(?:[\.][0-9]*)?)[ ]*(K|M)?(?:bp?)?", "i"),
	_objectFormat: new RegExp("^[ \t]*([_A-Za-z0-9][_A-Za-z0-9\.\-]*)[ \t]*", "i"),
	
	// Formats number adding ','
	formatNumber: function(n){
		var str = "";
		if(n > 0){
			while(n > 0){
				var n1 = n % 1000;
				n = (n - n1) / 1000;
				str = String(n1) + str;
				if(n > 0){
					if(n1 < 10)
						str = "00" + str;
					else if(n1 < 100)
						str = "0" + str;
					str = "," + str;
				}
			}
		}else
			str = "0";
		return str;
	},
	
	/* returns and object with properties:
	*  loc - location (integer)
	*  pos - formated position (will be changed)
	*  unit - "M", "K", or undefined (no entry)
	*  error - true if value fails validation
	* 
	*  return null if value is empty string or null
	*/
	parsePosition: function(value){
		if(value){
			var data = new Object();
			var array = ncbiformatter._positionFormat.exec(value);
			if(array && array.input == array[0]){
				data.loc = ncbiformatter._parseFloat(array[1]);
				if(array[2]){
					var unit = array[2].toUpperCase();
					data.pos = data.loc + unit;
					data.unit = unit;
					if(unit == "M")
						data.loc *= 1000000;
					else if(unit == "K")
						data.loc *= 1000;
				}else
					data.pos = data.loc;
			}else{
				if(array)
					data.value = array[0];
				data.error = true;
			}
			return data;
		}
		return null;
	},
	
	parseObjectName: function(value){
		if(value){
			var array = ncbiformatter._objectFormat.exec(value);
			if(array && array.input == array[0])
				return {value:array[1]};
			var data = {error:true};
			if(array)
				data.value = array[0];
		}
		return null;
	},
	
	// contextInfo - an object, on onput - validation mode
	// contextInfo.mode - 1: object, 0 or missing: position (i.e. a number), default
	// contextInfo.partial - true: validate while typing (for position), false (or missing): final validation (default)
	validate: function(value, contextInfo){
		if(value){
			var format = ncbiformatter._positionFormat;
			if(contextInfo && contextInfo.mode)
				format = ncbiformatter._objectFormat;
			else if(contextInfo && contextInfo.partial)
				format = ncbiformatter._positionFormat2;

			var array = format.exec(value);
			if(array){
				if(array.input == array[0])
					return true;
				else if(contextInfo)
					contextInfo.value = array[0];
			}
			return false;
		}
		return true;
	},

	// parses value with a specifier as: name[type]
	parseTypedValue: function(value){
		if(value){
			var k = value.indexOf("[");
			var l = value.length;
			var k1 = k >= 0? value.indexOf("]", k+1) : l;
			var obj = {
				value: k >= 0? value.substr(0, k) : value,
				type: (k >= 0 && k1 > k)? value.substr(k+1, k1 - k - 1) : ""
			};
			return obj;
		}
		return {value:"", type:""};
	},
	
	_parseFloat: function(str){
		var value = 0;
		if(str){
			var array = str.split(",");
			for(var n=0;n<array.length;n++)
				value = value*1000 + parseFloat(array[n]);
		}
		return value;
	}

};