var wui = {};

/**
 * Reference to the global context.  In most cases this will be 'window'.
 */
wui.global = this;

/**
 * Positioning and visibility
 */
(function(wui, $) {

	var toggleVisibility_ids = [];
	wui.toggleVisibility = function(id) {
		toggleVisibility_ids.include(id);
		for (var i=0; i<toggleVisibility_ids.length; i++) {
			var toggleVisibility_id = toggleVisibility_ids[i];
			var elt = $(toggleVisibility_id);
			if (!elt) {
				continue;
			} else if (toggleVisibility_id === id) {
				elt.toggleClass("none");
			} else {
				elt.addClass("none");
			}
		}
	};
	
	wui.centerInWindow = function(id) {
		var elt = $(id);
		if (!elt) return;
		elt.setStyles({
			'position': 'absolute',
			'top': 0,
			'left': 0
		});
		var hasClassNone = false;
		if (elt.hasClass("none")) {
			hasClassNone = true;
			elt.removeClass("none");
		}
		var window_width = window.getWidth();
		var window_height = window.getHeight();
		var content_width = elt.getSize().size.x;
		var content_height = elt.getSize().size.y;
		var top = (window_height - content_height) / 2;
		var left = (window_width - content_width) / 2;
		elt.setStyles({
			'top': top,
			'left': left
		});
		if (hasClassNone) {
			elt.addClass("none");
		}
	};
	
	wui.dropdown = function(options) {
		this.options = $.extend(true, {
			selectorButton: null,
			selectorMenu: null,
			position: {
				my: "left top",
				at: "left bottom",
				of: null, // set immediately below
				offset: "0 0",
				collision: "none none"
			},
			delay: 100,
			hoverClass: null
		}, options ? options : {});
		this.options.position.of = this.options.selectorButton;
		
		var button = $(this.options.selectorButton);
		var menu = $(this.options.selectorMenu);
		$.data(menu, 'hover', false);
		var options = this.options;
	
		button.mouseenter(function(e) {
			menu.stop(true).show();
			button.addClass(options.hoverClass);
			menu.addClass(options.hoverClass);
			if(!$.data(menu, 'hover')){
				menu.css({"position":"absolute", "top":"0px", "left":"0px", "z-index":1000});
				menu.position(options.position);
			}
			
			if(StickerPopUp){
				StickerPopUp.forceHide();
			}

		}).mouseleave(function(e) {
			menu.delay(options.delay).hide(0);
			button.removeClass(options.hoverClass);
			menu.removeClass(options.hoverClass);
		});
		
		menu.mouseenter(function(e) {
			$.data(menu, 'hover', true);
			button.mouseenter();
			// menu.stop(true).show();
		}).mouseleave(function(e) {
			$.data(menu, 'hover', false);
			// menu.delay(options.delay).hide(0);
			button.mouseleave();
		});
	};
	
	$(document).ready(function() {
		// hover effect on the page header
		$("#optionBar").mouseenter(function(event) {
			$("#pageHeader").addClass("headerOver").removeClass("headerOff");
		}).mouseleave(function(event) {
			$("#pageHeader").addClass("headerOff").removeClass("headerOver");
		});
		
		// hover effect on the homepage geo image
		$("#picCred").mouseenter(function(event) {
			$("#geoData").fadeTo("slow", 0);
		}).mouseleave(function(event) {
			$("#geoData").fadeTo("slow", 1.00);
		});
		
		// hover effect on drop down menus
		new wui.dropdown({
			selectorButton: "#socialMore",
			selectorMenu: "#socialList",
			position: {
				my: "right top",
				at: "right bottom",
			},
			hoverClass: "hover",
			delay: 0 
		});

		new wui.dropdown({
			selectorButton: "#quickMenu",
			selectorMenu: "#quickMenuDropdown",
			position: {
				my: "left top",
				at: "left bottom",
			},
			hoverClass: "hover",
			delay: 0
		});

		new wui.dropdown({
			selectorButton: "#conds_details_radar .imageContain",
			selectorMenu: "#conds_details_radar_overlay",
			position: {
				my: "center center",
				at: "center center",
			},
			//hoverClass: "hover",
			delay: 0 
		});

		new wui.dropdown({
			selectorButton: "#wximage_img",
			selectorMenu: "#wximage_overlay",
			position: {
				my: "center center",
				at: "center center",
			},
			delay: 0 
		});
	});

	// YAZ 20110119 - extend tablesort for sorting columns that have numbers with commas like: "115,520.32"
	if ($.tablesorter) {
		$.tablesorter.addParser({
			id: "englishNumber",
			is: function (s, table) {
				// do not autodetect this type
				return false;
			},
			format: function (s) {
				// strip commas before converting to float for comparison
				return $.tablesorter.formatFloat(s.replace(new RegExp(/[,]/g),''));
			},
			type: "numeric"
		});
	}

})(wui, jQuery);

