window.appState = {
	month: $.cookie('month'),
	selectedTrip: null,
    selectedTrade: null,
	tempTrade: null,
    shopMode: 'tripShopping',   // tripShopping, staticTradeShopping, dynamicTradeShopping
	detailsWindows: {},
    timestampUpdater: null
};

window.cluetipOptions = {
	local: true
};

function clearSelectedItems() {
   window.appState.selectedTrip = null;
   window.appState.selectedTrade = null;
}

// convert trip object (like the one in window.appState.selectedTrip) to a string
// that can be used in page parameters.
function tripToParamStr(t) {
	if (typeof(t.getParams) == 'function') t = t.getParams();
	return ''+t.id+'_'+t.date+'_'+t.m+'_'+t.d+'_'+t.f+'_'+t.s;
}
function isSameTrip(t1, t2) {
	if (t1 === t2) return true;
	if (!t1 || !t2) return false;
	return tripToParamStr(t1) == tripToParamStr(t2);
}

function showTripDetailsWindow(t) {
    if(!t)
        return;
    var url = "tripdetails.php?"+$.param(t.getParams());        
	var key = tripToParamStr(t)
    var width = 490, height = 450, scroll = 'yes';
    showWindow(url, key, width, height, scroll);
}

function contactOwnerWindow(t) {
    if(!t)
        return;
    var url = "message-contactowner.php?"+$.param(t.getParams());        
    var key = tripToParamStr(t)+'_co'
    var width = 590, height = 450, scroll = 'no';
    showWindow(url, key, width, height, scroll);
}

function showWindow(url, key, width, height, scroll) {
	if (appState.detailsWindows[key]) {
		var wnd = appState.detailsWindows[key];
		if (typeof wnd.closed == 'boolean')
		{
			// mozilla
			if (wnd.closed)
				openTripDetailsWindow(url, key, width, height, scroll);
			else 
				appState.detailsWindows[key].focus();
		}
		else
		{
			//console.log('focusing');
			try {
				appState.detailsWindows[key].focus();
			} 
			catch (e) {
				openTripDetailsWindow(url, key, width, height, scroll);
			}
		}
	} else
		openTripDetailsWindow(url, key, width, height, scroll);
}

function openTripDetailsWindow(url, key, width, height, scroll){
	var wnd = window.open(url, key.replace(/-/g,''), "status=1,toolbar=0,menubar=0,width=" + width + ",height=" + height + ",scrollbars=" + scroll);
	appState.detailsWindows[key] = wnd;
	if(wnd)	// can be null in IE7
		wnd.appState = appState;
}

// this gets called when inline trip info is injected into the DOM
function trip_inline($tripinfo) {
	$tripinfo.find('li > .title').wrap('<div class="event-catcher" style="position: relative; z-index: 100; margin-left: -22px; padding-left: 22px; cursor: pointer;"/>');
	$tripinfo.find('li > div.event-catcher').click(function(event) {
		var $li = $(this).parent();
		$li.toggleClass('expanded')
			.find('.title > img.expander')
				.attr('src', ($li.hasClass('expanded') ? 'images/minus.gif' : 'images/plus.gif'))
				.end()
			.find('> .content').toggle();  //.slideToggle('fast');
	});

	$tripinfo.find('a.popout').click(function() {
		var trid = $(this).parents('tr.tripinfo').attr('id');
		var trip = Trip.fromString(/^trinfo_(.*)$/i.exec(trid)[1]);
		showTripDetailsWindow(trip);
		return false;
	});
    
    $tripinfo.find('a.popout2').click(function() {
        var trid = $(this).parents('tr.tripinfo').attr('id');
        var trip = Trip.fromString(/^trinfo_(.*)$/i.exec(trid)[1]);
        contactOwnerWindow(trip);
        return false;
    });    
    
	// update trips details handler(when there are no trip details)
	$tripinfo.find('.update-request a.trip-details-update').click(function() {
		var trid = $(this).parents('tr.tripinfo').attr('id');
		var trip = Trip.fromString(/^trinfo_(.*)$/i.exec(trid)[1]);
		var $parent = $(this).parents('div.notfound');

		// close handler for the "update trip details" notice 
		$parent.find('#close-notice').click(function() {
			$parent.find('.update-request').removeClass('hidden');
			$parent.find('.update-notice').addClass('hidden');
		});
		
		requestTripDetailUpdate(trip, $parent);
	});
}

