// Requires the share & jQuery libraries to be included first

if (!window['netShelter']) 
	window['netShelter'] = {};

netShelter.parseUnicodeFromString = function(value) {
	/*	Converts escaped Unicode into appropriate characters
	 * 		e.g. &#201c; becomes "
	 */
	
	//	Separate unicode-encodings from value and mark them with ⸚ 
	var part = value.replace(/&#(x?[a-fA-F0-9]{4,5});/g, '&#' + String.fromCharCode(11802) + '$1&#').split('&#');

	//Convert ⸚-marked segments into character equivalents
	for (var i = 0; i < part.length; i++) {
		if (part[i].charCodeAt(0) == 11802) {
			// If the original string was &#x, use hexadecimal; otherwise, use decimal
			var charCode = part[i].charAt(1).toLowerCase() == 'x'
				? Number('0x' + part[i].substr(2))
				: part[i].substr(1);
				
			part[i] = String.fromCharCode(charCode);
		}
	}

	return part.join('');
}


netShelter.StoryModel = function(
	title,
	summary,
	date,
	author,
	articlePath,
	publicationName,
	publicationDomain,
	n2iPID,
	shareMetadata
) {
	this.title = 				title				||	"";
	this.summary =				summary			    ||	"";
	this.date =					date				||	null;
	this.author =				author				||	"";
	this.articlePath =			articlePath		    ||	"";
	this.publicationName =		publicationName	    ||	"";
	this.publicationDomain =	publicationDomain	||	"";
	this.n2iPID =				n2iPID				||	-1;
	this.shareMetadata =		shareMetadata		||	{};
	
	function populateShareMetadataFromMetricsString(metrics) {
		/*	Not recycling shareCountRegEx with a static variable because regEx.exec isn't 
		 *	reliable across multiple independent strings.  (It was sometimes setting 
		 *	shareCount to 0 when it should have had a value).
		 *
		 *	Not using {key: value} syntax because keys are constants, not anonymous strings.
		 */

		var shareCountRegEx = {};
		shareCountRegEx[ShareTarget.DELICIOUS]	=	/delicious=(\d+)/ig;
		shareCountRegEx[ShareTarget.DIGG]		=	/digg=(\d+)/ig;
		shareCountRegEx[ShareTarget.EMAIL]		=	/e-mail=(\d+)/ig;
		shareCountRegEx[ShareTarget.FACEBOOK]	=	/fb_post=(\d+)/ig;
		shareCountRegEx[ShareTarget.LINKEDIN]	=	/linkedin=(\d+)/ig;		// Guessing the key for this one until I get confirmation from Brin.
		shareCountRegEx[ShareTarget.REDDIT]		=	/reddit_votes=(\d+)/ig;
		shareCountRegEx[ShareTarget.TWITTER]	=	/twitter=(\d+)/ig;
			
		for (var shareTarget in shareCountRegEx) {
			var regExGroups = shareCountRegEx[shareTarget].exec(metrics);

			if (!this.shareMetadata.hasOwnProperty(shareTarget))
				this.shareMetadata[shareTarget] = {};
				
			this.shareMetadata[shareTarget].count = (regExGroups) 
				? parseInt(regExGroups.pop()) 
				: 0;
		}
	}
}

netShelter.StoryModel.fromRSS = function(node) {
	with (netShelter) {
		var node = $(node);
			
		function getText(childName) {
			// If the Handlebars templates use triple-{s, the browser will parse Unicode by itself.  Otherwise, wrap the result in parseUnicodeFromString.
			return node.children(childName).text();
		}
	
		window.sampleRSSNode = node;
	
		return new StoryModel(
			getText('title'),
			getText('description'),
			new Date(getText('pubDate')), 
			getText("[nodeName='dc:creator']"),
			getText('link'),
			node.parent().children('title').text(),
			node.parent().children('link').text()
		);
	}
}

netShelter.StoryModel.fromXML = function(node) {
	with (netShelter) {
		var node = $(node);
		
		function getText(childName) {
			// If the Handlebars templates use triple-{s, the browser will parse Unicode by itself.  Otherwise, wrap the result in parseUnicodeFromString.
			return node.children(childName).text();
		}
	
		var result = new StoryModel(
			getText('title'),
			getText('summary'),
			new Date(1000 * parseInt(getText('updated'))), 
			getText('author'),
			getText('link'),
			getText('site_title'),
			getText('site_name'),
			parseInt(getText('post_id') || getText('id'))
		);
		
		result.populateShareMetadataFromMetricsString(getText('metrics'));
		
		return result;
	}
}

netShelter.StoryModel.fromJSON = function(dict) {
	with (netShelter) {
		var shareCountRegEx = {};
		shareCountRegEx[ShareTarget.DELICIOUS]	=	/delicious=(\d+)/ig;
		shareCountRegEx[ShareTarget.DIGG]		=	/digg=(\d+)/ig;
		shareCountRegEx[ShareTarget.EMAIL]		=	/e-mail=(\d+)/ig;
		shareCountRegEx[ShareTarget.FACEBOOK]	=	/fb_post=(\d+)/ig;
		shareCountRegEx[ShareTarget.LINKEDIN]	=	/linkedin=(\d+)/ig;		// Guessing the key for this one until I get confirmation from Brin.
		shareCountRegEx[ShareTarget.REDDIT]		=	/reddit_votes=(\d+)/ig;
		shareCountRegEx[ShareTarget.TWITTER]	=	/twitter=(\d+)/ig;
		
		var result = new StoryModel(
			dict.title,
			dict.summary,
			new Date(1000 * parseInt(dict.updated)), 
			dict.author,
			dict.link,
			dict.site_title,
			dict.site_name,
			parseInt(dict.post_id || dict.id)
		);
		
		result.populateShareMetadataFromMetricsString(dict.metrics);
		
		return result;
	}
}

netShelter.getModelsFromXMLFeed = function(
	feedPath, 
	parser, 
	nodeName, 
	callback, 
	dataType
) {
	// If the first argument is a dict, use it to populate the arguments.
	if (typeof(feedPath) != 'string') {
		var argumentDict = arguments[0];
		
		feedPath	= argumentDict.feedPath;
		parser		= argumentDict.parser;
		nodeName	= argumentDict.nodeName;
		callback	= argumentDict.callback;
		dataType	= argumentDict.dataType;
	}

	$.ajax({
       	'url':		feedPath,
       	'dataType':	dataType || 'xml',
       	'success':	function(value) {
			// Make a list of Models, using all the result nodes from the returned feed
			var modelList = $(value).find(nodeName).map(
				// jQuery's map has a backwards order in its callback signature, so use a function to ignore the index
				function (i, node) {
					return parser(node);
				}
			).toArray();

			callback(modelList);
		}
	});
}

netShelter.getStoryModelsFromFeed = function(
	storyFeedPath, 
	callback, 
	storyFeedType, 
	storyFeedID
) {
	// If the first argument is a dict, use it to populate the arguments.
	if (typeof(storyFeedPath) != 'string') {
		var argumentDict = arguments[0];
		
		storyFeedPath		= argumentDict.storyFeedPath;
		callback			= argumentDict.callback;
		storyFeedType		= argumentDict.storyFeedType;
		storyFeedID			= argumentDict.storyFeedID;
	}

	// Set defaults for undefined parameters
	if (!storyFeedPath)
		throw new Error("netShelter.getStoryModelsFromFeed requires a storyFeedPath parameter");
	
	if (!callback)
		throw new Error("netShelter.getStoryModelsFromFeed requires a callback parameter");
	
	storyFeedType	= storyFeedType	|| storyFeedPath.split('.').pop();
	storyFeedID		= storyFeedID	|| storyFeedPath.indexOf('post_') != -1
											? storyFeedPath.substring(storyFeedPath.indexOf('post_') + 5)
											: NaN;


	switch (storyFeedType) {
		case "xml":
			return netShelter.getModelsFromXMLFeed({
				'feedPath':		storyFeedPath, 
				'parser':		netShelter.StoryModel.fromXML, 
				'nodeName':		'result', 
				'callback':		callback,
				'dataType':		'xml'
			});
			
			
		case 'rss':
			return netShelter.getModelsFromXMLFeed({
				'feedPath':		storyFeedPath, 
				'parser':		netShelter.StoryModel.fromRSS, 
				'nodeName':		'item', 
				'callback':		callback,
				'dataType':		'xml'
			});
		
		
		case "js":
		case "json":
			if (!storyFeedID)
				throw new Error("netShelter.getModelsFromXMLFeed could not determine the story feed ID.");
			
			// store the callback for the specific feed
			netShelter._pendingStoryFeedCallback = netShelter._pendingStoryFeedCallback || {};

			if (netShelter._pendingStoryFeedCallback.hasOwnProperty(storyFeedID) && netShelter._pendingStoryFeedCallback[storyFeedID] != callback) {
				var oldCallback = netShelter._pendingStoryFeedCallback[storyFeedID];
				var wrappedCallback = function(storyModelList) {
					oldCallback(storyModelList);
					callback(storyModelList);
				}
			
				netShelter._pendingStoryFeedCallback[storyFeedID] = wrappedCallback;
			} else
				netShelter._pendingStoryFeedCallback[storyFeedID] = callback;
		
		
			var script = document.createElement('script');
			script.setAttribute('type', 'text/javascript');
			script.setAttribute('src', storyFeedPath);
		
			//IE7 doesn't like document.head
			document.getElementsByTagName('head')[0].appendChild(script);
			break;
			
			
		default:
			throw new Error("netShelter.getStoryModelsFromFeed could not determine feed type.");
	}
}
