/*****************************************************************************************
 *   Stingray Engineering::Spotlight JS Client
 *      javascript library for the thomson reuters spotlight data service.
 *      this library supports cross-domain communication and provides default 
 *      rendering of the data as well as a plugable rendering framework
 *****************************************************************************************/

// ******* top level namespace and "static" utility functions *******
var spotlight = {};

// ensure a namespace exists
spotlight.ensureNamespace = function( ns ) {
	if (ns != null && ns.length>0) {
		var levels = ns.split(".");
		var currentNS = spotlight;
		var start = (levels[0] == 'spotlight') ? 1 : 0;
		for (var i=start; i<levels.length; i++) {
			currentNS[levels[i]] = currentNS[levels[i]] || {};
			currentNS = currentNS[levels[i]];
		}
		return currentNS;
	} else {
		return null;
	}
}
// manages a script block in the HEAD of the doc
spotlight.ensureScript = function(id, url) {
	if ( id != null && url != null && url.length > 0 ) {
		var head = document.getElementsByTagName("head")[0];
		var script = document.getElementById(id);
		if (script != null) {
			head.removeChild(script);
		}
		script = document.createElement('script');
		if ( id != null ) {
			script.id = id;
		}
		script.type = 'text/javascript';
		script.src = url;
		head.appendChild(script)
	}
}

// the spotlight namespaces
spotlight.ensureNamespace('spotlight');
spotlight.ensureNamespace('spotlight.data');
spotlight.ensureNamespace('spotlight.dhtml');
spotlight.ensureNamespace('spotlight.dhtml.renderers');


