/** 
 *	commuterlink_traffic v1.0.4
 *	
 *	Version log:
 *	1.0.4 -	Cleaned up documentation & removed <form> (button click only is fine)
 *	1.0.3 - Moved ct-options HTML to load via javascript,  fixed default zip code bug & added save/loading cookie options
 *	1.0.2 - Added adding show_advanced options
 *	1.0.1 - Added enable_pager option
 *	1.0.0 - Inital
*/
;(function($) {        
	$.fn.commuterlink_traffic = function(config) {
		$.fn.commuterlink_traffic.opts = $.extend({
			'url'				:	'connector.php', 
			'zip'				:	'84105', 
			'camera_limit'		:	20, 
			'camera_offset'		:	0,
			'camera_page'		:	1,
			'camera_url_prefix'	:	'http://commuterlink.utah.gov/1_devices/aux', 
			'camera_url_suffix'	:	'.jpeg', 
			'easing'			:	'drop', 
			'easing_time'		:	400,
			'enable_pager'		:	true,
			'show_advanced'		:	true,
			'next'				:	'Next', 
			'prev'				:	'Prev',
			'within_miles'		:	50,
			'sort_by'			:	'Congestion',
			'easing_opts'		:	{'direction' : 'up'}, 
			'ver'				:	'1.0.3', 
			'look_within_miles'	:	50, 
			'sort_by'			:	'Congestion'
			
		}, config);
		
		return this.each(function() {

				$.fn.commuterlink_traffic.load_traffic_html(this);
				$.fn.commuterlink_traffic.load_stored_config();
				$.fn.commuterlink_traffic.init(this);
				$.fn.commuterlink_traffic.refresh(this);

		}); 
	};

	/**
	 *	Populate container HTML, setup defaults, opts form submission
	 *	@param container object Traffic container object
	*/
	$.fn.commuterlink_traffic.init = function(container) {
				
			$('#ct-traffic-opt-container-sort', container).selectable();
			//Only allow 1 selection (radio style)
			$('#ct-traffic-opt-container-sort', container).bind('selectableselected',function(e, ui) {
				$('.ui-selected',this).not(ui.selected).removeClass("ui-selected");
			}); 

			$('#ct-traffic-options-link', container).click(function() { 
				$('#ct-traffic-options', container).slideToggle();
			}); 
			
			$('#ct-traffic-opts-container-look-within-miles').buttonset();
			
			$('#ct-traffic-opts-container-buttons :input').button();

				
			$('<div class="ct-camera-data" />')
				.appendTo(container);
			;
			var pager = $('<div class="ct-camera-pager" />')
				.appendTo(container);
			; 
			
			//Update the default zipcode
			$.fn.commuterlink_traffic.refresh_zipcode(container);
			
			//Options form submission handler - not a real form, just handle the button click
			$('#ct-traffic-options .ct-traffic-opts-submit').click(function() { 
				//Reset pager offset
				$.fn.commuterlink_traffic.opts.camera_offset = 0; 

				//Update options panel
				var zip = $.fn.commuterlink_traffic.refresh_zipcode(container);
				$.fn.commuterlink_traffic.opts.zip = zip;
				
				//Update the container
				$.fn.commuterlink_traffic.refresh(container);


				return false;
				

			}); 
			
			
			
			return container;

				
	}; 
	/**
	 *	Select a specific page view
	 *	@param container object Traffic Container
	 *	@param page int The page number
	*/
	$.fn.commuterlink_traffic.select_page = function(container, page) {

		page = (page > 0) ? page : 0;

		$.fn.commuterlink_traffic.opts.camera_offset = page - 1;
		$.fn.commuterlink_traffic.refresh(container);
	};
	
	/**
	 *	Select the next page
	 *	@param container object Traffic container
	*/
	$.fn.commuterlink_traffic.next = function(container) {
		$.fn.commuterlink_traffic.opts.camera_offset++;
		$.fn.commuterlink_traffic.refresh(container);
		return false;
	};

	/**
	 *	Select the previous page
	 *	@param container object Traffic container
	*/
	$.fn.commuterlink_traffic.prev = function(container) {
		if ( $.fn.commuterlink_traffic.opts.camera_offset > 0 ) {
			$.fn.commuterlink_traffic.opts.camera_offset--;
			$.fn.commuterlink_traffic.refresh(container);
		}
		return false;
	};

	/**
	 *	Update the traffic container with set opts
	 *	@param container Traffic container
	*/
	$.fn.commuterlink_traffic.refresh = function(container) {
		var opts = $.fn.commuterlink_traffic.opts;
		var content = $('.ct-camera-data', container);
	
		//miles_from
		//sort_by
		//Update config object with user preferences
				
		var sort_by = $('#ct-traffic-opt-container-sort li.ui-selected', container).attr('selected-sort'); 
		var within_miles = $('#ct-traffic-opts-container-look-within-miles :checked').first().val(); 
		if ( sort_by == undefined || within_miles == undefined) { 
			return false; 
		}
		
		opts.look_within_miles = within_miles; 
		opts.sort_by = sort_by; 
		
		$.jsonp({
				'url'		:	opts.url, 
				'data'		:	{
								'func'		:	'fetch_traffic_speed_by_zipcode', 
								'opts'		:	[ opts.zip, opts.camera_limit, (opts.camera_offset * opts.camera_limit) , within_miles, sort_by ]
								},
				'success'	:	function(json, status) {

									if ( json.meta.success == true ) { 
										if ( json.meta.total > 0 ) { 

											//Lock the height to prevent pager from moving around, add a bit of padding to prevnet cutting the pager
											$.fn.commuterlink_traffic.update_traffic_display(container , json.data);
											if ( opts.enable_pager == true ) { 
												$.fn.commuterlink_traffic.update_pager(container, json.meta.total);
											}
											
											//Save settings;
											$.fn.commuterlink_traffic.save_config();
										} else {
											//Zero results found
											$('.ct-camera-data', container).stop(true,true).css('min-height', '50px').html('<p style="padding:25px 0;text-align:center;font-weight:bold;">No results found.</p>').show();
											return false;
										}
										
									} else {
										$('.ct-camera-data', container).html('<p>Could not fetch traffic information.  Please try again later.</p>').show();
										return false;
									}
								}
		});
		//Only fade out if we have results 
		if ( $('img', content).size() > 0 ) { 
			$(content).hide(opts.easing, opts.easing_opts, opts.easing_time);
		}

	};
	
	/**
	 *	Update any text zipcodes
	 *	@param container object Traffic Container
	*/
	$.fn.commuterlink_traffic.refresh_zipcode = function(container) { 
		var zip = $('#ct-traffic-options-zip', container).val(); 
		if ( $.fn.commuterlink_traffic.validate_zipcode(zip) != true ) { 
			zip = $.fn.commuterlink_traffic.opts.zip;
		}

		
		$('#ct-traffic-options-zip').val(zip); 
		$('.ct-zip-val').text(zip);
		return zip;
		
	};

	/**
	 *	Validate a zipcode
	 *	@param container int zipcode to validate
	 *	@return bool True if valid
	*/
	$.fn.commuterlink_traffic.validate_zipcode = function(zip) { 
		return ( parseInt(zip) && zip.toString().length == 5 );
	};
	
	
	/**
	 *	Re-build the pager with the current page
	*/
	$.fn.commuterlink_traffic.update_pager = function(container, total) { 
		var opts = $.fn.commuterlink_traffic.opts;

		var pages = Math.ceil( total / opts.camera_limit );
		var current = opts.camera_offset+1;


		var last = ( pages==current );
		var first = ( opts.camera_offset == 0 );
	
		var linkclass; 
		
		var pager = $('.ct-camera-pager', container).empty();

		linkclass = ( last==false ) ? 'ct-link-next' : 'ct-link-next ct-link-disabled';
		$('<a />')
			.attr({
				'href' : 'javascript:void(0);', 
				'class' : linkclass
			})
			.html(opts.next)
			.click(function() {
				if ( last == false ) 
					$.fn.commuterlink_traffic.next(container)
			})
			.appendTo(pager)
		;
		
		linkclass = ( first==false ) ? 'ct-link-prev' : 'ct-link-prev ct-link-disabled'; 
		$('<a />')
			.attr({
				'href' : 'javascript:void(0);', 
				'class' : linkclass
			})
			.html(opts.prev)
			.click(function() {
				if ( first == false ) 
					$.fn.commuterlink_traffic.prev(container)
			})
			.appendTo(pager)
		;
		
		//Info container
		var info = $('<div class="ct-pager-info" />')
			.css({
				'clear'		:	'both'
			})
			.appendTo(pager);
		;
		
		//$(info).html('Page <b>' + current + '</b> of <b>' + pages + '</b>');
		$(info).html('<b>' + current + '</b> / <b>' + pages + '</b>');

		
		

		
	};
	
	$.fn.commuterlink_traffic.update_traffic_display = function(container, items) {
			var opts = $.fn.commuterlink_traffic.opts;

			if ( !(items.length>0) ) {
				return false;
			}
			var content = $('.ct-camera-data', container);

			$(content).empty();	
			for( i=0; i < items.length; i++) {

					var img = $('<img/>')
							.attr({
								  'class' 	:	'ct-image',
								  'src'		:	opts.camera_url_prefix + items[i].device_id + opts.camera_url_suffix
							})
							.wrap('<div class="ct-image-container" />')
					;
					
					

					var title = $('<div class="ct-station-name" />')
						.append( items[i].station_name.toString() )
					; 
					var city = $('<div class="ct-station-city" />')
						.append( items[i].city.toString() )
					;

					
					var mph_speed = 			'<div class="ct-mph">MPH: <span class="ct-val">' + items[i].mph_speed.toString() + '</span></div>';
					var vehicles_per_minute = 	'<div class="ct-vpm">Vehicles/Min: <span class="ct-val">' + items[i].vehicles_per_minute.toString() + '</span></div>';
					
					var info = $('<div class="ct-station-info" />')
						.append( mph_speed)
						.append(vehicles_per_minute)
					;
					
					var station = $('<div class="ct-station" />')
						.append(title)
						.append(city)
						.append(img)
						.append(info)
						.appendTo(content)
					;

					//Commuterlink Cameras image pulsing
					$(station).imagepulser({
							width: 320, 
							height: 240, 
							//padding_top: 18, 
							//padding_left: 25, 
							easing_open_effect: 'easeInOutCirc', 
							easing_close_effect: 'easeOutBounce', 
							
							title_formatter: function(item) { 

								var title = $('<p/>')
												.append( $(item).data('parent').siblings('.ct-station-name').html() )
												.append( $(item).data('parent').siblings('.ct-station-info').html() )
								;

								return title;
							
							}
					});
					
					if ( i == (items.length-1) ) { 
						//Last item
						$(station).addClass('ct-station-last');
					}
			}
			
			$(content).show(opts.easing, opts.easing_opts, opts.easing_time, function() {
				//Now move the pager if the container has changed size
				//$(container).css({ height: 'auto' });
				if ( opts.camera_offset == 0 )  {
					window.setTimeout(function() {
						$(content).css({ height : $(content).height() });
					}, 1000);
				}
					
			});
			
			
	};



	/**
	 *	Make a JSONp request
	 *	@param config object jsonp config
	 *	@param callback function Success callback
	*/
	$.fn.commuterlink_traffic.request = function(config, callback) {
		//jsonp config
		var jpconfig = $.extend({
				'url'		:	opts.url,
				'success'	:	callback
				
		}, config);
		
		$.jsonp(jpconfig); 
	}; 
	
	/**
	 *	Load a saved configuration from cookie storage
	*/
	$.fn.commuterlink_traffic.load_stored_config = function() {
		var opts = $.fn.commuterlink_traffic.opts;
		var store = 'commuterlink_feed-opts-' + opts.ver; 
		var o = $.fn.commuterlink_traffic.cookie(store); 
	

		if ( o != undefined ) { 
			o = $.evalJSON(o);
			
			opts.zip = o.zip;
			opts.camera_limit = o.camera_limit; 
			opts.camera_offset = o.camera_offset;
			opts.look_within_miles = o.look_within_miles; 
			opts.sort_by = o.sort_by; 
			
			//Update local settings
			$('#ct-traffic-opt-container-sort .ui-selected').removeClass('ui-selected');
			$('#ct-traffic-opt-container-sort li[selected-sort="'+o.sort_by+'"]').addClass('ui-selected');
			
			$('#ct-traffic-opts-container-look-within-miles :checked').attr('checked', false);
			$('#ct-traffic-opts-container-look-within-miles [value="'+o.look_within_miles+'"]').attr('checked', true);
			
		}
		return true;
		
	}

	/**
	 *	Save the current configuration from cookie-storage
	*/
	$.fn.commuterlink_traffic.save_config = function() {
		var opts = $.fn.commuterlink_traffic.opts;
		var store = 'commuterlink_feed-opts-' + opts.ver; 
		var o = {
			'zip'	:	opts.zip, 
			'camera_limit'	:	opts.camera_limit, 
			'camera_offset'	:	opts.camera_offset, 
			'look_within_miles'	:	opts.look_within_miles,
			'sort_by'			:	opts.sort_by
		}; 
		$.fn.commuterlink_traffic.cookie(store, $.toJSON(o) ); 
		return true;
	}
	
	
	
	/**
	 *	Populate the container with base HTML (should only be called during init)
	 *	@param container object Traffic container
	*/
	
	$.fn.commuterlink_traffic.load_traffic_html = function(container) {	
		var html = '																											\
																																\
<span class="ui-icon ui-icon-wrench" style="float:left;"></span>																\
<a id="ct-traffic-options-link" href="javascript:void(0);">Options</a>															\
<br class="clear" />																											\
																																\
<div id="ct-traffic-options">																									\
	<form id="ct-traffic-opts-form">																								\
	  <b>Sort By:</b>																												\
	  <ul id="ct-traffic-opt-container-sort">																						\
		<li class="ui-selected" selected-sort="Congestion" >Congestion</li>								\
		<li selected-sort="MPH" >MPH (Slowest)</li>														\
		<li selected-sort="VPM" >Vehicles per minute</li>												\
		<li selected-sort="Distance">Distance from <span class="ct-zip-val">84105</span></li>			\
	  </ul>																															\
	  <br />																														\
	  <b>Look Within:</b>																											\
	  <div id="ct-traffic-opts-container-look-within">																				\
		<div id="ct-traffic-opts-container-look-within-miles">																		\
		  <input type="radio" name="ct-traffic-opts-look-within-miles" id="ct-traffic-opts-look-within-miles-5" value="5" />		\
		  <label for="ct-traffic-opts-look-within-miles-5">5</label>																\
		  <input type="radio" name="ct-traffic-opts-look-within-miles" id="ct-traffic-opts-look-within-miles-10" value="10" />		\
		  <label for="ct-traffic-opts-look-within-miles-10">10</label>																\
		  <input type="radio" name="ct-traffic-opts-look-within-miles" id="ct-traffic-opts-look-within-miles-25" value="25" />		\
		  <label for="ct-traffic-opts-look-within-miles-25">25</label>																\
		  <input type="radio" name="ct-traffic-opts-look-within-miles" id="ct-traffic-opts-look-within-miles-50" value="50" checked="checked" />		\
		  <label for="ct-traffic-opts-look-within-miles-50">50</label>																\
		</div>																														\
		<b>Miles of </b> <input size="5" maxlength="5" name="ct-traffic-options-zip" id="ct-traffic-options-zip" />					\
	  </div>																														\
	  <div id="ct-traffic-opts-container-buttons">																					\
		<input type="button" value="Go" class="ct-traffic-opts-submit" />																							\
	  </div>																														\
	</form>																															\
</div>																																\
																																	\
		';
		
		$(container).html(html);
		return true;
		
	}
	
	
	
	
	
	/** 
	 *	Properties
	*/
	$.fn.commuterlink_traffic.opts = {}; 
	$.fn.commuterlink_traffic.data = {}; 
	$.fn.commuterlink_traffic.meta = {}; 
	
	
	
	
	
	
	
	
	
	/** 
	 * jQuery cookie from
	 * http://plugins.jquery.com/files/jquery.cookie.js.txt
	*
	 * Cookie plugin
	 *
	 * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
	 * Dual licensed under the MIT and GPL licenses:
	 * http://www.opensource.org/licenses/mit-license.php
	 * http://www.gnu.org/licenses/gpl.html
	 *
	 */
	$.fn.commuterlink_traffic.cookie = function(name, value, options) {
		if (typeof value != 'undefined') { // name and value given, set cookie
			options = options || {};
			if (value === null) {
				value = '';
				options.expires = -1;
			}
			var expires = '';
			if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
				var date;
				if (typeof options.expires == 'number') {
					date = new Date();
					date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
				} else {
					date = options.expires;
				}
				expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
			}
			// CAUTION: Needed to parenthesize options.path and options.domain
			// in the following expressions, otherwise they evaluate to undefined
			// in the packed version for some reason...
			var path = options.path ? '; path=' + (options.path) : '';
			var domain = options.domain ? '; domain=' + (options.domain) : '';
			var secure = options.secure ? '; secure' : '';
			document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
		} else { // only name given, get cookie
			var cookieValue = null;
			if (document.cookie && document.cookie != '') {
				var cookies = document.cookie.split(';');
				for (var i = 0; i < cookies.length; i++) {
					var cookie = jQuery.trim(cookies[i]);
					// Does this cookie string begin with the name we want?
					if (cookie.substring(0, name.length + 1) == (name + '=')) {
						cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
						break;
					}
				}
			}
			return cookieValue;
		}
	};	//end cookie	







		
})(jQuery);

		
		
		

