/* 	xmlArticleDisplay.js
	Ver 1.0 -- May 11, 2008
 	Ver 1.1 -- January 18, 2010
		Sort on Date instead of String version of date
	Ver 1.2 -- January 19, 2010
		Fixed title links to be anchor tags
		Added linkNode (Ability to select which part of stump is link)
		Added active tag and function
	Ver 1.3 -- February 17, 2011
		Added stumpFormat: 'title-date'
		
 	Written by Rev. Dr. Samuel J. Lovetro, III, MsD.
 	Site: http://lovetro.com
	Copyright (c) 2009. Unauthorized use is a violation of applicable laws.
	This application relies on MooTools, ver 1.2.1

	This program will:
		Read a specified XML file of articles into an array of articleObj.
		Sort the array by date or category.
		Display links to display articles. These are called "stumps" and can be grouped by date or category. 
		Display a selected article and any associated links that it possesses.

	This program requires:
		1. The XML article file for display.
		2. The ID for the article display.
		3. The ID for the stump display.
		
/*	Definitions:
	An ARTICLE will be defined as:
		1. A date when the article was posted.	requireD: SINGLE
		2. A title for the article.				requireD: SINGLE
		3. The contents of the article.			requireD: SINGLE
		4. The category of the article.			OPTIONAL: SINGLE
		5. One or more links					OPTIONAL: MANY
		6. Whether this listing is ACTIVE		requireD: SINGLE (Only required if useActive is TRUE)

	A LINK is defined as:
		1. A url								OPTIONAL: ZERO or MANY
		2. Text									OPTIONAL: ZERO or MANY
		3. External linking flag	 			OPTIONAL: ZERO or MANY
			(if true, opens in new window)

/*	XML format:
		<document>
			<article>
				<date>01/01/2009</date>													// The date of the posting. 					requireD: SINGLE
				<title>New Website Launches</title>										// The title of the article. 					requireD: SINGLE
				<contents>Lorem ipsum dolor sit amet, consectetur ...</contents>		// The contents of the article. 				requireD: SINGLE
				<category>press</category>												// The category of the article.					requireD: SINGLE
				<url>page1.htm</url>													// The URL for the article link. 				OPTIONAL: MANY
				<text>Go to Page 1!</text>												// The text for the article link.	 			OPTIONAL: MANY
				<external>false</external>												// If true, the link pops new window.			OPTIONAL: MANY
				...any number of link elements				
			</article>
			...any number of article elements
		</document>

/*	Display:
	Navigation:
		<ul id="stump">
			<li>
				<a class="date" href="javascript:;">01/01/2009</a>
				<div class="title">Lorem ipsum dolor sit amet <a class="more" href="javascript:;">MORE</a></div>
			</li>
		</ul>

	Articles:
		<div class="article">
			<div class="title">New Website Launches</div>
			<div class="date">Posted: 01/01/2009</div>
			<div class="category">Category: press</div>
			<div class="contents">Lorem ipsum dolor sit amet...</div>
			<ul class="links">
				<li><a href="page1.htm">Go to Page 1!</a></li>
			</ul>
		</div>
		
/* Additional functionality: 
	Order of data display (-1 for not used)
	Ability to re-order, re-sort data
*/
var linkObj = new Class({
	initialize: function( url, title, external ){
		this.url = url;
		if( title != null ) { this.title = title } else { this.title = url };
		if( external != null ) if( external.toUpperCase() == 'TRUE' ) { this.external = true } else { this.external = false };
	}
});
var articleObj = new Class({
	initialize: function( date, dateString, title, category, contents, links, id ){
		this.date = date;
		this.dateString = dateString;
		this.title = title;
		this.category = category;
		this.contents = contents;
		this.links = links;
		this.id = id;
	}
});
var xmlArticleDisplay = new Class({
	Implements: [Options, Events],
	options: {
		articleDisplay: true,
		stumpTag: 'li',
		sortType: 'recent',
		stumpDisplayAmount: 'all',
		stumpFormat: 'date-title',
		dateFormat: 'normal',
		linkNode: 'date',
		clearStumpContainer: true,
		filter: 'none',
		useMore: false,
		defaultID: null,
		displayHtml: true,
		defaultStumpUrl: '',
		completed: $empty
	},
	initialize: function( xmlFile, articleContainer, stumpContainer, options ){
		this.articleContainer = articleContainer;
		this.stumpContainer = stumpContainer;
		this.articles = new Array();
		this.queryString = this.getQueryString();
		this.articleID = this.getArticleID();
		this.setOptions(options);
		this.readXML( xmlFile, this.articleContainer );
		this.aIdx = 0;// Current article index
		this.aID = null;// Current article ID
	},
	readXML: function( file, location ) {
		//alert('readXML invoked. file='+file+', location='+location);
		var myRequest = new Request({
			url: file,
			method: 'get',
			onSuccess: function(responseText, responseXML){
				//alert(responseText);
				this.parseXML( responseXML );
			}.bind(this),
			onFailure: function(){
				//alert( 'There was a problem retrieving the XML data:\n' + file );
				if( $( location ))
				{
					var el = $( location ).set({
						'html': 'There was a problem retrieving the XML file:<br/>' + file,
						'styles': { 'color': '#ff0000', 'text-align': 'center', 'font-weight': 'bold' }
					});
				}
				else 
				{ 
					alert( 'There was a problem retrieving the XML data:\n' + file ); 
				};
			}
		}).send();
	},
	getTagValue: function( el, tag ) {
		if( !el ) return null;
		if( !el.getElementsByTagName( tag )) return null;
		
		var nodes = el.getElementsByTagName( tag );
		if( !nodes.length ) return null;
		if( nodes.length == 0 ) return null;
		if( nodes[ 0 ].firstChild == null ) return null;
		if( nodes[ 0 ].firstChild.nodeValue == null ) return null;
		
		return nodes[ 0 ].firstChild.nodeValue;
	},
	getValue: function( el ) {
		if( !el ) return null;
		if( !el.firstChild ) return null;
		if( el.firstChild == null ) return null;
		if( el.firstChild.nodeValue == null ) return null;
		
		return el.firstChild.nodeValue;
	},
	getQueryString: function() {
		var qsParm = new Array();
		var query = window.location.search.substring( 1 );
		var parms = query.split( '&' );
		for( var i=0; i < parms.length; i++ ) {
			var pos = parms[ i ].indexOf( '=' );
			if( pos > 0 ) {
				var key = parms[ i ].substring( 0, pos );
				var val = parms[ i ].substring( pos+1 );
				qsParm[ key ] = val;
			};
		};
		return qsParm;
	},
	getArticleID: function() {
		//alert('this.queryString[ articleID ]='+this.queryString[ 'ArticleID' ]);
		return this.queryString[ 'articleID' ];
	},
	parseXML: function( xmlObj ) {
		//alert('parseXML invoked.');
		var elements = xmlObj.getElementsByTagName( 'article' );
		if ( elements.length == 0 ) {
			var el = $( this.articleContainer );
			el.set( 'html', 'There are no articles at this time.' );
			return;
		};
		var k = 0;
		for( var i = 0; i < elements.length; i++ ) {
			var active = this.getTagValue( elements[ i ], 'active' );
			if( active != null && active.toUpperCase() != 'TRUE' && this.options.useActive ) continue;
			
			var links = new Array();
			var eLinks = elements[ i ].getElementsByTagName( 'url' );
			var eText = elements[ i ].getElementsByTagName( 'text' );
			var eExt = elements[ i ].getElementsByTagName( 'external' );
			if( eLinks.length ) {
				for (var j = 0; j < eLinks.length; j++) {
					links[ j ] = new linkObj( 
						this.getValue( eLinks[ j ]), 
						this.getValue( eText[ j ]), 
						this.getValue( eExt[ j ]) 
					);
				};
			};
			var date = this.convertStringToDate( this.getTagValue( elements[ i ], 'date' ));
			var dateString = this.convertDateToDateString( date );
			this.articles[ k ] = new articleObj( 
				date, 
				dateString,
				this.getTagValue( elements[ i ], 'title' ), 
				this.getTagValue( elements[ i ], 'category' ), 
				this.getTagValue( elements[ i ], 'contents' ), 
				links,
				elements[ i ].getAttribute( 'id' )
			);
			k++;
		};
		this.sortArticles( this.options.sortType );
		//if( this.options.filter != 'none' ) this.filterDisplay(); 
		this.createStumpDisplay( this.options.stumpDisplayAmount );
		this.displayArticle( null );
		if( this.options.completed != $empty ) this.options.completed();
	},
	convertStringToDate: function ( s ) {
		var mIdx = s.indexOf( '/' );
		var m = Number( s.slice( 0, mIdx ))-1;
		var dIdx = s.indexOf( '/', mIdx );
		var d = Number( s.slice( mIdx+1, mIdx+dIdx+1 ));
		var y = Number( s.slice( mIdx+dIdx+2 ));
		return new Date( y, m, d ); 
	},
	convertDateToDateString: function ( x ) {
		var rtn = ''; // Format: January 1, 2010
		switch( this.options.dateFormat ) {
			default:
				var m = x.getMonth();
				var d = x.getDate();
				var y = x.getFullYear();
				switch( m ) {
					case 0:  m='January'; break;
					case 1:  m='February'; break;
					case 2:  m='March'; break;
					case 3:  m='April'; break;
					case 4:  m='May'; break;
					case 5:  m='June'; break;
					case 6:  m='July'; break;
					case 7:  m='August'; break;
					case 8:  m='September'; break;
					case 9: m='October'; break;
					case 10: m='November'; break;
					case 11: m='December'; break;
					default: break;
				};
				rtn = m + ' ' + d + ', ' + y;
				break;
		};
		return rtn;
	},
	sortByOldest: function ( a, b ){
		return (a.date < b.date) ? -1 : 1;
	},
	sortByRecent: function ( a, b ){
		return ( a.date < b.date ) ? 1 : -1;
	},
	sortByCategoryDate: function ( a, b ){
		if ( a.category == b.category ) {
			return ( a.date < b.date ) ? -1 : 1;
		};
		return ( a.category < b.category ) ? -1 : 1;
	},
	sortByCategoryTitle: function ( a, b ){
		if ( a.category == b.category ) {
			return ( a.title < b.title ) ? -1 : 1;
		};
		return ( a.category < b.category ) ? -1 : 1;
	},
	sortArticles: function( type ) {
		//alert('sortArticles invoked. type='+type);
		switch( type ) {
			case 'category-title':
				this.articles.sort( this.sortByCategoryTitle );
				break;
			case 'category-date':
				this.articles.sort( this.sortByCategoryDate );
				break;
			case 'oldest':
				this.articles.sort( this.sortByOldest );
				break;
			default: // 'current'
				this.articles.sort( this.sortByRecent );
				break;
		};
	},
	setLinkage: function ( node, id ) {
		if( this.options.defaultStumpUrl != '' ) {
			node.set( 'href', this.options.defaultStumpUrl + '?articleID=' + id );
		} else {
			node.addEvent( 'click', this.displayArticle.bind( this, [ id ]));
		};
	},
	createNewStump: function ( dateString, title, id, index ) {
		var e = new Element( this.options.stumpTag, { 'class': 'stump' });
		var eDate, eTitle;
		
		switch( this.options.linkNode ) {
			case 'title':
				eTitle = new Element( 'a', {
					'class': 'contents',
					'href': 'javascript:;'
				}).set( 'text', title );
				this.setLinkage( eTitle, id );

				eDate = new Element( 'div', {
					'class': 'date'
				}).set( 'text', dateString );
				break;
			default: // 'date'
				eDate = new Element( 'a', {
					'class': 'date',
					'href': 'javascript:;'
				}).set( 'text', dateString );
				this.setLinkage( eDate, id );
				
				eTitle = new Element( 'div', {
					'class': 'contents'
				}).set( 'text', title );
				break;
		};

		if( this.options.useMore ) {
			var eMore = new Element( 'a', {
				'class':'more',
				'href': 'javascript:;'
			}).set( 'text', 'More...' );
			this.setLinkage( eMore, id );			
			var eSpace = new Element( 'br' );
			eTitle.appendChild( eSpace );
			eTitle.appendChild( eMore );
		};
		
		switch( this.options.stumpFormat ) {
			case 'date':
				e.appendChild( eDate );
				break;
			case 'title':
				e.appendChild( eTitle );
				break;
			case 'title-date':
				e.appendChild( eTitle );
				e.appendChild( eDate );
				break;
			default: // 'date-title'
				e.appendChild( eDate );
				e.appendChild( eTitle );
				break;
		};
		return e;
	},
	createStumpDisplay: function( amount ) {
		//alert('createStumpDisplay invoked. amount='+amount);
		var element = $( this.stumpContainer );
		if( this.options.clearStumpContainer ) element.set( 'html', '' );
		switch( amount ) {
			case 'all':
				var display = this.articles.length;
				break;
			default:
				var display = Number( amount );
				if( display > this.articles.length ) display = this.articles.length;
		};
		for ( var i=0; i<display; i++ ) {
			var stump = this.createNewStump( 
				this.articles[ i ].dateString, 
				this.articles[ i ].title, 
				this.articles[ i ].id, 
				i 
			);
			element.appendChild( stump );
		};
	},
	createLinks: function( linksArray ) {
		var exist = false;
		if( linksArray.length > 0 ) {
			var ul = new Element( 'ul', {
				'class': 'links'
			});
			for( var i=0; i<linksArray.length; i++ ) {
				if( linksArray[ i ].url != null ) {
					exist = true;
					var li = new Element( 'li' );
					var a = new Element( 'a', {
						'href': linksArray[ i ].url
					});
					if ( linksArray[i].title ) {
						a.set( 'text', linksArray[ i ].title );
					} else {
						a.set( 'text', linksArray[ i ].url );
					};
					if ( linksArray[i].external ) {
						a.set( 'rel', 'external' );
						a.set( 'target', '_blank' );
						a.addClass( 'external' );
					}
					li.appendChild( a );
					ul.appendChild( li );
				};
			};
		};
		if( exist ) return ul;
	},
	displayArticle: function( choice ) {
//alert('displayArticle. choice='+choice);
		if( !this.options.articleDisplay ) return;
		var element = $( this.articleContainer );
		element.set( 'html', '' );
		
		var id = null;
		var index = 0;
		if( this.options.defaultID != null ) id = this.options.defaultID;
		if( this.articleID != null ) id = this.articleID;
		if( choice != null ) id = choice;

		if( id != null ) {
			for( var i=0; i<this.articles.length; i++ ) {
				if( this.articles[ i ].id == id ) {
					index = i;
					break;
				};
			};
		};
		this.aIdx = index;
		this.aID = id;
		var ac = this.articleContainer + '-';
		
		var article = new Element( 'div', { 
			'class': 'article', 
			'id': ac + 'article' 
		});
		
		var title = new Element( 'div', { 
			'class': 'title', 
			'id': ac + 'title' 
		}).set( 'text', this.articles[ index ].title );
		article.appendChild( title );
		
		var date = new Element( 'div', {
			'class': 'date',
			'id': ac + 'date' 
		}).set( 'text', 'Posted: ' + this.articles[ index ].dateString );
		article.appendChild( date );
		
		var category = new Element( 'div', { 
			'class': 'category',
			'id': ac + 'category' 
		}).set( 'text', 'Category: ' + this.articles[ index ].category );
		article.appendChild( category );

		var contents = new Element( 'div', { 
			'class': 'contents', 
			'id': ac + 'contents' 
		});
		if ( this.options.displayHtml ) {
			contents.set( 'html', this.articles[ index ].contents );
		} else {
			contents.set( 'text', this.articles[ index ].contents );
		};
		article.appendChild( contents );
		
		var links = this.createLinks( this.articles[ index ].links );
		if( links != null ) article.appendChild( links );
		element.appendChild( article );
	}
});
/* 	Deployment: 
var myXmlArticleDisplay = new xmlArticleDisplay( 
	'/xml/articleDisplay.xml',										// location of xml file
	'article', 														// id for article display
	'nav', 															// id for stump display
	{																// Options (Default shown)
		articleDisplay: true,											// Do articles display? BOOLEAN
		sortType: 'current', 											// Articles sorted by: 'current', 'oldest', 'category-date', 'category-title'
		defaultID: null,												// Default article id to show. Will show 0 index article if null.
		stumpDisplayAmount: 'all',										// Number of stumps to display: 'all' or ###
		stumpFormat: 'date-title',										// Format for stumps: 'date-title', 'date', 'title'
		linkNode: 'date', 'title',										// Which node to use as a link
		dateFormat: 'normal',											// Format for date: 'normal' (no change), 'month-date-year' (January 1, 2009)
		filter: 'none',		 											// Filter articles by: 'none', 'category' (not implemented)
		clearStumpContainer: true, 										// Clears the stump navigation before drawing: true or false
		useMore: false,													// Adds link to stump title that says "More...": true, or false
		displayHtml: true,												// Display article contents as HTML: true or false
		defaultStumpUrl: '',											// If set, the default url for all stump links
		completed: 														// Function to execute on complete
			function () { addSecondaryAnimation( 'news' ); }
});
*/