// ******* spotlight base data list manager *******
spotlight.data.listManagerBase = function(id, apiKey, ulClass, liClass, showDescription, descriptionLength) {
	if ( arguments.length > 0 ) {
		this.init(id, apiKey, ulClass, liClass, showDescription, descriptionLength);
	}
}
spotlight.data.listManagerBase.prototype.init = function(id, apiKey, ulClass, liClass, showDescription, descriptionLength) {
	this.id = id;
	this.apiKey = apiKey;
	this.listClass = ulClass;
	this.itemClass = liClass;
	this.showDescription = (showDescription==null) ? false : showDescription;
	this.descriptionLength = (descriptionLength==null) ? -1 : descriptionLength;
	this.baseUrl = 'http://spotlight.reuters.com/api';
	this.apiType = 'feed';
	this.channel = null;
	this.edition = null;
	this.parms = null;
	this.feedType = null;
	this.renderer = null;
	this.onWriteDataCallback = null;
	this.localStoragePrefix = "spotlight.data.newsManager." + this.id + '.';
	this.useLocalStorage = false;
	this.refreshFrequency = 0;
	this.lastUpdateDate = null;
}
// get data from the spotlight services
spotlight.data.listManagerBase.prototype.getData = function(edition, channel) {
	var args = Array.prototype.slice.call(arguments);
	var parms = args.splice(2,args.length-1);
	if ( edition != null ) this.edition = edition;
	if ( channel != null ) this.channel = channel;
	if ( parms != null && parms.length > 0 ) this.parms = parms;
	if ( this.useLocalStorage ) {
		var json_data = localStorage.getItem(this.getLocalStorageKey());
		var updated =   localStorage.getItem(this.getLocalStorageKey()+'_lastUpdate');
		if ( updated != null ) {
			this.lastUpdateDate = new Date(parseInt(updated));
		}
		if(json_data == null){
			spotlight.ensureScript(this.id + '_script', this.buildUrl(parms));
		}else{
			this.writeData(JSON.parse(json_data), true);
			var updateMe = 'spotlight.ensureScript(\'' + this.id + '_script\', \'' + this.buildUrl(parms) + '\');';
			if ( this.refreshFrequency > 0 ) {
				window.setInterval(updateMe, this.refreshFrequency);
			} else {
				window.setTimeout(updateMe, 300);
			}
		}
	} else {
		spotlight.ensureScript(this.id + '_script', this.buildUrl(parms));
	}
}
// get local storage key
spotlight.data.listManagerBase.prototype.getLocalStorageKey = function() {
	return this.localStoragePrefix + this.edition + '.' + this.channel;
}
// build the spotlight url
spotlight.data.listManagerBase.prototype.buildUrl = function(params) {
	var url = '';
	if ( this.edition != null && this.channel != null && this.feedType != null && this.apiKey != null && this.apiKey.length > 0) {
		url += this.baseUrl + '/' + this.apiType + '/' + this.edition + '/' + this.feedType;
		url += '/' + this.channel + '/json?apikey=' + this.apiKey;
		url += '&callback=' + escape(this.id + '.writeData');
	}
	url += this.buildUrlParams(params);
	return url;
}
spotlight.data.listManagerBase.prototype.buildUrlParams = function(params) {
	var url = '';
	for( var i=0; i<params.length; i++ ) {
		url += '&' + params[i].name + '=' + params[i].val
	}
	return url;
}
// write the data returned from the spotlight services
spotlight.data.listManagerBase.prototype.writeData = function(data, fromCache) {
	var elem = document.getElementById(this.id);
	if ( elem != null ) {
		if ( this.preProcess(elem, data) ) {
			this.renderer = this.getRenderer(data);
			if ( this.renderer != null ) {
				this.renderer.render(elem);
			} else {
				alert('Error: spotlight.data.listManagerBase.getRenderer returned null, please provide an implementation');
			}
		}
		this.postProcess(elem, data);
		if ( this.useLocalStorage ) {
			try {  
				var json_str = JSON.stringify(data);
				localStorage.setItem(this.getLocalStorageKey(), json_str);
			} catch(err){ alert(err); }
			if ( fromCache != true ) {
				this.lastUpdateDate = new Date();
				localStorage.setItem(this.getLocalStorageKey()+'_lastUpdate', this.lastUpdateDate.getTime());
			}
		}
		if (this.onWriteDataCallback != null) {
			this.onWriteDataCallback.call(this, data);
		}
	}
}
// get renderer
spotlight.data.listManagerBase.prototype.getRenderer = function(data) {
	return new spotlight.dhtml.renderers.baseListRenderer(this.id, data, this.listClass, this.itemClass, this.showDescription, this.descriptionLength);
}
// write select handler attribute
spotlight.data.listManagerBase.prototype.handleSelect = function(itemData) {
	if (this.selectItemFunc != null) {
		this.selectItemFunc.call(this, itemData);
	}
}
// pre processing default imp - return false to prevent rendering chain
spotlight.data.listManagerBase.prototype.preProcess = function(elem, data) {
	return true;
}
// abstract method, post processing
spotlight.data.listManagerBase.prototype.postProcess = function(elem, data) {}


// ******* base list manager for services *******
spotlight.data.serviceListManagerBase = function(id, apiKey, ulClass, liClass) {
	if ( arguments.length > 0 ) {
		this.init(id, apiKey, ulClass, liClass);
	}
}
spotlight.data.serviceListManagerBase.prototype = new spotlight.data.listManagerBase();
spotlight.data.serviceListManagerBase.superclass = spotlight.data.listManagerBase.prototype;
spotlight.data.serviceListManagerBase.prototype.init = function(id, apiKey, ulClass, liClass) {
	spotlight.data.serviceListManagerBase.superclass.init.call(this, id, apiKey, ulClass, liClass, null, null);
	this.apiType = 'service';
}
spotlight.data.serviceListManagerBase.prototype.getData = function() {
	spotlight.ensureScript(this.id + '_script', this.buildUrl(Array.prototype.slice.call(arguments)));
}
spotlight.data.serviceListManagerBase.prototype.buildUrl = function(params) {
	var url = '';
	if (this.feedType != null && this.apiKey != null && this.apiKey.length > 0) {
		url += this.baseUrl + '/' + this.apiType + '/' + this.feedType;
		url += '?apikey=' + this.apiKey + '&callback=' + escape(this.id + '.writeData') + '&format=json';
	}
	url += this.buildUrlParams(params);
	return url;
}