/** 
 *	jquery.json.min.js 
 *	
*/

(function($){$.toJSON=function(o)
{if(typeof(JSON)=='object'&&JSON.stringify)
return JSON.stringify(o);var type=typeof(o);if(o===null)
return"null";if(type=="undefined")
return undefined;if(type=="number"||type=="boolean")
return o+"";if(type=="string")
return $.quoteString(o);if(type=='object')
{if(typeof o.toJSON=="function")
return $.toJSON(o.toJSON());if(o.constructor===Date)
{var month=o.getUTCMonth()+1;if(month<10)month='0'+month;var day=o.getUTCDate();if(day<10)day='0'+day;var year=o.getUTCFullYear();var hours=o.getUTCHours();if(hours<10)hours='0'+hours;var minutes=o.getUTCMinutes();if(minutes<10)minutes='0'+minutes;var seconds=o.getUTCSeconds();if(seconds<10)seconds='0'+seconds;var milli=o.getUTCMilliseconds();if(milli<100)milli='0'+milli;if(milli<10)milli='0'+milli;return'"'+year+'-'+month+'-'+day+'T'+
hours+':'+minutes+':'+seconds+'.'+milli+'Z"';}
if(o.constructor===Array)
{var ret=[];for(var i=0;i<o.length;i++)
ret.push($.toJSON(o[i])||"null");return"["+ret.join(",")+"]";}
var pairs=[];for(var k in o){var name;var type=typeof k;if(type=="number")
name='"'+k+'"';else if(type=="string")
name=$.quoteString(k);else
continue;if(typeof o[k]=="function")
continue;var val=$.toJSON(o[k]);pairs.push(name+":"+val);}
return"{"+pairs.join(", ")+"}";}};$.evalJSON=function(src)
{if(typeof(JSON)=='object'&&JSON.parse)
return JSON.parse(src);return eval("("+src+")");};$.secureEvalJSON=function(src)
{if(typeof(JSON)=='object'&&JSON.parse)
return JSON.parse(src);var filtered=src;filtered=filtered.replace(/\\["\\\/bfnrtu]/g,'@');filtered=filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']');filtered=filtered.replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered))
return eval("("+src+")");else
throw new SyntaxError("Error parsing JSON, source is not valid.");};$.quoteString=function(string)
{if(string.match(_escapeable))
{return'"'+string.replace(_escapeable,function(a)
{var c=_meta[a];if(typeof c==='string')return c;c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';}
return'"'+string+'"';};var _escapeable=/["\\\x00-\x1f\x7f-\x9f]/g;var _meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};})(jQuery);

		



		
		
		