function calPaneTripsMap() {
    attachTripsMapHandler('#calendar-pane map area.popout');
}

function myCalendarTripsMap() {
    attachTripsMapHandler('#my-calendar map area.popout');
}

function attachTripsMapHandler(selector){
    $(selector).live('click', function() {
        var href = $(this).attr('href');
        var trip = Trip.fromUrl(href);
        showTripDetailsWindow(trip);
        return false;
    });    
}

function requestTripDetailUpdate(trip, $parent) {
	var key = tripToParamStr(trip);
	var url = "clienttaskrequest.php?request=tripdetails&"+$.param(trip.getParams());
	
	$.ajax({
		type: 'POST',
		url: url
	});			
	
	$parent.find('.update-request').addClass('hidden');
	$parent.find('.update-notice').removeClass('hidden');
}

function triplist($table, clientSorting) {
	if ($table.length > 1) throw "triplist() should be called with only a single element";

	if(clientSorting)
		$table.tablesorter();

	// get # of columns for future use
	var numcols = $table.find('th').length;
	// get default width of the table
	var tblwidth = $table.innerWidth();

	var lastClick = 0;

	$table.find('tr.trip')
		.click(function(event) {
			if (event.button > 1) return true;

			var $tr = $(this);
			var trid = $tr.attr('id');
			var trinfoid = trid.replace(/^t_/,'trinfo_');
			var $trinfo = $('#'+trinfoid);
			if (!$tr.hasClass('selected') || $tr.hasClass('error')) {
				$table.find('.selected').removeClass('selected');
				$tr.addClass('selected');

				var trip = Trip.fromString(/^t_(.*)$/i.exec(trid)[1]);
				appState.selectedTrip = trip;

				if (settings.expandTripOn != 'click2')
					toggleTrip($tr);

				$table.triggerHandler('tripSelected', appState.selectedTrip);
			} else {
				toggleTrip($tr);
			}
		});

	function toggleTrip($tr) {
		var trid = $tr.attr('id');
		var trinfoid = trid.replace(/^t_/,'trinfo_');
		var $trinfo = $('#'+trinfoid);

		// first check to see if this trip already has a hidden info row
		if ($trinfo.length == 0) {
			$tr.after(	'<tr id="'+trinfoid+'" class="tripinfo hidden">'+
							'<td colspan="'+numcols+'">'+
								'<div class="container">'+
									//'<div class="loading">&nbsp;<\/div>'+
								'<\/div>'+
							'<\/td>'+
						'<\/tr>');
			$trinfo = $('#'+trinfoid);
			var $cont = $trinfo.find('.container');

			loadTripDetails($tr, $trinfo, $cont);
		} else {
			if ($trinfo.hasClass('hidden')) {
				
				if($trinfo.find('.notfound .update-request').length > 0) {
					// in case we have requested trip details previously,
					// but the trip doesn't have any trip details yet,
					// request them again
					var $cont = $trinfo.find('.container');
					loadTripDetails($tr, $trinfo, $cont)
				}
				else				
					showtrinfo($trinfo);
			}
			else 
				hidetrinfo($trinfo);
		}
	}

	function loadTripDetails($tr, $trinfo, $cont) {
		$tr.removeClass('error').addClass('loading');

		$.ajax({
			type: 'GET',
			url: 'trip-inline.php',
			data: appState.selectedTrip.getParams(),
			timeout: 15000,
			success: function(data, textStatus) {
				$tr.removeClass('loading');

				var $tripinfo = $(data);
				$cont.html($tripinfo);
				trip_inline($tripinfo);
				$tripinfo.find('li > div.event-catcher').click();
				$tripinfo.find('.quicktip').cluetip(cluetipOptions);

				showtrinfo($trinfo);
			},
			error: function(xhr, textStatus, errorThrown) {
				$tr.removeClass('loading').addClass('error');
				$trinfo.remove();
				//alert('error loading trip info');
			}
		});		
	}


	var trinfoContainer = document.createDocumentFragment();

	$table
		.bind('sortStart', function() {
			// remove trip info rows before sorting
			$table.find('tr.tripinfo').addClass('hidden').each(function() {
				trinfoContainer.appendChild(this);
			});
		})
		.bind('sortEnd', function() {
			// fix the location of all the tripinfo rows after sorting
			$.each($.makeArray(trinfoContainer.childNodes), function() {
				var $trinfo = $(this);
				var trid = $trinfo.attr('id').replace(/^trinfo_/,'t_');
				$('#'+trid).after($trinfo);
			});
		});

	function showtrinfo($trinfo) {
		$trinfo.removeClass('hidden');
	}

	function hidetrinfo($trinfo) {
		$trinfo.addClass('hidden');
	}
}