// ******* channel news headline list manager *******
spotlight.data.newsManager = function(id, apiKey, ulClass, liClass, showDescription, descriptionLength) {
	if ( arguments.length > 0 ) {
		this.init(id, apiKey, ulClass, liClass, showDescription, descriptionLength);
	}
}
spotlight.data.newsManager.prototype = new spotlight.data.listManagerBase();
spotlight.data.newsManager.superclass = spotlight.data.listManagerBase.prototype;
spotlight.data.newsManager.prototype.init = function(id, apiKey, ulClass, liClass, showDescription, descriptionLength) {
	spotlight.data.newsManager.superclass.init.call(this, id, apiKey, ulClass, liClass, showDescription, descriptionLength);
	this.feedType = 'channelnews';
}


// ******* channel photo list manager *******
spotlight.data.photoManager = function(id, apiKey, ulClass, liClass, showDescription, descriptionLength) {
	if ( arguments.length > 0 ) {
		this.init(id, apiKey, ulClass, liClass, showDescription, descriptionLength);
	}
}
spotlight.data.photoManager.prototype = new spotlight.data.listManagerBase();
spotlight.data.photoManager.superclass = spotlight.data.listManagerBase.prototype;
spotlight.data.photoManager.prototype.init = function(id, apiKey, ulClass, liClass, showDescription, descriptionLength) {
	spotlight.data.photoManager.superclass.init.call(this, id, apiKey, ulClass, liClass, showDescription, descriptionLength);
	this.feedType = 'channelphotos';
	this.currentItemIndex = 0; // tracking of a currently selected/displayed item
	this.items = null;  // data items
}
spotlight.data.photoManager.prototype.getRenderer = function(data) {
	return new spotlight.dhtml.renderers.photoListRenderer(this.id, data, this.listClass, this.itemClass, this.showDescription, this.descriptionLength);
}
spotlight.data.photoManager.prototype.postProcess = function(elem, data) {
	this.items = (data!=null) ? data.items : null;
	this.currentItemIndex = 0;
	this.showCurrentItem();
}
// image display control
spotlight.data.photoManager.prototype.previous = function() {
	if ( this.items != null ) {
		if ( this.currentItemIndex>0 ) {
			this.currentItemIndex--;
		} else {
			this.currentItemIndex = 0;
		}
		this.showCurrentItem();
	}
}
spotlight.data.photoManager.prototype.next = function() {
	if ( this.items != null ) {
		if ( this.currentItemIndex<(this.items.length-1) ) {
			this.currentItemIndex++;
		} else {
			this.currentItemIndex = this.items.length-1;
		}
		this.showCurrentItem();
	}
}
spotlight.data.photoManager.prototype.begin = function() {
	if ( this.items != null ) {
		this.currentItemIndex = 0;
		this.showCurrentItem();
	}
}
spotlight.data.photoManager.prototype.end = function() {
	if ( this.items != null ) {
		this.currentItemIndex = this.items.length-1
		this.showCurrentItem();
	}
}
spotlight.data.photoManager.prototype.showCurrentItem = function() {
	for(var i=0; i<this.items.length; i++ ) {
		var elem = document.getElementById(this.id + '_' + i);
		if ( elem != null ) {
			if ( i == this.currentItemIndex ) {
				elem.style.display = '';
			} else {
				elem.style.display = 'none';
			}
		}
	}
}


