﻿/***************************************************************
 *
 *		Poor Man's Publisher (PiMP v1.00.01)
 *		Brian Schwinn (brain) - stringrayengineering.com
 *
 ***************************************************************
 *
 *		The Poor Man's Publisher, or PiMP system is a simple, yet flexible "content" management system which requires
 *		no server side support.
 *
 *		The PiMP "database" can be broken down into three main entities, all of which are simply 
 *		javascript associative arrays, these are:  LISTS, ITEMS and FIELDS (think tables, rows and columns)
 *
 *			 - a list (table) is simply a collection of items (rows)
 *			 - an item (row) is a collection of fields (columns)
 *
 ***************************************************************
 *		1...PMP data format (a list looks like this):
 ***************************************************************
 *
 *		var <<list id>> = { 
 *			<<item 1 id>> : {	// if specified, useful for quick id lookups
 *				<<field 1 name>> : '<<value of field 1>>';
 *				...
 *				<<field n name>> : '<<value of field n>>';
 *			},
 *			<<item 2 id>> : {
 *				<<field 1 name>> : '<<value of field 1>>';
 *				...
 *				<<field n name>> : '<<value of field 2>>';
 *			}
 *		}
 *
 *		...to be more specific...
 *
 *		var myArticleList = { 
 *			'article_2345' : {			// optional, if specified is useful for quick id lookups
 *				'id'		: 'article_2345';  // could be here too for uniformity
 *				'title'		: 'titles of fake articles are sometimes hard to make funny';
 *				'synopsis'	: 'something that kind of sits between the title and the descr. indeed.';
 *				'desc'		: '<p>complimentary, lengthy and witty text, well, that\'s <strong>another</strong> story altogether</p>';
 *			},
 *			'article_5678' : {
 *				'id'		: 'article_5678';
 *				'title'		: 'that could be why i write code rather than articles for the onion';
 *				'synopsis'	: 'if you add fields on the fly, the list sometimes becomes mellow-eratic.';
 *				'desc'		: '<span class="visualgoodness">i\'ve already made enough of a fool out of myself</span>';
 *			}
 *		}
 *
 ***************************************************************
 *		2...PMP templates...
 ***************************************************************
 *
 * 	<div id="pmpTemplates">
 *		<div id="pmpTemplate_articleList">
 *			<h1><a href="javascript:showArticleDetail( '~~id~~' )">~~title~~</a></h1>
 *			<p>~~synopsis~~</p>
 *		</div>
 *		<div id="pmpTemplate_articleDetail">
 *			<h1><a href="~~full_url~~">~~title~~</a></h1>
 *			<p><img src="~~img_url~~" /></p>
 *			<p>~~desc~~</p>
 *		</div>
 *	</div>
 *
 ***************************************************************
 *		3...using the PMP API to string the data 
 *		and the templates together...
 ***************************************************************
 *
 *		var pimp = new stingray.pmp.publisher();
 *		var contentContainer = document.getElementById('placeWhereArticleListGoes');
 *		contentContainer.innerHTML = pimp.renderContent( myArticleList, 'pmpTemplate_articleList' );
 *
 *		function showArticleDetail( id ) {
 *			var contentContainer = document.getElementById('placeWhereArticleDetailGoes');
 *			contentContainer.innerHTML = pimp.renderContent( myArticleList[id], 'pmpTemplate_articleDetail' );
 *		}
 *
 ****************************************************************/

stingray.getNamespace( 'stingray.pmp' );

/**
 * Poor Mans Publisher class
 * @class stingray.pmp.publisher
 * @author brian@stingrayengineering.com
 * @constructor
 */
stingray.pmp.publisher = function(_id) {
	if ( arguments.length > 0 ) {
		this.init(_id);
	}
}

/*
 * intitializes the publishing framework
 */
stingray.pmp.publisher.prototype.init = function(_id) {
	this.id = _id;
	this.templateManager = new stingray.pmp.templateManager();
}

/**
 * renders a list of item/template pairs into a DOM element
 * @param {_item} the item to parse
 * @param {_templateId} id of the rendering template to use
 * @param {_destId} id of the DOM element where content is to be rendered
 */
stingray.pmp.publisher.prototype.renderList = function(_list, _templateId, _destId) {
	var dest = document.getElementById( _destId );
	if ( dest != null ) {
		dest.innerHTML = this.renderListHTML( _list, _templateId );
	}
}

/**
 * renders a list of item/template pairs and returns the product HTML as a string
 * @param {_item} the item to parse
 * @param {_templateId} rendering template dom element id
 */
stingray.pmp.publisher.prototype.renderListHTML = function(_list, _templateId) {
	var result = new stingray.util.stringBuffer();
	for( var item in _list ) {
		result.append( this.applyTemplate( _list[item], _templateId ) );
	}
	return result.toString();
}

/**
 * renders a single item/template pair into a DOM element
 * @param {_item} the item to parse
 * @param {_templateId} rendering template dom element id
 * @param {_destId} id of the DOM element where content is to be rendered
 */
stingray.pmp.publisher.prototype.renderItem = function(_item, _templateId, _destId) {
	var dest = document.getElementById( _destId );
	if ( dest != null ) {
		dest.innerHTML = this.applyTemplate( _item, _templateId );
	}
}

/**
 * renders a single item/template pair and returns the product HTML as a string
 * @param {_item} the item to parse
 * @param {_templateId} rendering template dom element id
 */
stingray.pmp.publisher.prototype.renderItemHTML = function(_item, _templateId) {
	return this.applyTemplate( _item, _templateId );
}

/**
 * renders a single item/template pair and returns the product HTML as a string
 * for each field in the item, substitute any occurences of field names in the template
 * with the actual item values.
 * @param {_item} the item to parse
 * @param {_templateId} rendering template dom element id
 */
stingray.pmp.publisher.prototype.applyTemplate = function(_item, _templateId) {
	var html = this.templateManager.getTemplateHTML(_templateId);
	if ( html != null && html != '' ) {
		// href attrib contents get escaped in ff, restore the '~'s
		html = html.replace( /\%7E/g, '~' );
		// process system fields
		html = html.replace( new RegExp( '~~ITEM_ID~~', "g" ), _item.id );
		// process fields
		var rexp = null;
		for( var field in _item ) {
			html = html.replace( new RegExp( "~~"+field+"~~", "g" ), _item[field] );
		}
	}
	return html;
}




/**
 * template manager class
 * @class stingray.pmp.templateManager
 * @author brian@stingrayengineering.com
 * @constructor
 */
stingray.pmp.templateManager = function() {
	this.init();
}

/**
 * intitializes the template manager
 */
stingray.pmp.templateManager.prototype.init = function() {
	this.templates = new stingray.util.hashList();
}

/**
 * returns templates html
 */
stingray.pmp.templateManager.prototype.getTemplateHTML = function(_templateId) {
	if ( !this.templates.hasItem(_templateId) ) {
		var tmplNode = document.getElementById(_templateId);
		if ( tmplNode != null ) {
			var html = tmplNode.innerHTML;
			this.templates.addItem(_templateId, html);
			return html;
		} else {
			alert( 'template: ' + _templateId + ', not found!' );
		}
	} else {
		return this.templates.getItem(_templateId);
	}
}