/**
 * geolocation
 */
(function(wui, $) {

	wui.geolocation = function() {
		if (navigator && navigator.geolocation) {
			navigator.geolocation.getCurrentPosition(showPosition);				
		}

		function showPosition(position) {
			var lat = position.coords.latitude;
			var lon = position.coords.longitude;
			if (wui.geolocation.getURL) {
				// example in scripts/auto_chrome.js
				var url = wui.geolocation.getURL(lat, lon);
				window.location = url;
			} else {
				window.location.search = "query="+lat+","+lon;				
			}
		}
	};
	
})(wui, jQuery);

/**
 * logging
 */
(function(wui, $) {

	var settings = {};
	
	wui.log = function(s) {
		wui.log.write(s);
	};

	wui.log.initialize = function() {
		settings.container = $("<div></div>").addClass("wui-log").appendTo(document.body).css({
			"position": "absolute",
			"bottom": "1em",
			"left": "1em"
		});
		// head and body
		settings.container_head = $("<div></div>").addClass("wui-log-head").appendTo(settings.container).html("wui.log");
		settings.container_body = $("<div></div>").addClass("wui-log-body").appendTo(settings.container);
		// close button
		var btn = $("<a></a>").addClass("wui-log-close").appendTo(settings.container_head).html("X");
		btn.attr("href","javascript:void(0);");
		btn.click(function(e) {
			e.preventDefault();
			wui.log.remove();
		});
		// drag
		settings.container.draggable({
			"handle": settings.container_head
		});
		// flag
		settings.initialized = true;
	};
	
	wui.log.write = function(s) {
		if (!settings.initialized) wui.log.initialize();
		var now = new Date();
		var milliseconds = ((now.getMilliseconds() / 1000).toFixed(3) + "").substr(2);
		var timestr = '<span class="wui-log-time">' + now.toLocaleTimeString() +"."+ milliseconds + '</span>';
		var row = $("<div></div>").addClass("wui-log-row").html(timestr + " " + s);
		row.appendTo(settings.container_body);
	};

	wui.log.remove = function() {
		settings.container.remove();
		settings.initialized = false;
	};
	
})(wui, jQuery);

/**
 * history
 */
(function(wui, $) {

	var hash = {};
	
	wui.history = {};
	
	wui.history.toQueryString = function() {
		var str = "#";
		var arr = [];
		for (var key in hash) {
			if (hash.hasOwnProperty(key)) {
				var val = hash[key];
				arr.push(key + "=" + encodeURIComponent(val));
			}
		}
		if (arr.length > 0) {
			str += '?' + arr.join('&');
		}
		return str;
	};
	
	wui.history.setKey = function(key, val) {
		hash[key] = val;
	};
	
	wui.history.getKey = function(key) {
		return hash[key];
	};
	
	wui.history.replace = function() {
		var url = wui.history.toQueryString();
		window.location.replace(url);
	};
	
	wui.history.update = function() {
		var url = wui.history.toQueryString();
		window.location = url;
	};
	
	wui.history.parse = function() {
		var str = window.location.hash;
		if (str.length > 2 && str.charAt(0)=='#' && str.charAt(1)=='?') {
			str = str.substr(2);
			var arr = str.split('&');
			for (var i=0; i<arr.length; i++) {
				var parts = arr[i].split('=', 2);
				var key = parts[0];
				var val = decodeURIComponent(parts[1]);
				hash[key] = val;
			}
		}
	};
	
	wui.history.parse();
	
})(wui, jQuery);