// ******* quote list manager *******
spotlight.data.quoteListManager = function(id, apiKey, ulClass, liClass, shellClass, descriptionLength) {
	if ( arguments.length > 0 ) {
		this.init(id, apiKey, ulClass, liClass, shellClass, descriptionLength);
	}
}
spotlight.data.quoteListManager.prototype = new spotlight.data.serviceListManagerBase();
spotlight.data.quoteListManager.superclass = spotlight.data.serviceListManagerBase.prototype;
spotlight.data.quoteListManager.prototype.init = function(id, apiKey, ulClass, liClass, shellClass, descriptionLength) {
	spotlight.data.quoteListManager.superclass.init.call(this, id, apiKey, ulClass, liClass);
	this.shellClass = shellClass;
	this.descriptionLength = descriptionLength;
	this.feedType = 'quote';
}
spotlight.data.quoteListManager.prototype.getRenderer = function(data) {
	return new spotlight.dhtml.renderers.quoteListRenderer(this.id, data, this.listClass, this.itemClass, this.shellClass, this.descriptionLength);
}


// ******* lookup manager *******
spotlight.data.lookupManager = function(id, apiKey, ulClass, liClass, shellClass, descriptionLength) {
	if ( arguments.length > 0 ) {
		this.init(id, apiKey, ulClass, liClass, shellClass, descriptionLength);
	}
}
spotlight.data.lookupManager.prototype = new spotlight.data.serviceListManagerBase();
spotlight.data.lookupManager.superclass = spotlight.data.serviceListManagerBase.prototype;
spotlight.data.lookupManager.prototype.init = function(id, apiKey, ulClass, liClass, shellClass, descriptionLength) {
	spotlight.data.quoteListManager.superclass.init.call(this, id, apiKey, ulClass, liClass);
	this.shellClass = shellClass;
	this.descriptionLength = descriptionLength;
	this.feedType = 'lookup';
	this.autoSelectSymbol = null;
	this.autoSelectFunc = null;
	this.selectItemFunc = null;
}
// get renderer
spotlight.data.lookupManager.prototype.getRenderer = function(data) {
	return new spotlight.dhtml.renderers.lookupRenderer(this.id, data, this.listClass, this.itemClass, this.shellClass, this.descriptionLength, this.selectItemFunc);
}
// if single result, no render, just fire selected event
spotlight.data.lookupManager.prototype.preProcess = function(elem, data) {
	if ( data != null && data.results != null && data.results.length == 1 ) {
		this.autoSelectSymbol = data.results[0].ric;
		return false;
	} else {
		this.setDisplay('block', elem);
		return true;
	}
}
spotlight.data.lookupManager.prototype.setDisplay = function(display, elem) {
	if ( elem == null ) elem = document.getElementById(this.id);
	if ( elem != null ) elem.style.display = display;
}
// process the case of single symbol
spotlight.data.lookupManager.prototype.postProcess = function(elem, data) {
	if (this.autoSelectSymbol != null) {
		if ( this.autoSelectFunc != null ) {
			this.autoSelectFunc.call(this, this.autoSelectSymbol);
		}
		this.autoSelectSymbol = null;
	}
}


// ******* singular quote manager *******
spotlight.data.quoteManager = function(id, apiKey) {
	if ( arguments.length > 0 ) {
		this.init(id, apiKey);
	}
}
spotlight.data.quoteManager.prototype = new spotlight.data.quoteListManager();
spotlight.data.quoteManager.superclass = spotlight.data.quoteListManager.prototype;
// get renderer
spotlight.data.quoteManager.prototype.getRenderer = function(data) {
	return new spotlight.dhtml.renderers.singleQuoteRenderer(this.id, data);
}


// ******* base dhtml widget *******
spotlight.dhtml.widgetBase = function(id) {
	if ( arguments.length > 0 ) {
		this.init(id);
	}
}
// initialise base widget
spotlight.dhtml.widgetBase.prototype.init = function(id) {
	this.id = id;
}
// swap a css class - takes class attrib string, returns new class attrib string
spotlight.dhtml.widgetBase.prototype.swapCssClass = function(classAttrib, srcClass, destClass) {
	var retClass = '';
	if ( classAttrib != null && classAttrib.length>0 ) {
		if ( srcClass != null && srcClass.length>0 && classAttrib.indexOf(srcClass) > -1 ) {
			retClass = classAttrib.replace( srcClass, destClass );
		} else {
			retClass = classAttrib  + ' ' + destClass;
		}
	} else {
		retClass = destClass;
	}
	return retClass;
}