function calendarPane($cp) {
	$cp = $cp || $('#calendar-pane');

	$cp.find('.quicktip').cluetip(cluetipOptions);

	$cp.find('.toggle-minor')
        .click(function(e) {
		    if (e.button > 1) return true;

		    var $a = $(this);
		    var shown = $a.data('shown');
		    // .toggle() doesn't work in IE8
            $cp.find('.monthly-summary .minor').each(function() {
                var $elem = $(this);
                if($elem.css('display') == 'none')
                     $elem.show();
                else
                     $elem.hide();                       
            });
            
		    if (!shown) {
			    $a.text('Show less').data('shown', true);
		    } else {
			    $a.text('Show more').data('shown', false);
		    }
		    return false;
	    })
        .preventFocusRect();;
    
    $cp.find('table tbody td a.popout').click(function(){
        var trid = $(this).parents('tr.trip').attr('id');
        var trip = Trip.fromString(/^t_(.*)$/i.exec(trid)[1]);
        showTripDetailsWindow(trip);
        return false;        
    });
    
    $cp.find('#extras a.toggle-my-trips')
        .click(function(){
            var $a = $(this);
            var $tripsCont = $a.next();
            if($tripsCont) {
                $tripsCont.toggleClass('hidden');            
                if($tripsCont.hasClass('hidden')) {
                    $a.text('Show My Trips');
                    setCookie('expandedCalPaneTrips', false, {expires:null});
                }
                else {
                    $a.text('Hide My Trips')
                    setCookie('expandedCalPaneTrips', true, {expires:null});
                }
            }
        })
        .preventFocusRect();

	return $cp;
}

