/**
* @fileOverview A library of custom reuseable and semi-reusable widgets, plugins, 
* and utilities for use with WCMC websites. The goal is to speed 
* production time and promote unity and consistency of global code. <br/><br/>
*
* Copyright 2010 Weill Cornell Medical College. All rights reserved. <br/><br/>
*
* @author Brian Tobin
* @version 1.0.0
*/

"use strict";


(function( window ){
	

/**
* WC main namespace wrapper
* @namespace
* @requires $
*/
var WC = {
	/**
	* @property
	*/
	version: '1.0.0'
};


/**
* User Interface components namespace
* @namespace
*/
WC.UI = {};


/** 
* Constructs a page template from page variable
* @class
* @requires page
* @param {object} page_obj
* @example
* See <a href="http://cornellent.org">www.cornellent.org</a> for full example.
* The page_obj props setup the page and set active states: <br/><em>
* WC.UI.Template.setup({ 
* 	'body_id': 'health_services', 
* 	'section': 'Healthcare Services',
* 	'sub': [ 
* 		'Diseases of the Ear'
* 	]
* });
* </em>
*
*/
WC.UI.Template = {
	
	
	
	/**
	* Set page title, create breadcrumbs
	* @function
	*/
	setup: function(page_obj){
		
		var page_title 	= $('#col_2 h1').html() ? $('#col_2 h1').html() + ' | ' : '',
			// TODO: var page should be only an argument of the Template.setup() and not
			// a standalone var on the page
			// Ent has the standalone page var, this we call param page_arg bor backwards compatibility
			page		= page_obj || page,
			id 			= page.body_id || '',
			section 	= page.section || '',
			sub 		= page.sub || [],
			depth 		= sub.length;
		
		// kill the script if the page is 'home'
		// this allows designers not to worry about conflicts with their custom home page
		// updates should build on the started work arounds
		if ($('body').attr('id') === 'home') return;
		
		// set page title and body id
		document.title = page_title + site.the_name;
		// set page id	
		$('body').attr('id', id);			
		// add first portion of breadcrumb
		var breadcrumbs = '<li><a href="' + site.root + '">Home</a></li>';
		
		function format_class(string){
			string = string.replace(/\s/g, '_').toLowerCase(); 
			string = string.replace(/\:|\(|\)|\.|\,|\"|\'/g, ''); 
			return string;
		}
		
		// set section breadcrumb as plain text or links based on how deep we are in page
		if (section !== ''){
			if (depth < 1){
				breadcrumbs += '\n<li>/</li>\n<li>' + section + '</li>';
			}
			else {
				breadcrumbs += '\n<li>/</li>\n<li><a href="index.html">' + section + '</a></li>';
			}
			
		}
		
		// Add section as first body class	
		$('body').addClass(format_class(section));
					
		// loop through sub items...
		for (var i=0; i<depth; i+=1 ){
			// add those as formatted classes to body
			$('body').addClass(format_class(sub[i]));
			// add breadcrumbs
			// if not last item...
			var last = depth - 1;
			if (i === last){
				breadcrumbs += '\n<li>/</li>\n<li>' + sub[i] + '</li>';
			}
			// make crumb a link if not last in array
			else {
				breadcrumbs += '\n<li>/</li>\n<li><a href="' + format_class(sub[i]) + '.html">' + sub[i] + '</a></li>';
			}
		}
		// apend breadcrumb trail
		$('#breadcrumb ul').html(breadcrumbs);
		// highlight nav items
		this.set_nav(id, format_class(section), sub, depth);
	},
	
	/**
	* Recurses through nav and activates links for current page
	* @function
	* @param {String} id page.body_id
	* @param {String} section page.section
	* @param {Array} sub page.sub
	* @param {Number} depth length of sub array
	*/
	set_nav: function(id, section, sub, depth){

		function format_text(string){
			return string.replace(/^\s+|\s+$/g, '').toLowerCase();
		}
		
		// highlight main nav section
		$('ul.main_nav #' + section).addClass('active');
		// gather all links into array. This ecompasses both 2nd and 3rd level.
		var nav_links = $('.level_2_nav li a');
		// if there are no sub pages, depth is 0 for loop
		if (depth === ''){
			depth = 0;
		}
		// loop level 2 nav links
		for (var i=0; i<nav_links.length; i+=1){
			// loop through the page.sub array
			for (var x=0; x<depth; x+=1){
				// if formatted nav text and formatted page.sub text match, highlight it
				if (format_text(sub[x]) === format_text($(nav_links[i]).text())){
					// add the active class to the appropriate link
					$(nav_links[i]).addClass('active');
					// if find a 3rd level nav, open that sucker up
					var level_3_nav = $(nav_links[i]).parent('li').find('ul.level_3_nav');
					if (level_3_nav){
						// remove and css from javascript
						level_3_nav.css('display','inline');
					}
				}
			}
		}
	}
};


/**
* Slideshow with controller. Currently lacks abstraction and
* controller is specific to wcmc homepage
* author: Philip Forget
* @class
* @example
* This plugin is currently not abstracted to the point of being reusable. 
* For now this is tailored for the wcmc homepage only.
*/
WC.UI.slideshow = {
	options: {
		loop_behavior: {
			YOYO: "yoyo",
			REWIND: "rewind"
		}
	},
	get_new_id:function(){
		var idStart = -1;
		return function(){
			idStart += 1;
			return idStart;
		};
	}(),
	slideshowArray: [],
	/**
	* Add new slideshow
	* @function add_slideshow
	*/
	add_slideshow: function(slideshow){
		this.slideshowArray[slideshow.get_id()] = slideshow;
	},
	get_slideshow_by_id:function(index){
		return this.slideshowArray[index];
	},
	/**
	* Create a new instance of slideshow
	* @function
	*/
	create_slideshow: function( slideshow_div, slideshow_options, controller_div ){
		// Private methods and variables
		var slides_array = $(slideshow_div).find("div div");
		var current_slide = slideshow_options.startIndex;
		var play = false;
		var play_direction = true;
		var slideshow_id = this.get_new_id();
		var padding = $(slides_array[0]).css('margin-right');
		
		padding = padding.substr(0, padding.length - 2);
		slideshow_options.slideOffset = -285;
		
		var num_slides_displayed = 2;
		
		/**
		* Build the controller
		* currently lacking the abstraction
		* @function 
		*/
		var build_controller = function(){
			
			var iconHolder = $(controller_div).find('span');
			var controllerTemplate = iconHolder.html();
			// Clear the controller of the template li elements
			iconHolder.html(''); 
			
			var slide_width = $(slideshow_div).find('div').outerWidth(true),
				slider_width = slides_array.length * slide_width;
			$(slideshow_div).css('width', slider_width);
	
			$(controller_div).css({
				// show the controller. prevents controller from beings shown without JS
				'display': 'block',
				// currently not abstracted - needs to take size of icons, etc...
				'width': (slides_array.length * 15) + 22 + 'px'
			});
			
			for (var i = 0; i< slides_array.length; i++){
				// Create the icon for the controller
				var icon = $(controllerTemplate);
				
				$(icon).attr({
					"id": "icon" + i
				});
				
				$(icon).click(function(slideshow_id, i){
					return function(e){
						var slideshow = WC.UI.slideshow.get_slideshow_by_id(slideshow_id);
						slideshow.go_to_slide(i);
						return false;
					};
				}(slideshow_id, i));
				
				// append icons
				$(iconHolder).append(icon);
				$(icon).mouseover(function(i){}(i));
				$(icon).mouseout(function(i){}(i));
			};
			
			$(controller_div + ' > .previous').click(function(slideshow){
				return function(){
					var slideshow = WC.UI.slideshow.get_slideshow_by_id(slideshow_id);
					slideshow.regress_slideshow();
					return false;
				}
			}(slideshow_id));
			
			$(controller_div + ' > .next').click(function(slideshow){
				return function(){
					var slideshow = WC.UI.slideshow.get_slideshow_by_id(slideshow_id);
					slideshow.advance_slideshow();
					return false;
				}
			}(slideshow_id));
			
			if (slideshow_options.autoPause){
				$(slideshow_div).hover(pause_slideshow, play_slideshow);
				$(controller_div).hover(pause_slideshow, play_slideshow);
			}
		};
		var play_slideshow = function(){
			play = true;
			clearTimeout(timer);
			timer = setTimeout(auto_advance, slideshow_options.advanceDelay);
		}
		var pause_slideshow = function(){
			play = false;
			clearTimeout(timer);
		}
		var auto_advance = function(){
			var slideshow = WC.UI.slideshow.get_slideshow_by_id(slideshow_id);
			slideshow.advance_slideshow();
			if (play){
				play_slideshow();
			}
			else{
				pause_slideshow();
			}
		};
		build_controller();
		if (slideshow_options.autoPlay) {
			var timer = setTimeout(auto_advance, slideshow_options.advanceDelay);
		}
		// Return public variables and methods
		return {
			advance_slideshow: function(){
				if (current_slide < slides_array.length-num_slides_displayed){
					this.go_to_slide(current_slide+1);
				}
				else{
					if (slideshow_options.loop_behavior === WC.UI.slideshow.options.loop_behavior.REWIND){
						this.go_to_slide(0);
					}
					else if (slideshow_options.loop_behavior === WC.UI.slideshow.options.loop_behavior.YOYO){
					}
				}
			},
			regress_slideshow: function(){
				if (current_slide!=0){
					this.go_to_slide(current_slide - 1);
				}
				else {
					this.go_to_slide(slides_array.length-1);
				}
			},
			go_to_slide: function(index){
				if (index >= slides_array.length - num_slides_displayed) {
					index = slides_array.length - num_slides_displayed;
				}
				current_slide = index;
				$(slideshow_div).animate({'left': slideshow_options.slideOffset*index+'px'}, "slow");
				
				
				for (var i = 0; i< slides_array.length; i++){
					$('#icon' + i).removeClass('on');
				}
				$('#icon' + index).addClass('on');
				$('#icon' + (index + 1)).addClass('on');
				
			},
			get_id: function(){
				return slideshow_id;
			}
		};
	}
};


/**
* Add/Remove active state classname to an element
* @class
* @example
* WC.UI.button.activate('#btn');
* WC.UI.button.deactivate('#btn');
*/
WC.UI.button = {
	/**
	* Add active class to element
	* @function
	*/
	activate: function(element){
		// active classes for buttons that spawn modals include superior z - index;
		element.addClass('active');	
	},
	/**
	* Remove active class from element
	* @function
	*/
	deactivate: function(element){
		element.removeClass('active');
	}
};


/**
* Simple clear field on focus function
* @function
* @example 
* WC.UI.clear_field('#field');
*/
WC.UI.clear_field = function(element){
	$(element).focus(function(){
		$(this).val('');
	});
};


/*
* TODO:
* Save Overlay created for HOPS editor
* Consider rolling something here into another modal
* saveOverlay.init('#cancelChanges', {
	'loader_img': 'http://webmedia.med.cornell.edu/cmn/weillcornell/images/loading.gif',
	'content': 'Saving...'
});
*/
var saveOverlay = function(){
	// private overlay functions
	var overlay = {
		get_dimensions: function(){
			// get window height and width
			var window_width = $(window).width(),
				window_height = $(window).height();
			// return then in an array
			return [window_width, window_height];
		},
		size_overlay: function(){
			// grab current screen dimensions
			var dimensions = this.get_dimensions();
			// inline style the overlay div
			this.overlay_div.css({
				'width': dimensions[0] + 'px',
				'height': dimensions[1] + 'px'
			});
		},
		position_content: function(){
			// grab current screen dimensions
			var dimensions = this.get_dimensions();
			// inline style the content div
			this.content_div.css('left', ( Math.round( dimensions[0] - 100 ) / 2 ) + 'px');
		},
		close: function(){
			// fade out overlay div and content, then remove
			$('.overlay_div').fadeOut(300, function(){ $(this).remove() });
			$('.overlay_content').fadeOut(300, function(){ $(this).remove() });
		},
		add: function(options){
			
			// create both elements
			this.overlay_div = $('<div class="overlay_div"></div>');
			this.content_div = $('<div class="overlay_content"></div>');
			
			// if no options, create empty object
			var options = options || {},
				// save context for annoymous
				self = this;
			
			// append overlay div
			$('body').append(this.overlay_div);
			// size the overlay div, style it, fade it in, bind the close
			this.size_overlay();
			this.overlay_div
				.addClass('div.saving_overlay')
				.css('opacity', '0.0')
				//.bind('click', function(){ self.close() });

			$('body').append(this.content_div);
			// position the content, append the loading image and message
			// adjust css width for bigger content area
			this.position_content();
			this.content_div
				.append('<img src="' + options.loader_img + '" />\n<h4>' + options.content + '</h4>')

			// fade'em in
			this.overlay_div.animate({ opacity: options.opacity || '0.4' },  300)
			this.content_div.fadeIn(300);
			
			// bind window resize
			$(window).resize(function(){
				self.size_overlay();
				self.position_content();
			});
		}
	};
	
	return {
		init: function(trigger, options){
			if (typeof $ !== 'function') return;
			// bind click to save button
			$(trigger).bind('click', function(e){
				var e = e || window.event;
				overlay.add(options);
				e.preventDefault();
			});
		},
		close: overlay.close
	};
}();


/**
* Simple standalone overlay
* @class
* @example
* <em>var overlay = WC.UI.overlay.init(function(){});
* overlay.close()</em>
*/
WC.UI.overlay = {

	/** 
	* Init function for adding overlay, callback function
	* @private
	* @param {function} callback Any additional close statements to be fired
	*/
	init: function(callback){
		
		var self = this; 
		this.callback = callback;
		
		// if overlay exists, stop script
		if ($('.overlay').css('display') == 'block') return;
		
		// if not harcoded like GSA page, append html to end of body
		if (!$('body').hasClass('GSA_results')){
			$('body').append('<div class="overlay"></div>');
		}
		
		// size the div 
		this.size_it();
		
		// position overlay and fade it in
		$('.overlay')
			.css({
				'backgroundColor': '#111',
				'position': WC.UTIL.is_ie6 ? 'absolute' : 'fixed',
				'opacity': '0.0',
				'display': 'block'
			})
			.animate({ 'opacity': '0.7' }, 300)
			.bind('click', function(){
				self.close();
			});
			
		// bind window resize function
		$(window).resize(function(){
			self.size_it();
		});
	},
	
	/** 
	* Size the overlay to fit the screen
	* @function
	*/
	size_it: function(){
		$('.overlay').css({
			'width': $(window).width(),
			'height': WC.UTIL.is_ie6 ? '3000px' : $(window).height()
		});
	},
	
	/** 
	* close the overlay and fire callback fn
	* @private
	*/
	close: function(){
		
		// fire callback function
		if (this.callback){
			this.callback();
		}
		// if this is not the GSA page and anything else
		// fadeout and remove the modal
		if (!$('body').hasClass('GSA_results')){
			$('.overlay').fadeOut(400, function(){ $(this).remove() });
		}
		// else on GSA overlay cannot be appended and is hard coded (no js DOM injection)
		// in the future all overlays should be hardcoded if there is to be one
		else {
			$('.overlay').fadeOut(400);
		}
		
			
	}
};


/**
* Multiple menu hover show/hide content with optional modal
* @class
* @example 
* <em>WC.UI.multi_menu.init('ul#parent', {
*	'speed': 400, 
*	'custom': 'div.child_to_show_if_not_ul'
* });</em>
* 'custom' is a optional custom child div to close rather than just an li.
*/
WC.UI.multi_menu = {
	init: function( parent, options ){
		// if no parent, stop
		if (!parent) return;
		
		// save options or defaults
		var options 	= options || {};
		this.speed 		= options.speed || 300;
		this.to_show 	= options.custom || 'ul:eq(0)';

		// bind rollover functions
		$(parent + ' li').hover( this.over, this.out );
	},
	over: function(){

		var speed = WC.UI.multi_menu.speed,
			the_child = $(this).contents(WC.UI.multi_menu.to_show);
				
		// if there is no child then don't continue
		if (the_child.length < 1) return;

		$(this)
			// add over class to that particular li
			.addClass('over')
			// find first a and and activate
			.find('a:eq(0)').addClass('active');

		// save context
		var menu = $(this);
		// set 100 ms timer for quick movements to ensure 
		// there is a mouse over
		setTimeout(function(){
			// after timer, if still has over then we
			// show the hidden element and keep the parent li active
			if (menu.hasClass('over')){

				// add active class to first a only
				$('a:eq(0)', this).addClass('active');
				// hide it to kill lingering animations, then show it
				the_child.fadeIn( speed )
			}
		}, 100);
	},
	out: function(){

		var speed = WC.UI.multi_menu.speed,
			the_child = $(this).contents(WC.UI.multi_menu.to_show);
			
		// if there is no child then don't continue
		if (the_child.length < 1) return;

		// save context
		var menu = $(this);
				
		// set timer on close, giving time for accidental mouseout
		setTimeout(function(){
			
			// making sure there is no over ensures that the 
			// parent li does not lose it's active state prematurely
			if (!menu.hasClass('over')){
	
				// remove the active class from all a tags
				$('a', menu).removeClass('active');
				// show it
				the_child.fadeOut( speed );
			}
		}, 100);
		
		// call this last so there is time for the above
		$(this).removeClass('over');
	}
};


/**
* Bleed an element off the page from inside a parent on the right
* @function
*/
WC.UI.bleed_element = function(element, parent){ 

	var bleed_width;
	
	/** @private */
	function size_bleed(){
		// determine bleed width for element
		bleed_width = ($(window).width() > '970')
						? ($(window).width() - ($(parent).offset().left + $(parent).outerWidth()))
						: '0';
						
		// size the bleed box
		$(element).css({
			'right': -bleed_width + 'px',
			'width': bleed_width + 'px'
		});
	};
	
	// call it
	size_bleed();
	// bind the window resize resizing
	$(window).bind('resize', size_bleed);
};


/** 
* Filter a list of elements
* @class
*/
WC.UI.content_filter = function(){
	
	/**
	* Filtering action
	* @private
	*/
	function do_filter(elements, split){
		// for each element
		$(elements).each(function(i){
			// match it against each split member
			for (var i in split){
				// add appropriate class if match or no match
				if ($(this).text().toLowerCase().indexOf(split[i]) === -1){
					$(this).addClass('no_match');
				}
				else {
					$(this).removeClass('no_match');
				}
			}
		});	
	}
	
	return {
		/** 
		* Bind keyup to input, list of elements to filter
		* @public
		* @param {String} input selector
		* @param {String} elements comma seperated string of content elements to filter
		*/
		init: function(input, elements){
		
			var val, split;
		
			// on keyup
			$(input).keyup(function(){
				// grab lowercase value
				val = $(this).val().toLowerCase();
				// split it
				split = val.split(' ');
				// filter the elements list
				do_filter(elements, split);
			});
		}
	}
}();


/* ----------------------------------------------------------------------------------- */


/** 
* Health library specific classes
* @class
*/
WC.HealthLibrary = {
	
	/** 
	* Show health library articles in modal window and display mapped services
	* @class
	* @example
	* See <a href="http://cornellent.org">www.cornellent.org</a> for full example.
	*/
	modal: {
		
		/**
		* Construct article modal
		* @private
		* @param {string} article_id The article link id
		*/
		setup: function(article_id){
			// close any existing modal
			this.close();
			// init modal
			this.append_content(article_id);
			// get article content height
			var article_content_height = $('.hl_modal').height();
			// give ie6 a different height than other browsers...
			if (WC.UTIL.is_ie6){
				$('.l').css('height', article_content_height + 46);	
			}
			else {
				$('.l').css('height', article_content_height + 55);	
			}
		
			// scroll the page back to the top
			$('html, body').animate({ scrollTop: 0 }, 800);
		},
		
		/**
		* Append modal content
		* @private
		*/
		append_content: function(article_id){
			// select the article based on the link class
			var article_content = $('#articles div.' + article_id).html();
			// if this particular article does not exists...
			if (article_content === null){
				alert('We apologize, this article is temporarily being updated. Please check back later.');
				return;
			}
		
			var that = this;
			// currently not using any modal overlay
			this.append_overlay();
			// modal template
			// CSS should be moved from site.css to the asset possibly
			var modal = '<div class="modal_container">\n<div class="left_shadow">\n<div class="tl"></div>\n<div class="l"></div>\n</div>\n<div class="hl_modal">\n<div id="breadcrumb">\n<ul></ul>\n</div>\n';
			modal += '<div id="article_content" class="container colspan-24">' + article_content + '</div>\n';
			modal += '<div id="close">close&nbsp;&nbsp;<a href="">X</a></div>\n<div id="related_services" class="container colspan-7 last">\n</div>\n';
			modal += '</div>\n<div class="bottom_shadow">\n<div class="bl"></div>\n<div class="b"></div>\n<div class="br"></div>\n</div></div>';
	
			// get the related services
			that.populate_services(article_id,'#related_services');
			// Append our modal
			$('body').append(modal);
			// Run the template script to set the breadcrumb for us
			WC.Template.setup();			
			//position the modal
			that.position_modal();
			// if ie 6, we need to run the pngFix to the appended transparent content function before showing
			if ($.browser.msie){
				$('.left_shadow, .bottom_shadow').pngFix(); 
				$('.modal_container').show();
			}
			else {
				$('.modal_container').fadeIn(400);
			}
		},
	
		/**
		* Populate the services in modal
		* @private
		* @param {string} service_cont The selector for the service div container
		*/
		populate_services: function(article_id, service_cont){
			// grab the services mapping 
			$.getScript(site.service_map_location,
				function(){ 
					// find that appropriate array with given ID
					var services = service_map[article_id];
				
					// create temp array to hold html list
					var html_tmp_arr = [];
					html_tmp_arr.push('<h4>Related ENT Services</h4><ul>');
								
					// if there is no match, return null					
					if (services === undefined) return;
					
					// loop through the file and return the appropriate services array, build <li> links
					for (var i=0; i<services.length; i+=1){
						var service_name = services[i];
						// turn to lowercase and replace spaces with underscores
						var service_link = services[i].toLowerCase().replace(/\s/g, '_').replace(/^\s+|\(|\)|\s+$/g, '');
						// need to abstract service dirname
						html_tmp_arr.push('<li><a href="../healthcare_services/' + service_link + '.html">' + service_name + '</a></li>');
					}
					html_tmp_arr.push('</ul>\n');
					// join array items for output - increases speed over string concatenation 
					var html_output = html_tmp_arr.join('');
					// append html to page
					$(service_cont).append(html_output);
				}
			);
		},
		
		/** 
		* Positoin Modal
		* @private
		*/
		position_modal: function(){
			var wrapper_offset = $('#content_wrapper').offset();
			var pos_left = wrapper_offset.left;
			$('.modal_container').css('left', pos_left - 5);
		},
		
		/** 
		* Add overlay
		* @private
		*/
		append_overlay: function(){
			// currently not using modal overlay
			// BUG: does not show as transparent in ie7
			$('body').append('<div class="overlay"></div>');
			this.size_overlay();
			$('.overlay').css('opacity', 0.7).fadeIn(100);
			$(window).resize(function(){ WC.HealthLibrary.modal.size_overlay(); });
		},
		
		/** 
		* Size the overlay
		* @private
		*/
		size_overlay: function(){
			$('.overlay').css({
				width: $(window).width(),
				height: $(window).height()
			});
			if ($.browser.msie && $.browser.version === '6.0'){
				$('.overlay').css({
					height: '5000px',
					position: 'absolute'
				});
			}
		},
		
		/** 
		* Close all items
		* @private
		*/		
		close: function(){
			$('.overlay, .modal_container').fadeOut(200, 
				function(){ 
					$(this).remove();
				}
			); 
		}
	},

	/** 
	* Filter health library links on a main library list page
	* @class
	*/	
	filter: {
		
		/**
		* Filter item collection array
		* @property
		*/
		collection: [],
		
		/**
		* Create the collection
		* @private
		*/
		create_filter_collection: function(selector){
			var group = $(selector);
			for (var i=0; i<group.length; i+=1){
				this.collection.push($(group[i]).text());
			}
		},
		
		/**
		* Filter article links action
		* @private
		*/
		filter_articles: function(content_selector, list_selector, query){
			// get content column height for when list starts to filter
			// lock the col height so it does not shrink up and make a page jump
			var col_height = $(content_selector).height();
			$('#col_2').css('height', col_height);
			// change query to lower
			query = query.toLowerCase();
			// return null if query is backspaced to 0 length
			if (query.length === 0){
				this.show_collection(list_selector);
				return;
			}
			// run through the collection and match the query
			for (var i=0; i<this.collection.length; i+=1){
				var term = this.collection[i].toLowerCase();
				// hide those that don't match...
				if (term.match(query) === null){
					$(list_selector + ':eq(' + i + ')').css('display','none');
				}
				// if already hidden, show the ones that do match
				else 
					$(list_selector + ':eq(' + i + ')').css('display','inline');
			}
		},
		
		/**
		* Show hidden
		* @private
		*/
		show_collection: function(list_selector){
			$(list_selector).fadeIn(400);
			$('#col_2').removeAttr('style');
		}
	},
	

	/** 
	* Show related health articles on service page
	* @private
	* @requires services_format_exceptions object
	*/
	show_related_articles: function(){
		// grab the first index of the page.sub array
		var cur_service = page.sub[0] !== undefined ? page.sub[0].replace(/^\s+|\s+$/g, '') : '',
			// get jquery collection array of articles
			articles_array = $('#articles .article'),
			// initiate collection array
			article_class_collection = [];
		
		// create a article class collection array from the hidden articles in the page		
		for (var i=0; i<articles_array.length; i+=1){
			var article_classes = $(articles_array[i]).attr('class');
			var classes_array = article_classes.split(' ');
			article_class_collection.push(classes_array[1]);
		}
		
		// get our mapping json script
		// anonymous function wrapper to pass in exeptions
		(function(){
			
			$.getScript(site.service_map_location,
				function(){
					// open our html temp array holder
					var html_tmp_arr = [];
					html_tmp_arr.push('<h4>Related Health Articles</h4>\n<ul>');
					// set a counter and current hidden state
					var count = 0,
						some_hidden = false;
					// loop through the article class collection created above
					for (var i=0; i<article_class_collection.length; i+=1){
						// each specific article class
						var article_class = article_class_collection[i],
						// seach mapped service array from article_class
							article_services = service_map[article_class];
						// if the spcific service array is found based on article_class
						if (article_services !== undefined){
							// loop through those services...
							for (var x=0; x<article_services.length; x+=1){
								var this_service = article_services[x];
								// if the service matches a service in an article array, add it to the html string
								if (this_service === cur_service){
									var article_name = article_class.replace(/_/g, ' '),
										article_id = article_class;
									// check the exceptions list to format properly
									for (var p in services_format_exceptions){
										if (article_name == p.toLowerCase())
											article_name = services_format_exceptions[p];
									}
									// if we are on the 14th match, then our list is as high as we want it to be
									if (count >= 14){
										// time to hide the rest
										some_hidden = true;
										html_tmp_arr.push('<li class="hide"><a href="" id="' + article_id + '">' + article_name + '</a></li>');
									}
									else {
										// display them as normal\n
										html_tmp_arr.push('<li><a href="" id="' + article_id + '">' + article_name + '</a></li>');
									}
									count += 1;
								}
							}
						}
					}
					if (some_hidden === true){
						html_tmp_arr.push('<li><a href="" id="toggle_article_list">Show more</a></li>\n');
					}
				
					// close our ul and div
					html_tmp_arr.push('</ul>\n');
					var html_output = html_tmp_arr.join('');
					// if there is at least one <li> in the html, append to page
					if (html_output.match('<li>')){
						$('#related_articles').append(html_output);
					}
				}
			);
		
		// pass in the service format exceptions from one anonymous to another
		})(services_format_exceptions);
	}
};




/**
* Utilities Object
* @namespace
*/
WC.UTIL = {
	/** 
	* Are you still around?
	* @property
	*/
	is_ie: 	typeof window.addEventListener === 'undefined',
	/** 
	* Really?
	* @property
	*/
	is_ie6: typeof window.XMLHttpRequest === 'undefined',
	/** 
	* Ehhhhh....
	* @property
	*/
	is_ie7: typeof window.XMLHttpRequest !== 'undefined' && typeof window.addEventListener === 'undefined',
	
	/** 
	* Transform string to a class, stripping all chars but letters and taking first four words
	* @function
	*/
	string_to_class: function(string){
		// strip out all characters but spaces
		string = string.toLowerCase().replace(/[\/\"\'\,\.\-\&\(\)\[\]\:\;]/gm, '');
		// if more than two spaces between words, strip one
		string = string.replace(/\s{2}/g, ' ');
		// save a match up to four words
		string = string.match(/(?:[a-z]*\s?){1,4}/);
		// strip the last space of the string
		string = string.toString().replace(/\s$/, '');
		// replace all spaces with underscores
		string = string.replace(/\s/gm, '_');
		return string;
	},
	
	/** 
	* Create, Read and Erase cookies
	* @class
	* @example
	* <em>var cookie = WC.UTIL.Cookie;
	* cookie.create('my_cookie', 'cookie_value', 1);
	* var cookie_value = cookie.read('my_cookie');
	* cookie.erase('my_cookie')</em>
	*/
	Cookie: {
		/**
		* Create the cookie
		* @private
		* @param {string} name Name of cookie
		* @param {any} value Value to be stored for cookie
		* @param {number} days Optional amount of days before expiration
		*/
		create: function( name, value, days ){
			// if we want to date it
			if (days){
				var date = new Date();
				date.setTime(date.getTime() + (days*24*60*60*1000));
				var expires = '; expires=' + date.toGMTString();
			}
			// else empty expires
			else var expires = '';
			// cache the cookie
			document.cookie = name + '=' + value + expires + '; path=/';
		},
		/**
		* Read out the stored cookie
		* @private
		* @param {string} name Name of cookie
		*/
		read: function( name ){
			// split cookie string at semi-colons
			var cookie_array = document.cookie.split(';'),
				cookie_length = cookie_array.length;
			// loop through array	
			for (var i=0; i<cookie_length; i+=1){
				// strip leading space and split into parts
				var cookies = cookie_array[i].replace(/^\s/, '').split('=');
				if (cookies[0] == name){
					return cookies[1];
				}
			}
			return null;
		},
		/**
		* Erase the cookie
		* @private
		*/
		erase: function( name ){
			this.create(name, '', -1);
		}
	},
	
	/** 
	* Simple debug bar to replace document.write and alert debugging
	* @class
	* @example
	* Add debug div to html element: <br/>
	* <em>var debug = WC.UTIL.Debug;
	* debug.init('body');
	* debug.write('error or thing to write');</em>
	*/
	Debug: {
		
		/**
		* Append the debug div to where you want it
		* @private
		*/
		init: function(where){ 
			$(where).append('<div id="error_log"></div>');
			$('#error_log').css({
				'backgroundColor': '#fff',
				'position': 'fixed',
				'bottom': '0',
				'left': '0',
				'padding': '15px 2%',
				'width': '98%',
				'color': '#ff3300',
				'z-index': '5000',
				'fontFamily': 'sans-serif',
				'fontSize': '12px'
			});
		},
		
		/**
		* Log what you want to see
		* @private
		*/
		write: function(tolog){
			$('#error_log').append(tolog + ', ');
		}
	},
	
	/** 
	* Simple logging function
	* @function
	*/
	log: function(){
		try {
			console.log.apply( console, arguments );
		} catch(e){
			try {
				opera.postError.apply( opera, arguments );
			} catch(e){
				alert( Array.prototype.join.call( arguments, ' ' ) );
			}
		}
	},
	
	/**
	* Assert value - compliments of JResig
	* @function
	*/
	assert: function(){
		var li = document.createElement('li');
		li.className = value ? 'pass' : 'fail';
		li.appendChild( document.createTextNode( desc ) );
		document.getElementById('results').appendChild( li );
	}, 
	
	/** 
	* Print out a formatted date with custom delimeter
	* @function
	* @param {string} delimeter The type of delimeter you want to use for the date string
	*/
	get_date: function(delimeter){
		var date = new Date();
		var month = date.getMonth();
		var day = date.getDay();
		var year = date.getFullYear();
		var date_string = month + delimeter + day + delimeter + year;
		return date_string;
	}
};


// bind to window
window.WC = WC;


})( window );