// ******* tab pane control widget - generic tab/pane view management *******
spotlight.dhtml.pane = function(id, tabCssClass, tabCssClassSelected, contentCssClass, contentCssClassSelected) {
	if ( arguments.length > 0 ) {
		this.init(id, tabCssClass, tabCssClassSelected, contentCssClass, contentCssClassSelected);
	}
}
spotlight.dhtml.pane.prototype = new spotlight.dhtml.widgetBase();
spotlight.dhtml.pane.superclass = spotlight.dhtml.widgetBase.prototype;
spotlight.dhtml.pane.prototype.init = function(id, tabCssClass, tabCssClassSelected, contentCssClass, contentCssClassSelected) {
	spotlight.dhtml.pane.superclass.init.call(this, id);
	this.tabCssClass = tabCssClass;
	this.tabCssClassSelected = tabCssClassSelected;
	this.contentCssClass = contentCssClass;
	this.contentCssClassSelected = contentCssClassSelected;
	this.defaultTabIndex = 0;
}
// add a "tab/pane" to the collection
spotlight.dhtml.pane.prototype.addTab = function(tabId, contentId) {
	if ( this.tabs == null ) this.tabs = new Array();
	var tabObj = new Object();
	tabObj.id = tabId;
	tabObj.contentId = contentId;
	this.tabs[this.tabs.length] = this.tabs[tabId] = tabObj;
}
// change the current tab
spotlight.dhtml.pane.prototype.changeTab = function(tabId) {
	if ( this.tabs != null && this.tabs[tabId] != null) {
		var newTab = this.tabs[tabId];
		for ( var i=0; i < this.tabs.length; i++ ) {
			var elem = document.getElementById(this.tabs[i].id);
			elem.className = this.swapCssClass(elem.className, this.tabCssClassSelected, this.tabCssClass);
			var cElem = document.getElementById(this.tabs[i].contentId);
			if ( this.contentCssClass != null ) {
				cElem.className = this.swapCssClass(cElem.className, this.contentCssClassSelected, this.contentCssClass);
			} else {
				cElem.style.display = 'none';
			}
		}
		var newElem = document.getElementById(newTab.id);
		newElem.className = this.swapCssClass(newElem.className, this.tabCssClass, this.tabCssClassSelected);
		var ncElem = document.getElementById(newTab.contentId);
		if ( this.contentCssClassSelected != null ) {
			ncElem.className = this.swapCssClass(cElem.className, this.contentCssClass, this.contentCssClassSelected);
		} else {
			ncElem.style.display = '';
		}
	}
}
// show the default tab
spotlight.dhtml.pane.prototype.showDefaultTab = function() {
	if (this.tabs != null && this.tabs[this.defaultTabIndex] != null) {
		this.changeTab(this.tabs[this.defaultTabIndex].id);
	}
}


// ******* base renderer *******
spotlight.dhtml.renderers.baseRenderer = function(id, data) {
	if ( arguments.length > 0 ) {
		this.init(id, data);
	}
}
spotlight.dhtml.renderers.baseRenderer.prototype.init = function(id, data) {
	this.id = id;
	this.data = data;
}
// hasData method default imp
spotlight.dhtml.renderers.baseRenderer.prototype.hasData = function() {
	return (this.data != null);
}
// apply data
spotlight.dhtml.renderers.baseRenderer.prototype.applyData = function(rootId, dataItem) {
	for ( var field in dataItem ) {
		if (document.getElementById(rootId + '_' + field) != null ) {
			document.getElementById(rootId + '_' + field).innerHTML = dataItem[field];
		}
	}
}
// abstract method, render
spotlight.dhtml.renderers.baseRenderer.prototype.render = function() {
	if ( this.hasData() ) {
		var item = this.getData();
		this.applyData(this.getItemKey(item), item);
	}
}
// abstract method, get data item key
spotlight.dhtml.renderers.baseRenderer.prototype.getItemKey = function(itemData) {}