$(function() {
	// disable focus rects on certain elements (for browsers that have this ability)
	$('#toplinks a, #menu a, #submenu a').preventFocusRect();

	// legend link
	$('#legend-link').click(function(e) {
		var wnd = window.open($(e.target).attr('href'), "Legend", "status=0,toolbar=0,menubar=0,width=460,height=530");
		return false;
	});


	// closure to manage menu state
	(function() {
		var mouseLeaveTimeout;
		var cursorOnMenuElement = false;
		var anyActive = false;
		var $defsm = $('#submenu > .submenu-items.default');

		function showSubmenu($submenu) {
			var id = $submenu.attr('id');
			$submenu.removeClass('hidden').addClass('active');
			$('.submenu-items:not(#'+id+')').addClass('hidden').removeClass('active');
			anyActive = true;
		}

		function reset() {
			if (anyActive) {
				$defsm.stop().removeClass('hidden').removeClass('active');
				$('#submenu > .submenu-items:not(.default)').stop().addClass('hidden').removeClass('active');
				anyActive = false;
			}
		};

		function menuMouseLeave() {
			cursorOnMenuElement = false;
			if (anyActive) {
				clearTimeout(mouseLeaveTimeout);
				mouseLeaveTimeout = setTimeout(function() {
					if (!cursorOnMenuElement)
                        reset();
				}, 500);
			}
		};

		$('#menu li:not(.right) a')
			.hoverIntent({
				timeout: 0, // timeout handled manually
				over: function() {
					showSubmenu($($(this).attr('rel')));
				},
				out: menuMouseLeave
			})
			.mousemove(function() {
				cursorOnMenuElement = true;
			});

		$('#submenu')
			.bind('mouseleave', menuMouseLeave)
			.mousemove(function() {
				cursorOnMenuElement = true;
			});

		$('#submenu > .submenu-items a')
			.click(function(e) {
				if (e.button > 1) return;
				$('#submenu > .submenu-items.default').removeClass('default');
				$('#submenu > .submenu-items a.active').removeClass('active');
				$defsm = $(this).addClass('active').parent().addClass('default');
				setTimeout(function() { reset(); }, 100);
			});

	})();

	// month selector
	$('#month-selector a').preventFocusRect()
		.click(function() {
			var month = /month=([0-9]+)/.exec($(this).attr('href'))[1];
			$.cookie('month', month);
			location.href = location.href;
			return false;
		});

	// anything that has the float class should follow the viewport.
	// typically only the calendar pane does this
	$('.float').each(function() {
		var $e = $(this).css({position:'absolute'});
		var padViewport = 5;
		var panelWindowOffset = Math.floor($e.offset().top);
		var lastScrollTop = $(document).scrollTop();
		$(window).scroll(function() {
			var newTop = 0,
				scrollTop = $(document).scrollTop(),
				wndHeight = $(window).height(),
				panelHeight = $e.height();

			if (wndHeight > panelHeight) {
				// just float the panel at the top if the viewport is tall enough to show all of it
				newTop = Math.max(0, scrollTop - panelWindowOffset + padViewport);
			} else {
				// if the viewport isn't tall enough to show all of the panel, things get complicated
				newTop = null; // leave the panel where its at by default
				var ptop = $e.position().top + panelWindowOffset,
					pbottom = ptop + panelHeight,
					vpheight = wndHeight - (padViewport * 2),
					vptop = scrollTop + padViewport,
					vpbottom = vptop + vpheight,
					ptopShown = ptop - vptop,
					pbottomShown = vpbottom - pbottom;

				// if ptopShown or pbottomShown is negative then that number of pixels is invisible
				// from the respective part of the element.
				//console.log(ptopShown, pbottomShown);

				if (ptopShown > 0 && scrollTop < lastScrollTop) {
					// float to top
					newTop = Math.max(0, vptop - panelWindowOffset);
					//console.log('ptopShown > 0 ::::: newTop='+newTop);
				} else if (pbottomShown > 0 && scrollTop > lastScrollTop) {
					newTop = Math.max(0, scrollTop - panelWindowOffset - panelHeight + vpheight);
					//console.log('pbottomShown > 0 ::::: newTop='+newTop);
				}
			}

			lastScrollTop = scrollTop;
			//console.log('setting top to '+newTop);
			if (newTop !== null) {
				$e.stop(true, false);
				$e.animate({top:newTop},{duration:500,queue:false});
			}
		});
	});


	// "quicktip" tooltips
	$('.quicktip').cluetip(cluetipOptions);


	// calendar pane
	calendarPane();
});


// classes
function Trip() {
	this.id;	this.date;	this.month;
	this.dom;	this.eqp;	this.pos;

	var self = this;

	this.isSameTrip = function(other) {
		return 	self.id == other.id &&
				self.date == other.date &&
				self.month == other.month &&
				self.dom == other.dom &&
				self.eqp == other.eqp &&
				self.pos == other.pos;
	};

	this.getParams = function() {
		return {
			id: self.id,
			date: self.date,
			m: self.month,
			d: self.dom,
			f: self.eqp,
			s: self.pos
		};
	};

	this.toString = function() {
		return ''+self.id+'_'+self.date+'_'+self.month+'_'+self.dom+'_'+self.eqp+'_'+self.pos;
	};
}

