/*********************************************************************************

 * Module: format.js

 *		Formatting utilities.

 *		This module includes functions to help format resulting values.

 *********************************************************************************/



 

/*********************************************************************************

 * Object: fa

 *		Functions that can be applied to DATAOBJ properties or strings

 */



var fa = {



	/*********************************************************************************

	 * Function: _r(p,r)

	 *		Determine the source text range.  This function is used by the other

	 *		functions within the fa object.  This is an internal function to the

	 *		object and should not need to be called directly.

	 * Inputs:

	 *		p:Object or String - The source range

	 *			Object: An Censoft Data Object Property.  This provides context in

	 *				case other object properties are needed in the calculation.

	 *			String: An explicit source range

	 *		r:String - Optional override for source range if an intermediate result has

	 *			has been calculated.

	 */



	_r: function(p,r) {				// Get the source value that is input to the function

		if (r == null) {

			if (p.__p) {			// Check if a data object was specified

				return Extract._xr(p);	// Get the range from the data object

			} else {

				return p;			// Use the specified range

			}

		} else {	

			return r;				// Use the specified range

		}

	},

	

	/*********************************************************************************

	 * Function: text(p,r)

	 *		Convert HTML fragment to just the visible text.  HTML tags are stripped

	 *		when generating the resulting value.

	 * Example:

	 *		fa.text("this <b>and</b> that") -> "this and that"

	 */



	text: function(p,r) {

		r = fa._r(p,r);

		return r.text(2);			// 2 indicates that <BR> tags should be used for new line characters

	},

	

	/*********************************************************************************

	 * Function: toBR(p,r)

	 */



	toBR: function(p,r) {

		r = fa._r(p,r);

		return r.Range("",Tag.BR);

	},

	

	/*********************************************************************************

	 * Function: href(p,r)

	 *		Convert URL references from relative values to absolute values.

	 *		This routine can be used to alter links so that they still work

	 *		after they are retrieved from another domain.

	 */



	href: function(p,r) {

		r = fa._r(p,r);

		if (/\s(href|HREF|src|SRC|action|ACTION)=/.test(r)) {		// Check if replacement is needed

			var baseURL = DATAOBJ.getInheritedValue(p,"$baseURL");						// Get the base URL from the web page			

			var fullURL = DATAOBJ.getInheritedValue(p,"$url2");							// for #target expansion

			r = HTML.expandRefs(r,baseURL,fullURL);

		}

		return r;

	},

	

	/*********************************************************************************

	 * Object: fa.clean

	 *		"Clean" common HTML fragments by removing extra attributes

	 */



	clean: {

	

		/*********************************************************************************

		 * Function: fa.clean.A(p,r) -> String

		 *		Rebuild A elements as "safe" links without extra attributes.

		 *		All attributes are stripped except for the href attribute.

		 *		The contents of the TAG are converted to text with all HTML tags stripped.

		 */



		A: function(p,r) {

			r = fa._r(p,r);

			var href = HTML.attribute(r,"href");		// Get the href attribute for the element

			if (/(javascript:|JAVASCRIPT:|mailto:|MAILTO:)/.test(href)) return "";

			var text = r.text();						// Get the inner text

			if (href && text) {							// Only valid if href and text specified

				href = TAG.clean.href( href );

				return TAG.make.A(href,text);

			} else {

				return "";

			}

		},



		/*********************************************************************************

		 * Function: fa.clean.IMG(p,r) -> String

		 *		Rebuild IMG elements as "safe" elements without extra attributes.

		 *		All attributes are stripped except for the src attribute

		 */



		IMG: function(p,r) {

			r = fa._r(p,r);

			var src = HTML.attribute(r,"src");

			return (src) ? "<IMG src='" + src + "'>" : "";

		},



		/*********************************************************************************

		 * Function: fa.clean.TABLE(p,r) -> String

		 *		Rebuild TABLE elements as "safe" elements without extra attributes.

		 */



		TABLE: function(p,r) {

			r = fa._r(p,r);

			return HTML.cleanTable(r);

		}

		

	}

	

}