// ******* single quote renderer *******
spotlight.dhtml.renderers.singleQuoteRenderer = function(id, data) {
	if ( arguments.length > 0 ) {
		this.init(id, data);
	}
}
spotlight.dhtml.renderers.singleQuoteRenderer.prototype = new spotlight.dhtml.renderers.baseRenderer();
spotlight.dhtml.renderers.singleQuoteRenderer.superclass = spotlight.dhtml.renderers.baseRenderer.prototype;
spotlight.dhtml.renderers.singleQuoteRenderer.prototype.hasData = function() {
	return ( this.data != null && this.data.quotes != null && this.data.quotes.length > 0 ); 
}
spotlight.dhtml.renderers.singleQuoteRenderer.prototype.getData = function() {
	return this.data.quotes[0]; 
}
spotlight.dhtml.renderers.singleQuoteRenderer.prototype.getItemKey = function(item) {
	return this.id; 
}


// ******* base list renderer *******
spotlight.dhtml.renderers.baseListRenderer = function(id, data, listClass, itemClass, showDescription, descriptionLength) {
	if ( arguments.length > 0 ) {
		this.init(id, data, listClass, itemClass, showDescription, descriptionLength);
	}
}
spotlight.dhtml.renderers.baseListRenderer.prototype = new spotlight.dhtml.renderers.baseRenderer();
spotlight.dhtml.renderers.baseListRenderer.superclass = spotlight.dhtml.renderers.baseRenderer.prototype;
spotlight.dhtml.renderers.baseListRenderer.prototype.init = function(id, data, listClass, itemClass, showDescription, descriptionLength) {
	spotlight.dhtml.renderers.baseListRenderer.superclass.init.call(this, id, data);
	this.listClass = listClass;
	this.itemClass = itemClass;
	this.listElem = 'ul';
	this.itemElem = 'li';
	this.showDescription = (showDescription==null) ? false : showDescription;
	this.descriptionLength = (descriptionLength==null) ? -1 : descriptionLength;
	this.groupComparerFunc = null;
	this.groupAfterItems = false;
}
// render the list into the supplied elem
spotlight.dhtml.renderers.baseListRenderer.prototype.render = function(elem) {
	var html = '';
	if ( this.hasData() ) {
		var items = this.getDataItems();
		html += '<' + this.listElem + ' class=\"' + this.listClass + '\">';
		for( var i=0; i<items.length; i++ ) {
			html += '<' + this.itemElem + ' id=\"' + this.id + "_" + i + '\" class=\"' + this.itemClass + '\">';
			html += this.renderItem(items[i]);
			html += '</' + this.itemElem + '>';
		}
		html += '</' + this.listElem + '>';
	}
	elem.innerHTML = html;
}
// get the items to iterate over
spotlight.dhtml.renderers.baseListRenderer.prototype.getDataItems = function() {
	return this.data.items;
}
// render a single item in the list
spotlight.dhtml.renderers.baseListRenderer.prototype.renderItem = function(item) {
	var html = '';
	html += '<a href=\"' + item.link + '\">';
	html += item.title;
	html += '</a><br/>';
	if ( this.showDescription ) {
		html += (this.descriptionLength>0 && item.description!=null) ? item.description.substring(0, this.descriptionLength) + '...' : item.description;
	}
	return html;
}


