/* 
* Disclaimer Aggregator
* andrew relkin
* use it however you want, just leave the credits.
* and drop me an email if you do use it.
* relkin at live dt com
*
* v1.1 2011-10-06
* sorting option added
*
* v1.0 2011-09-27
*
* similar idea to several footnote aggregators;
* this looks for non-sequential, symbol-represented disclaimers,
* weeds out repeats and places resulting list in a disclaimer container
*
* this idea evolved out of the need for something similar to:
* http://www.planetholt.com/articles/jQuery-Footnotes
*
* CSS based on defaults:
* span.disclaimer { display:none; }
* div.disclaimer { [your styles here; nothing needed if just display:block] }
*
* example disclaimer format:
* <sup class="disclaimer_symbol">&bull;</sup><span class="disclaimer bullet1"><span class="disclaimer_symbol">&bull;</span> Now is the time for all good men.</span>
* <sup class="disclaimer_symbol">**</sup><span class="disclaimer asterisk2"><span class="disclaimer_symbol">**</span> Now is the time for all good men.</span>
*
* default usage:
* $('.disclaimer').disclaimerAggregator();
* 
* if disclaimers are put in custom areas, or have custom disclaimers in certain areas
* user can add custom/targeted disclaimer types
* this is mostly if footnote list is itemized and catchTypos==false;
* $('.disclaimer').disclaimerAggregator({"more":{"asterisk2":"**","double_caret":"^^"} });
* 
* if user has different disclaimers that need to be 
* placed in separate places on the page:
* $('.left_column .disclaimer').disclaimerAggregator({"disclaimerContainer":"#left_disclaimers"});
* $('.right_column .disclaimer').disclaimerAggregator({"disclaimerContainer":"#right_disclaimers"});
*
*
// possible default content for disclaimers_list

// the "itemized" is used both as a boolean and 
// as a counter for the debugging and reporting		
"asterisk1":{"itemized":0,"symbol":"*", "sContent":""},
"asterisk2":{"itemized":0,"symbol":"**", "sContent":""},
"caret1":{"itemized":0,"symbol":"^", "sContent":""},
"dagger1":{"itemized":0,"symbol":"&dagger;", "sContent":""},
"dagger2":{"itemized":0,"symbol":"&Dagger;", "sContent":""},
"para1":{"itemized":0,"symbol":"&para;", "sContent":""},
"pound1":{"itemized":0,"symbol":"#", "sContent":""},
"section1":{"itemized":0,"symbol":"&sect;", "sContent":""}

*/

