/** file: Printer.js
 *  Purpose: converts objects into html.
 *  Example Usage: 
 *  	new Printer().str(myObject)
 *  Good points: passing a Printer object in to another method 
 *  allows custom tweaking of the html in a modular fashion.
 */

function Printer() {
	

	/**
	 * Ported from StrUtils.java
	 * @param x
	 * @param n
	 * @return x to n significant figures
	 */
	this.toNSigFigs = function(x, n) {
		assert(n > 0);
		var sign = x < 0 ? "-" : "";
		var v = Math.abs(x);
		var lv = Math.floor(Math.log(v)/Math.log(10));
		var keeper = Math.pow(10, n - 1);
		var tens = Math.pow(10, lv);
		var keepMe = Math.round(v * keeper / tens);
		// avoid scientific notation for fairly small decimals
		if (lv < 0) {
			var s = this.toNSigFigs2_small(n, sign, lv, keepMe);
			if (s != null) return s;
		}
		var vt = keepMe * tens / keeper;
		var num = ""+vt;
		return sign + num;
	};
	
	this.toNSigFigs2_small = function(n, sign, lv, keepMe) {
		// use scientific notation for very small
		if (lv < -8) return null;
		var sb = ""+sign;
		var zs = -lv;
		var sKeepMe = ""+keepMe;
		if (sKeepMe.length > n) {
			assert(sKeepMe.charAt(sKeepMe.length - 1) == '0');
			// we've rounded up from 9 to 10, so lose a decimal place
			zs--;
			sKeepMe = sKeepMe.substring(0, sKeepMe.length() - 1);
			if (zs == 0) { 
				return null;
			}
		}
		sb += "0.";
		for (var i = 1; i < zs; i++) {
			sb += '0';
		}
		sb += sKeepMe;
		return sb;
	};


	/**
	 * A simple but useful toString for javascript objects.
	 * TODO probably a json ouput would be better here.
	 */
	this.str = function(object, seen) {	
		if (!object) return "";
		if (typeof(object)=="string") return object;
		if (typeof(object)=="number") return this.toNSigFigs(object, 3);
		if (typeof(object)=="boolean") return ""+object;
		
		
		if ( ! seen) seen = [];
		// avoid loops
		if (seen.indexOf(object) != -1) {
			if (seen[0] == object) return "this";
			return ""+(object.id || object.name || object);
		}
		seen.push(object);
		// array or array-like?
		if (object.length !== undefined) {
			var s = "[";
			for(var i=0; i<object.length; i++) {
				s += this.str(object[i], seen);
				if (i<object.length-1) s += ", ";
			}
			s += "]";
			return s;
		}
		// object or map
		var s = typeof(object)=='object'? "{" : typeof(object)+"{";
		for(var p in object) {
			s += this.str(p, seen)+":"+this.str(object[p], seen)+", ";			
		}
		if (s.length>2) s = s.substring(0, s.length-2);
		s += "}";
		return s;
	};
	
	/**
	 * Convert user text (eg a tweet) into html.
	 * Performs a clean, converts links
	 */
	this.textToHtml = function (contents, context) {		
		// TODO convert @you #tag and links ??emoticons -- See TwitterPlugin
		contents = clean(contents);
		// normalise whitespace TODO paragraphs & linebreaks?
		contents = contents.replace(/\s+/g," ");
		// convert & > into html entities (but protect &s in urls)
		contents = contents.replace(/ & /g," &amp; ");
		contents = contents.replace(/ < /g," &lt; ");
		contents = contents.replace(/ > /g," &gt; ");
		// links
		contents = contents.replace(URL_REGEX, "<a href='$1' target='_blank' rel='nofollow'>$1</a>");
		// TODO break-up over-long urls?
		// @username to their profile page
		var service = context && context.service? context.service : 'twitter';  
		contents = contents.replace(AT_YOU_SIR, "$1<a href='/profile?xid=$2%40"+service+"'>@$2</a>");
		// hashtag to a twitter search
		contents = contents.replace(HASHTAG, "$1<a href='/stream?"+Fields.SEARCH_TERM+"=%23$2'>#$2</a>");
		// a bit of markdown/email-markup TODO use a fully-fledged markdown converter??
		contents = contents.replace(/(^|\s)\*(\w+|\w.+?\w)\*($|\s)/g, "$1<i>*$2*</i>$3");
		contents = contents.replace(/(^|\s)_(\w+|\w.+?\w)_($|\s)/g, "$1<i>_$2_</i>$3");
		// correct for common numpty errors, such as encoded <b> or <i> tags
		contents = contents.replace(/&lt;(\/?[biBI])&gt;/g, "<$1>");		
		// ?? special effects, e.g. logos or emoticons?
		return contents;
	};
}

/** Default Printer -- can be replaced. */
var printer = new Printer();