// ******* photo list renderer *******
spotlight.dhtml.renderers.photoListRenderer = function(id, data, listClass, itemClass, showDescription, descriptionLength) {
	if ( arguments.length > 0 ) {
		this.init(id, data, listClass, itemClass, showDescription, descriptionLength);
	}
}
spotlight.dhtml.renderers.photoListRenderer.prototype = new spotlight.dhtml.renderers.baseRenderer();
spotlight.dhtml.renderers.photoListRenderer.superclass = spotlight.dhtml.renderers.baseRenderer.prototype;
spotlight.dhtml.renderers.photoListRenderer.prototype.init = function(id, data, listClass, itemClass, showDescription, descriptionLength) {
	spotlight.dhtml.renderers.photoListRenderer.superclass.init.call(this, id, data, listClass, itemClass, showDescription, descriptionLength);
	this.listElem = 'div';
	this.itemElem = 'div';
}
spotlight.dhtml.renderers.photoListRenderer.prototype.renderItem = function(item) {
	var html = '';
	html += '<a href=\"' + item.link + '\">';
	html += '<span>' + item.title + '</span>';
	html += '<img src=\"' + item.link + '\"';
	if ( this.showDescription ) {
		html += ' alt=\"' + ((this.descriptionLength>0 && item.description!=null) ? item.description.substring(0, this.descriptionLength) + '...' : item.description) + '\"';
	}
	html += ' />';
	html += '</a>';
	return html;
}


// ******* base tabular renderer *******
spotlight.dhtml.renderers.baseTabularRenderer = function(id, data, listClass, itemClass, shellClass, selectItemFunc) {
	if ( arguments.length > 0 ) {
		this.init(id, data, listClass, itemClass, shellClass, selectItemFunc);
	}
}
spotlight.dhtml.renderers.baseTabularRenderer.prototype = new spotlight.dhtml.renderers.baseRenderer();
spotlight.dhtml.renderers.baseTabularRenderer.superclass = spotlight.dhtml.renderers.baseRenderer.prototype;
spotlight.dhtml.renderers.baseTabularRenderer.prototype.init = function(id, data, listClass, itemClass, shellClass, selectItemFunc) {
	spotlight.dhtml.renderers.baseTabularRenderer.superclass.init.call(this, id, data, listClass, itemClass);
	this.listClass = listClass;
	this.itemClass = itemClass;
	this.shellClass = shellClass;
	this.selectItemFunc = selectItemFunc;
	this.listElem = 'tr';
	this.itemElem = 'td';
	this.shellElem = 'table';
	this.shellAttribs = {cellpadding : 0, cellspacing : 1, border : 0};
}
spotlight.dhtml.renderers.baseTabularRenderer.prototype.render = function(elem) {
	var html = '';
	if ( this.hasData() ) {
		html += '<' + this.shellElem + ' class=\"' + this.shellClass + '\" ' + this.renderAttribs() + '>';
		html += this.renderRows()
		html += '</' + this.shellElem + '>';
	}// else ??
	elem.innerHTML = html;
}
// write extra attributes
spotlight.dhtml.renderers.baseTabularRenderer.prototype.renderAttribs = function() {
	var attribs = '';
	for (var attrib in this.shellAttribs) {
		attribs += attrib + '=\"' + this.shellAttribs[attrib] + '\" ';
	}
	return attribs;
}
// loop over row data and render
spotlight.dhtml.renderers.baseTabularRenderer.prototype.renderRows = function() {
	var html = '';
	var things = this.getDataItems();
	for( var i=0; i < things.length; i++ ) {
		html += '<' + this.listElem + ' class=\"' + this.listClass + ((i%2 == 0) ? ' even' : ' odd') + '\" ' + this.renderSelectHandler(things[i]) + '>';
		html += this.renderRow(things[i]);
		html += '</' + this.listElem + '>';
	}
	return html;
}
// write select handler attribute
spotlight.dhtml.renderers.baseTabularRenderer.prototype.renderSelectHandler = function(dataItem) {
	var attribs = '';
	attribs += 'onclick=\"' + this.id + '.handleSelect(\'' + this.getItemKey(dataItem) + '\');\" ';
	return attribs;
}
// render the item (cell)
spotlight.dhtml.renderers.baseTabularRenderer.prototype.renderItem = function(id, val) {
	var html = '';
	html += '<' + this.itemElem + ' class=\"' + this.itemClass + '\">';
	html += val;
	html += '</' + this.itemElem + '>';
	return html;
}
// abstract method, render row items
spotlight.dhtml.renderers.baseTabularRenderer.prototype.renderRow = function(itemData) {}