/**
 * favorites
 */
(function(wui, $) {

	var settings = {
		activeClass: "active",
		disabledClass: "disabled",
		items: ".fav-item",
		scroll: {
			// gets filled with DOM elements on scroll.initialize method
		},
		sortable: {
			// gets filled with DOM elements on sortable.initialize method
		},
		home: {
			// gets filled with class names on home.toggle method
		}
	};
	
	wui.favorites = {};
	
	wui.favorites.add = function(place) {
		wui.favorites._modify(place, "addfavorite", null);
	};
	
	wui.favorites.del = function(place) {
		wui.favorites._modify(place, "delfavorite", null);
	};
	
	wui.favorites.toggle = function(place, button) {
		var active = $(button).hasClass(settings.activeClass);
		var action = (active) ? "delfavorite":"addfavorite";
		
		wui.favorites._modify(place, action, button);
	};
	
	wui.favorites._modify = function(place, action, button) {
		var url = 'http://www.wunderground.com/favorites/submit.html?action='+action+'&place='+place;
		var button = $(button);

		$.ajax({
			url: url,
			type: 'get',
			//dataType: 'html',
			dataType: 'jsonp',
			jsonp: 'jsonp',
			success: function(data) {
				var err_str = "Error";
				var results = data.RESULTS || data;
				if (results.indexOf(err_str.toLowerCase()) >= 0) {
					alert(results);
				}
				else if (button[0]) {
					var active = button.hasClass(settings.activeClass);
					if (active) {
						button.removeClass(settings.activeClass);
					} else {
						button.addClass(settings.activeClass);
					}
				}
			},
			error: function(e) {
				alert("Error: wui.favorites ajax request failed");
			}
		});
	};
	
	wui.favorites._getActiveIndex = function() {
		var favs = $(settings.items);
		for (var i=0; i<favs.length; i++) {
			if (favs.eq(i).hasClass(settings.activeClass)) {
				return i;
			}
		}
		return -1;
	};
	
	wui.favorites.next = function() {
		var index = wui.favorites._getActiveIndex();
		wui.favorites.go(index + 1);
	};
	
	wui.favorites.prev = function() {
		var index = wui.favorites._getActiveIndex();
		wui.favorites.go(index - 1);
	};
	
	wui.favorites.go = function(index) {
		var favs = $(settings.items);
		if (index < 0) {
			index = favs.length - 1;
		}
		if (index >= favs.length) {
			index = 0;
		}
		var target = favs.eq(index);
		if (target[0]) {
			window.location = target.attr("href");
		}
	};
	
	wui.favorites.scroll = {};
	wui.favorites.scroll.left = function() {
		wui.favorites.scroll.calculateIndex();
		if (settings.scroll.index > 0) {
			wui.favorites.scroll.go(--settings.scroll.index);
		}
	};
	
	wui.favorites.scroll.right = function() {
		wui.favorites.scroll.calculateIndex();
		var items = settings.scroll.items;
		if (settings.scroll.index < items.length-1) {
			wui.favorites.scroll.go(++settings.scroll.index);
		}
	};
	
	wui.favorites.scroll.snap = function() {
		wui.favorites.scroll.calculateIndex();
		wui.favorites.scroll.go(settings.scroll.index);
	};
	
	wui.favorites.scroll.go = function(index) {
		var item = settings.scroll.items.eq(index);
		var left = item.position().left + settings.scroll.container.scrollLeft();
		settings.scroll.container.animate({scrollLeft: left}, {
			duration: 'slow',
			complete: function() {
				// when the scrolling finishes, we might have to deactivate the buttons
				wui.favorites.scroll.setButtons();
			}
		});
	};
	
	wui.favorites.scroll.calculateIndex = function() {
		var items = settings.scroll.items;
		for (var i=0; i<items.length; i++) {
			if (items.eq(i).position().left + items.eq(i).width()/2 >= 0) {
				settings.scroll.index = i;
				break;
			}
		};
	};
	
	wui.favorites.scroll.setButtons = function() {
		var items = settings.scroll.items;		
		var first = items.eq(0);
		var last = items.eq(-1);
		
		// disable left button
		if (!first[0] || first.position().left >= 0) {
			settings.scroll.leftButton.addClass(settings.disabledClass);
		} else {
			settings.scroll.leftButton.removeClass(settings.disabledClass);
		}
		
		// disable right button
		if (!last[0] || last.position().left + last.width() <= settings.scroll.container.width()) {
			settings.scroll.rightButton.addClass(settings.disabledClass);
		} else {
			settings.scroll.rightButton.removeClass(settings.disabledClass);
		}
	};
	
	wui.favorites.scroll.initialize = function() {
		settings.scroll = {
			index: 0,
			bar: $("#favoritesBar"),
			container: $("#favoritesBar .favoritesScrollContainer"),
			items: $("#favoritesBar .favoritesItem"),
			leftButton: $("#favoritesBar .favoritesScrollLeft"),
			rightButton: $("#favoritesBar .favoritesScrollRight")
		};
		
		// set left/right buttons for the first time
		wui.favorites.scroll.setButtons();
		
		var elt = settings.scroll.container;
		
		// http://jqueryfordesigners.com/fun-with-overflows/
		elt.mousedown(function(event) {
			// store pieces of data for positioning the scroll element
			$(this)
			    .data('down', true)
			    .data('x', event.clientX)
			    .data('scrollLeft', this.scrollLeft);
			
			// setup the window event handler that positions the scroll element
			// this listener gets removed on window.mouseup
			$(window).bind("mousemove.favorites", function(event) {
				if (elt.data('down') == true) {
					elt[0].scrollLeft = elt.data('scrollLeft') + elt.data('x') - event.clientX;
				}
			});
			
			// to prevent selecting text when a drag is started by the left button
			if (event.which === 1) {
				event.preventDefault();
			}
			
			// setup the window event handler that releases the mousemove capture
			// it's inside the elt listener because this global event only applies when favorites bar is clicked
			$(window).one("mouseup.favorites", function(event) {
				$(window).unbind("mousemove.favorites");
				if (elt.data('down') == true) {
					wui.favorites.scroll.snap();
					wui.favorites.scroll.setButtons();
				}
				elt.data('down', false);
			});
		}).click(function(event) {
			if (elt.data('scrollLeft') != elt[0].scrollLeft) {
				event.preventDefault();
			}
		}).css({
			'cursor': '-moz-grab'
		});
	};
	
	wui.favorites.sortable = {};
	wui.favorites.sortable.initialize = function() {
		settings.sortable = {
			dragClass: "favMove",
			draggableClass: "favCursorMove",
			loadingClass: "ajax-loading",
			deleteButtonClass: "deleteButton",
			index: 0,
			list: $("#favorites-list"),
			items: $("#favorites-list li"),
			log: $("#log"),
		};
		
		settings.sortable.list.sortable({
			axis: "y",
			containment: settings.sortable.list,
			// items: settings.sortable.items,
			distance: 3, // pixels to start dragging
			tolerance: "pointer",
			start: function(event, ui) {
				ui.item.addClass(settings.sortable.dragClass);
			},
			stop: function(event, ui) {
				ui.item.removeClass(settings.sortable.dragClass);
			},
			update: function(event, ui) {
				wui.favorites.sortable.submit();
			}
		});
		
		// create delete buttons
		settings.sortable.items.each(function(index, element) {
			wui.favorites.sortable.setupItem($(element));
		});
	};
	
	// id should be zipmagicwmo
	wui.favorites.sortable.createItem = function(id, html) {
		var item = $("<li></li>").attr("id",id).html(html);
		item.hide();
		item.appendTo(settings.sortable.list);
		wui.favorites.sortable.setupItem(item);
		item.fadeIn(2000);
		return item;
	};
	
	wui.favorites.sortable.setupItem = function(element) {
		// add draggable cursor
		element.addClass(settings.sortable.draggableClass);
		// create delete button
		var button = $("<span></span>").addClass(settings.sortable.deleteButtonClass);
		button.click(function() {
			$(element).remove();
			wui.favorites.sortable.refresh();
			wui.favorites.sortable.submit();
		});
		element.append(button);
	};
	
	wui.favorites.sortable.refresh = function() {
		settings.sortable.list.sortable("refresh");
	};
	
	wui.favorites.sortable.submit = function() {
		var url = "/favorites/submit.html";
		var zipmagicwmos = "," + settings.sortable.list.sortable("toArray").join(",");
		wui.favorites.sortable.setLoading(true, null, 0);
		
		$.ajax({
			url: url,
			type: "post",
			data: {
				action: "reorderfavorites",
				order: zipmagicwmos
			},
			dataType: "html",
			success: function(data) {
				wui.favorites.sortable.setLoading(false, data, 3000);
			},
			error: function(e) {
				var msg = "Error: wui.favorites.sortable ajax request failed";
				wui.favorites.sortable.setLoading(false, msg, 0);
			}
		});
	};
	
	wui.favorites.sortable.setLoading = function(state, msg, delay) {
		var log = settings.sortable.log;
		if (state == true) {
			log.empty().addClass(settings.sortable.loadingClass);
		} else {
			log.empty().removeClass(settings.sortable.loadingClass);
		}
		if (msg) {
			log.html(msg)
		}
		if (delay) {
			window.setTimeout(function() {
				log.empty();
			}, delay);
		}
	};
	
	wui.favorites.home = function(place, button) {
		settings.home = {
			activeClass: "active",
			inactiveClass: ""
		};
		wui.favorites.home._modify(place, button);
	};
	
	wui.favorites.home.toggle = function(place, button, activeClass, inactiveClass) {
		if (activeClass || activeClass === "") settings.home.activeClass = activeClass;
		if (inactiveClass || inactiveClass === "") settings.home.inactiveClass = inactiveClass;
		var active = $(button).hasClass(settings.home.activeClass);
		if (active) place = "";
		wui.favorites.home._modify(place, button);
	};
	
	wui.favorites.home._modify = function(place, button) {
		var button = $(button);
		$.ajax({
			url: '/auto/wui/geo/PrefDump/index.html?setprefs.0.key=USERHOME&setprefs.0.val=' +place,
			type: 'get',
			dataType: 'html',
			success: function(data) {
				if (button) {
					if (button.hasClass(settings.home.activeClass)==true) {
						button.removeClass(settings.home.activeClass).addClass(settings.home.inactiveClass);
					} else {
						button.addClass(settings.home.activeClass).removeClass(settings.home.inactiveClass);
					}
				}
			},
			error: function(e) {
				alert("Error: wui.favorites.home ajax request failed");
			}
		});
	};
	
	$(document).ready(function() {
		wui.favorites.scroll.initialize();
		wui.favorites.sortable.initialize();
	});
	
})(wui, jQuery);