Trip.fromString = function(str) {
	var rx = /^([0-9]{1,4})_([0-9]{4}-[0-9]{2}-[0-9]{2})_([0-9]{6})_([A-Z]{3})_([A-Z0-9]{3})_(CAP|FO|FA)$/i,
		m = rx.exec(str);
	if (!m) return null;
	var t = new Trip(), i = 0;
	t.id = m[++i];
	t.date = m[++i];
	t.month = m[++i];
	t.dom = m[++i];
	t.eqp = m[++i];
	t.pos = m[++i];
	return t;
}

Trip.fromUrl = function(url) {
    url = url.replace(/\&amp;/g,'_');
    url = url.replace(/&/g,'_');
    var rx = /id=([0-9]{1,4})_date=([0-9]{4}-[0-9]{2}-[0-9]{2})_m=([0-9]{6})_d=([A-Z]{3})_f=([A-Z0-9]{3})_s=(CAP|FO|FA)$/i,
        m = rx.exec(url);    
    if (!m)
        return null;
    
    var t = new Trip(), i = 0;
    t.id = m[++i];
    t.date = m[++i];
    t.month = m[++i];
    t.dom = m[++i];
    t.eqp = m[++i];
    t.pos = m[++i];
    return t;
}

function Trade() {
	this.tradeItems = [];

	var self = this;

	this.add = function(type, trip) {
		self.tradeItems.push([type,trip]);
	};

	this.remove = function(trip) {
		var items = self.tradeItems;
		for (var i=0; i<items.length; i++) {
			var titype = items[i][0], titrip = items[i][1];
			if (trip.isSameTrip(titrip)) {
				delete self.tradeItems[i];
				self.tradeItems.splice(i, 1);
				break;
			}
		}
	};

	this.getParams = function() {
		var params = {};
		var items = self.tradeItems;
		if (items.length > 0) {
			for (var i=0; i<items.length; i++) {
				var titype = items[i][0], titrip = items[i][1];
				params['ti'+i+'_type'] = titype;
				params['ti'+i+'_trip'] = titrip.toString();
			}
		}
		return params;
	};
    
    this.clone = function() {
        trade = new Trade();
        for(i=0; i < this.tradeItems.length; i++)
        {
            ti = this.tradeItems[i];
            trade.add(ti[0], ti[1])
        }
        
        return trade;
    }
}

Trade.fromString = function(str)
{
    var trade = new Trade();
    
    str = str.replace(/\&amp;/g,'&');
    var currentType = null;
    var currentTrip = null;
    var params = str.split('&');        
    var rxMatch = new RegExp('/^ti([0-9]+)_(.*)$/', 'i');

    for(i=0; i < params.length; i++)
    {
        var param = params[i];
        var nv = param.split('=');
        var name = nv[0];
        var value= nv[1];
        var matches = /^ti([0-9]+)_(.*)/i.exec(name);

        if(matches != null)
        {
            var tiId = matches[1];
            var varName = matches[2];
            
            switch (varName)
            {
                case 'type':
                    currentType = value;
                    break;
                case 'trip':
                    // value is in format ID_date_month_dom_eqp_pos
                    currentTrip = Trip.fromString(value);
                    break;
            }
            
            if(currentType != null && currentTrip != null) 
            {
                trade.add(currentType, currentTrip);
                currentType = null;
                currentTrip = null;
            }
        }
    }

    return trade;
}

function TradeItem() {
    this.type = null;
    this.trip = null;
}

TradeItem.fromString = function(str) {
    str = str.replace(/\&amp;/g,'&');
    var params = str.split('&');        
    var ti = new TradeItem();
    
    for(i=0; i < params.length; i++)
    {
        var param = params[i];
        var nv = param.split('=');
        var name = nv[0];
        var value= nv[1];
        var matches = /^ti([0-9]+)_(.*)/i.exec(name);

        if(matches != null)
        {
            var tiId = matches[1];
            var varName = matches[2];
            
            switch (varName)
            {
                case 'type':
                    ti.type = value;
                    break;
                case 'trip':
                    // value is in format ID_date_month_dom_eqp_pos
                    ti.trip = Trip.fromString(value);
                    break;
            }
        }        
    }
    
    if(ti.type == null || ti.trip == null)
        return null;
    else
        return ti;
}