// ******* quote list renderer *******
spotlight.dhtml.renderers.quoteListRenderer = function(id, data, listClass, itemClass, shellClass, selectItemFunc, descriptionLength) {
	if ( arguments.length > 0 ) {
		this.init(id, data, listClass, itemClass, shellClass, selectItemFunc, descriptionLength);
	}
}
spotlight.dhtml.renderers.quoteListRenderer.prototype = new spotlight.dhtml.renderers.baseTabularRenderer();
spotlight.dhtml.renderers.quoteListRenderer.superclass = spotlight.dhtml.renderers.baseTabularRenderer.prototype;
spotlight.dhtml.renderers.quoteListRenderer.prototype.init = function(id, data, listClass, itemClass, shellClass, selectItemFunc, descriptionLength) {
	spotlight.dhtml.renderers.quoteListRenderer.superclass.init.call(this, id, data, listClass, itemClass, shellClass, selectItemFunc);
	this.descriptionLength = descriptionLength;
}
spotlight.dhtml.renderers.quoteListRenderer.prototype.getDataItems = function() {
	return this.data.quotes;
}
spotlight.dhtml.renderers.quoteListRenderer.prototype.hasData = function() {
	return ( this.data != null && this.data.quotes != null && this.data.quotes.length > 0 ); 
}
spotlight.dhtml.renderers.quoteListRenderer.prototype.renderRow = function(itemData) {
	var html = '';
	var key = this.getItemKey(itemData);
	html += this.renderItem(key + '_ric', itemData.ric);
	html += this.renderItem(key + '_name', (itemData.name.length > this.descriptionLength) ? itemData.name.substring(0, this.descriptionLength) + '...' : itemData.name);
	html += this.renderItem(key + '_last', itemData.last);
	html += this.renderItem(key + '_percentchange', itemData.percentchange);
	return html;
}
spotlight.dhtml.renderers.quoteListRenderer.prototype.getItemKey = function(item) {
	return this.id + '_' + item.ric; 
}


// ******* lookup result list renderer *******
spotlight.dhtml.renderers.lookupRenderer = function(id, data, listClass, itemClass, shellClass, selectItemFunc, descriptionLength) {
	if ( arguments.length > 0 ) {
		this.init(id, data, listClass, itemClass, shellClass, selectItemFunc, descriptionLength);
	}
}
spotlight.dhtml.renderers.lookupRenderer.prototype = new spotlight.dhtml.renderers.baseTabularRenderer();
spotlight.dhtml.renderers.lookupRenderer.superclass = spotlight.dhtml.renderers.baseTabularRenderer.prototype;
spotlight.dhtml.renderers.lookupRenderer.prototype.init = function(id, data, listClass, itemClass, shellClass, selectItemFunc, descriptionLength) {
	spotlight.dhtml.renderers.lookupRenderer.superclass.init.call(this, id, data, listClass, itemClass, shellClass, selectItemFunc);
	this.descriptionLength = descriptionLength;
}
spotlight.dhtml.renderers.lookupRenderer.prototype.getDataItems = function() {
	return this.data.results;
}
spotlight.dhtml.renderers.lookupRenderer.prototype.hasData = function() {
	return ( this.data != null && this.data.results != null && this.data.results.length > 0 ); 
}
spotlight.dhtml.renderers.lookupRenderer.prototype.renderRow = function(itemData) {
	var html = '';
	var key = this.getItemKey(itemData);
	html += this.renderItem(key + '_ric', itemData.ric);
	html += this.renderItem(key + '_name', (itemData.name.length > this.descriptionLength) ? itemData.name.substring(0, this.descriptionLength) + '...' : itemData.name);
	html += this.renderItem(key + '_exchangename', (itemData.exchangename.length > this.descriptionLength) ? itemData.exchangename.substring(0, this.descriptionLength) + '...' : itemData.exchangename);
	return html;
}
spotlight.dhtml.renderers.lookupRenderer.prototype.getItemKey = function(item) {
	return this.id + '_' + item.ric; 
}