;(function( $ ){
	
	var $scrollTo = $.scrollTo = function( target, duration, settings ){
		$(window).scrollTo( target, duration, settings );
	};

	$scrollTo.defaults = {
		axis:'xy',
		duration: parseFloat($.fn.jquery) >= 1.3 ? 0 : 1
	};

	// Returns the element that needs to be animated to scroll the window.
	// Kept for backwards compatibility (specially for localScroll & serialScroll)
	$scrollTo.window = function( scope ){
		return $(window)._scrollable();
	};

	// Hack, hack, hack :)
	// Returns the real elements to scroll (supports window/iframes, documents and regular nodes)
	$.fn._scrollable = function(){
		return this.map(function(){
			var elem = this,
				isWin = !elem.nodeName || $.inArray( elem.nodeName.toLowerCase(), ['iframe','#document','html','body'] ) != -1;

				if( !isWin )
					return elem;

			var doc = (elem.contentWindow || elem).document || elem.ownerDocument || elem;
			
			return $.browser.safari || doc.compatMode == 'BackCompat' ?
				doc.body : 
				doc.documentElement;
		});
	};

	$.fn.scrollTo = function( target, duration, settings ){
		if( typeof duration == 'object' ){
			settings = duration;
			duration = 0;
		}
		if( typeof settings == 'function' )
			settings = { onAfter:settings };
			
		if( target == 'max' )
			target = 9e9;
			
		settings = $.extend( {}, $scrollTo.defaults, settings );
		// Speed is still recognized for backwards compatibility
		duration = duration || settings.speed || settings.duration;
		// Make sure the settings are given right
		settings.queue = settings.queue && settings.axis.length > 1;
		
		if( settings.queue )
			// Let's keep the overall duration
			duration /= 2;
		settings.offset = both( settings.offset );
		settings.over = both( settings.over );

		return this._scrollable().each(function(){
			var elem = this,
				$elem = $(elem),
				targ = target, toff, attr = {},
				win = $elem.is('html,body');

			switch( typeof targ ){
				// A number will pass the regex
				case 'number':
				case 'string':
					if( /^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(targ) ){
						targ = both( targ );
						// We are done
						break;
					}
					// Relative selector, no break!
					targ = $(targ,this);
				case 'object':
					// DOMElement / jQuery
					if( targ.is || targ.style )
						// Get the real position of the target 
						toff = (targ = $(targ)).offset();
			}
			$.each( settings.axis.split(''), function( i, axis ){
				var Pos	= axis == 'x' ? 'Left' : 'Top',
					pos = Pos.toLowerCase(),
					key = 'scroll' + Pos,
					old = elem[key],
					max = $scrollTo.max(elem, axis);

				if( toff ){// jQuery / DOMElement
					attr[key] = toff[pos] + ( win ? 0 : old - $elem.offset()[pos] );

					// If it's a dom element, reduce the margin
					if( settings.margin ){
						attr[key] -= parseInt(targ.css('margin'+Pos)) || 0;
						attr[key] -= parseInt(targ.css('border'+Pos+'Width')) || 0;
					}
					
					attr[key] += settings.offset[pos] || 0;
					
					if( settings.over[pos] )
						// Scroll to a fraction of its width/height
						attr[key] += targ[axis=='x'?'width':'height']() * settings.over[pos];
				}else{ 
					var val = targ[pos];
					// Handle percentage values
					attr[key] = val.slice && val.slice(-1) == '%' ? 
						parseFloat(val) / 100 * max
						: val;
				}

				// Number or 'number'
				if( /^\d+$/.test(attr[key]) )
					// Check the limits
					attr[key] = attr[key] <= 0 ? 0 : Math.min( attr[key], max );

				// Queueing axes
				if( !i && settings.queue ){
					// Don't waste time animating, if there's no need.
					if( old != attr[key] )
						// Intermediate animation
						animate( settings.onAfterFirst );
					// Don't animate this axis again in the next iteration.
					delete attr[key];
				}
			});

			animate( settings.onAfter );			

			function animate( callback ){
				$elem.animate( attr, duration, settings.easing, callback && function(){
					callback.call(this, target, settings);
				});
			};

		}).end();
	};
	
	// Max scrolling position, works on quirks mode
	// It only fails (not too badly) on IE, quirks mode.
	$scrollTo.max = function( elem, axis ){
		var Dim = axis == 'x' ? 'Width' : 'Height',
			scroll = 'scroll'+Dim;
		
		if( !$(elem).is('html,body') )
			return elem[scroll] - $(elem)[Dim.toLowerCase()]();
		
		var size = 'client' + Dim,
			html = elem.ownerDocument.documentElement,
			body = elem.ownerDocument.body;

		return Math.max( html[scroll], body[scroll] ) 
			 - Math.min( html[size]  , body[size]   );
			
	};

	function both( val ){
		return typeof val == 'object' ? val : { top:val, left:val };
	};

})( jQuery );