(function ($) {

	$.fn.disclaimerAggregator = function (options) {

		var thisSelector = this.selector,
			thisElement = thisSelector.substr(((thisSelector.lastIndexOf(" .") > -1) ? (thisSelector.lastIndexOf(" .") + 2) : 1)),
		// container in which to aggregate all the disclaimers
			$aggregatedDisclaimers = $("<div/>").addClass('aggregatedDisclaimers');

		options = $.extend({

			debug: false,

			sort: true,

			more: {},

			// container in which disclaimers will be displayed (typically, a footer)
			disclaimerContainer: "#disclaimers_container",

			// class to search for when seeking all disclaimers
			disclaimerOutputClass: "disclaimer",

			// if true and a user mistypes a classname, a disclaimer 
			// might appear more than once in the aggregate list
			catchTypos: true,

			// if catchTypos==false, disclaimers_list must be itemized
			// in such a situation, it means only disclaimer types that appear on this list would be aggregated
			disclaimers_list: {},

			// could also be a class or ID
			disclaimerMarkContainer: "span"

		}, options);

		var debug = (query("debug")) ? true : options.debug;
		var allowDebug = true;

		// check to see if user added some
		// custom disclaimer types and add them to the disclaimers_list object
		if (!isEmpty(options.more)) { addFootnote(options.more, '') }

		// find one instance of each type of disclaimer
		// and append to footer
		this.each(function () {
			//var	re = new RegExp(" ?"+thisElement+" ?", "g"), 
			var c = this.className.replace(RegExp(" ?" + thisElement + " ?", "g"), "");

			// if found disclaimer not on "disclaimers_list" and checking for typos, add to list
			// list might be completely non-itemized and being populated on dynamically from page
			// if catchTypos==false, then "disclaimers_list" must be itemized
			if (!hasElement(c, options.disclaimers_list) && options.catchTypos) 
				{
				temp = {};
				temp[c] = $(options.disclaimerMarkContainer, $(this)).html();
				addFootnote(temp, $(this).html());
				}

			// if disclaimer type on "disclaimers_list" list,
			// grab the disclaimer and prepare for aggregate list
			if (hasElement(c, options.disclaimers_list)) 
				{
				if (options.disclaimers_list[c]["sContent"] == "") { options.disclaimers_list[c]["sContent"] = $(this).html(); }
				options.disclaimers_list[c]["itemized"]++;
				}

		}); // end each

		// sort list if need be
		var oDisclaimers = (options.sort) ? sortObject(options.disclaimers_list) : options.disclaimers_list;

		// aggregate into a DIV, any disclaimer type that actually appears on the page
		for (x in oDisclaimers) 
			{
			if (oDisclaimers[x]["itemized"] > 0) 
				{
				$("<div/>").addClass(options.disclaimerOutputClass)
					.html(oDisclaimers[x]["sContent"])
					.appendTo($aggregatedDisclaimers);
				}
			}

		// if proposed disclaimerContainer exists on page,
		// publish into that element, else just put at bottom of page
		appendHere = ($(options.disclaimerContainer).length > 0) ? $(options.disclaimerContainer) : "body";
		$aggregatedDisclaimers.appendTo(appendHere);

		// ---------------------------------------------------------------------

		// show a debug report near the aggregated disclaimer list
		if (debug && allowDebug) 
			{
			var disclaimersToDisplay = 0, allDisclaimers = 0, $i = $("<div/>").addClass('itemized').css({ "background-color": "#CCC", "margin-bottom": "12px" }).html("<b style='margin-bottom:10px;display:block;'>debug report: " + thisSelector + "</b>");
			log(oDisclaimers);
			for (x in oDisclaimers) { allDisclaimers += oDisclaimers[x]["itemized"]; if (oDisclaimers[x]["itemized"] > 0) { disclaimersToDisplay++; $("<div/>").text(oDisclaimers[x]["itemized"] + " " + x + " (" + oDisclaimers[x]["symbol"] + ") disclaimer_text: " + oDisclaimers[x]["sContent"]).appendTo($i); } }
			$("<p/>").text(allDisclaimers + " disclaimers found based on: " + thisSelector).appendTo($i);
			$("<p/>").text(disclaimersToDisplay + " disclaimers to be displayed.").appendTo($i);
			$i.prependTo($aggregatedDisclaimers);
			}

		function isEmpty(obj) { for (var i in obj) { return false; } return true; }
		function hasElement(e, o) { for (var i in o) { if (i == e) { return true; } } return false; }
		function query(fldNm) { var oRe = new RegExp("[\\?&]" + fldNm + "=([^&#]*)", "i"); var fldVal = oRe.exec(parent.location.search); return (fldVal) ? unescape(fldVal[1]) : ""; }
		function addFootnote(o, sContent) { for (var x in o) { options.disclaimers_list[x] = {}; options.disclaimers_list[x]["itemized"] = 0; options.disclaimers_list[x]["symbol"] = o[x]; options.disclaimers_list[x]["sContent"] = sContent; } }
		// http://www.stackoverflow.com/questions/1359761/sorting-a-json-object-in-javascript
		function sortObject(o) { var sorted = {}, key, a = []; for (key in o) { if (o.hasOwnProperty(key)) { a.push(key); } } a.sort(); for (key = 0; key < a.length; key++) { sorted[a[key]] = o[a[key]]; } return sorted; }
	};

})(jQuery);