/***************** Numeric Formatting Utilities ***************/





var NUM_FORMAT = {





	// toAddressPieces

	//  Convert a string with the following format:

	//   street address \n city, state zipcode

	//  to address pieces:

	

	toAddressPieces: function( address, fmt ) {



		address = address.text().trim();



		var sa = address.Match( /^(.+)\n/ ).trim();

		var csz = address.Range( "\n" ).trim();



		switch( fmt ) {

			case 'streetAddress':

				return sa;

			case 'city':

				return csz.Range("",",").trim();

			case 'state':

				return csz.Range(",",/\d/).trim();

			case 'zipcode':

				return csz.Match(/\d{5}/);

			case 'city_state':

				return csz.Range("",/\d/).trim();

			case 'city_state_zip':

				return csz;

		}

	},

								

	 // toXMLAddress

	 //  Convert a string with the following format:

	 //   street address \n city, state zipcode

	 //  to a string with XML tags:

	 //   <PRE><STREETADDRESS></PRE>streetAddress</STREETADDRESS><br><CITY>city</CITY><STATE>state</STATE><ZIPCODE>zipcode</ZIPCODE><COUNTRY>country</COUNTRY>

	 //  Requires input as the following format:

	 //	address = streetAddress1 + ("<br>" + streetAddress2 + "<br>" + streetAddress3) + "\n" + city + "," + state + " " + zipcode + "\n" + country;



	 toXMLAddress: function(address) {



		var streetAddress = address.Range("","\n");

		var city = address.Range("\n",",");

		var state = address.Range("\n","").Range(",","").Match(/\w{2}/);

		var zipcode = address.Range("\n","").Match(/\d{5}/);

		var country = address.Range("\n","").Range(",","").Range("\n","");		

		

		streetAddress = streetAddress ? streetAddress: "";

		city = city ? city: "";

		state = state ? state: "";

		zipcode = zipcode ? zipcode: "";

		country = country ? country: "";

		

		if ((!address) || ((!streetAddress) && (!city) && (!state) && (!zipcode) && (!country)))

			return "<PRE><STREETADDRESS></PRE></STREETADDRESS><br><CITY></CITY><STATE></STATE><ZIPCODE></ZIPCODE><br><COUNTRY></COUNTRY>";



		if (city) {

			return "<PRE><STREETADDRESS></PRE>" + streetAddress + "</STREETADDRESS>" + "<br>" + "<CITY>" + city + "</CITY>" + "," + "<STATE>" + state + "</STATE>" + " " +  "<ZIPCODE>" + zipcode + "</ZIPCODE>" + "<br>" + "<COUNTRY>" + country + "</COUNTRY>";

		}

		else {

			return "<PRE><STREETADDRESS></PRE>" + streetAddress + "</STREETADDRESS>" + "<br>" + "<CITY>" + city + "</CITY>" +  "<STATE>" + state + "</STATE>" + " " +  "<ZIPCODE>" + zipcode + "</ZIPCODE>"+ "<br>" + "<COUNTRY>" + country + "</COUNTRY>";

		}



	 },





	// ratio

	//		Returns a string representation of the ratio of two numbers

	// numerator - Number or String

	// denominator - Number or string

	// percent - Boolean - TRUE to format as a percentage

	// decimals - Number - Precision for the returned result



	ratio: function(numerator,denominator,percent,decimals) {

		if (typeof numerator == "string") numerator = parseFloat(numerator);

		if (typeof denominator == "string") denominator = parseFloat(denominator);

		if (denominator == 0 || isNaN(numerator) || isNaN(denominator)) return "";

		var r = numerator/denominator;

		if (percent) r = r * 100;

		var s = r.toString();

		if (decimals) {

			var p = s.indexOf(".");

			if (p>=0) s = s.substring(0,p+decimals+1);

		}

		if (percent) s = s + " %";

		return s;

	},



	// toNum

	//		Convert a string to a numeric value.  Looks for special characters (K, M, B) that 

	//		represent alternate units of measure (thousands, millions, billions).

	// s - String - Source value

	// format - String - Output units (K->thousands, M->millions, B->billions)



	toNum: function(s,format) {

		if (! s) return "";

		var units = 1;

		if (/k/i.test(s)) {

			units = 1000;

		} else if (/m/i.test(s)) {

			units = 1000000;

		} else if (/b/i.test(s)) {

			units = 1000000000;

		}

		var divide = 1;

		switch (format.toLowerCase()) {

		case "k":

			divide = 1000;

			break;

		case "m":

			divide = 1000000;

			break;

		case "b":

			divide = 1000000000;

			break;

		}

		num = parseFloat(s.replace(/[^\d\.]/g,""));	// Strip everything other than digits or decimal point

		return (num * units / divide).toString();

	},



	

	// Converts a integer to a phone number.

	// Still looking for any standard way to format numbers.  This is first used by Siebel.

	// Siebel passes raw phone number with no formating.

	toPhoneNum: function (phoneNum) {

		if (!phoneNum || typeof(phoneNum) == "undefined") return "";



		// get rid of any non-digits

		var pn = phoneNum.strip(/[^\d]/);



		// We assume 10 digit numbers are US.  Otherwise we need a better way to detect internatinal 10 digit 

		pn.match (/(\d\d\d)(\d\d\d)(\d\d\d\d)(.*)/);



		var areaCode = RegExp.$1;

		var prefix = RegExp.$2;

		var number = RegExp.$3;

		var ext =RegExp.$4;



		ext = ext.strip(' ');

		if (ext) {

			ext = (ext.IsStartWith('x')) ? ' ' + ext : ' x' + ext;

		}



		return ("(" + areaCode + ") " + prefix + "-" + number + ext);

	},

	

	convertMonth: function(from,toType) {

		if (! toType) toType = 1;

		var fromShort = from.substring(0,3).toLowerCase();

		var result = "";

		switch (toType) {

		case 1:	// Convert to "1".."12"

			switch (fromShort) {

			case "dec": return "12";

			case "nov": return "11";

			case "oct": return "10";

			case "sep": return "9";

			case "aug": return "8";

			case "jul": return "7";

			case "jun": return "6";

			case "may": return "5";

			case "apr": return "4";

			case "mar": return "3";

			case "feb": return "2";

			case "jan": return "1";

			default: return "";

			}

			break;

		case 2:

			break;

		case 3:

			break;

		}

		return result;

	}

	

}



/*********************************************************************************

 * Object: sort

 *		Sorting utilities

 */



var SORT = {

	

	byValue: function(a,b) { // Sort function that can handle numbers and strings

		if (typeof a[0] == "number" && typeof b[0] == "number") {

			return a[0]-b[0];

		} else {

			return (a[0] < b[0]) ? -1 : 1;

		}

	},

	

	byProp: function(a,b) {	// Sort function for objects that have a property named "sort"

		a = a.sort;

		b = b.sort;

		if (a < b) {

			return -1;

		} else if (a > b) {

			return 1;

		} else {

			return 0;

		}

	}	

}



/*********************************************************************************

 * Object: SEARCH_FORMAT

 *		Format routine for search results

 */



var SEARCH_FORMAT = {

	format: function(num,url) {

		var r = "";

		if (num > "1") {				

			r = num + " 条搜索结果来自 " + url;

		}

		else if (num == "-1") {				

			r = "更多搜索结果来自 " + url;

		}

		else if (num == "1") {				

			r = "1 条搜索结果来自 " + url;

		} else {

			r = "没有搜索到任何匹配结果。";

		}

		return r;

	}

}


