Object.size = function(obj) {
    var size = 0, key;
    for (key in obj) {
        if (obj.hasOwnProperty(key)) {size++;}
    }
    return size;
};

Place = function(){this.init();};
$.extend(Place.prototype, {
	id: null,
	name: null,
	url: null,
	children: null,
	arrive: null,
	depart: null,
	notes: null,
	latitude: 0,
	longitude: 0,
	type: null,
	order: 1,
	dateAdded: null,
	
	init: function()
	{
		this.children = {};
		this.order = 1;
	},
	
	/** 
	 * determine whether an ajax request needs to be made to gather more place data
	 */
	isLoaded: function()
	{
		return (this.latitude !== 0 && this.longitude !== 0);
	}
});

Ad = function(){};
$.extend(Ad.prototype, {
	id: null,
	type: null,
	url: null,
	name: null
});


var itinerary = {
		
		domEl: null,
		domElFull: null,
		places: {},
		stopRender: false,
		placesArray: [],
		dirty: false,
		isLoggedIn: false,
	
		init: function()
		{
			this.domEl = $('#itinerary');
			this.domElFull = $('#itinerary-full');
			
			// if no local state then use server state
			$.Jookie.Initialise("myDiscoveries", 44640*3); // set cookie for 3 months
			
			$.Jookie.Initialise("user", 44640*3);
			var userId = $.Jookie.Get("user", "id");
			this.isLoggedIn = (userId > 0);
			
			
			this.load();
			//this.test();
			this.initSectionsToPlaces();
			this.render();
			
			if(this.domElFull.length > 0)
			{
				$.getScript('/sites/eyeballnz.com/themes/default/jquery.ui.custom.min.js', function(){
					$(function() {
						$(".datepicker").datepicker({showOn: 'both', buttonImage: '/sites/eyeballnz.com/themes/default/images/date-picker.gif', buttonImageOnly: true});
						$('#itinerary-full').bind('click', function(){$(".datepicker").datepicker({showOn: 'both', buttonImage: '/sites/eyeballnz.com/themes/default/images/date-picker.gif', buttonImageOnly: true});} );
						$('.datepicker').bind('change', function(){itinerary.save();});
					});
				});
			}
			
		},
		
		swapArrayItems: function(arrayItems ,a,b)
		{
			var tmp=arrayItems[a];
			arrayItems[a]=arrayItems[b];
			arrayItems[b]=tmp;
		},

		addPlace: function(placeId, name, url)
		{
			if('p-'+placeId in this.places){return;}
			
			var place = new Place();
			place.id = placeId;
			place.name = name;
			place.url = url;
			place.dateAdded = new Date();
			
			var key = 'p-'+placeId;
			
			this.places[key] = place;
			
			place.order = this.placesArray.push(place);
			
			
			this.render();
			this.save();
		},
		
		initSectionsToPlaces: function()
		{
			$('.itinerary-location').each(function(i){
				var secId = this.id.replace(/section\-/,'');
				
				var placeResult = eval( '(' + $.ajax({
				  url: "/index.php?module=places&type=rpc&func=getPlaceFromSection&sectionId="+secId,
				  async: false
				 }).responseText + ')' );
				var place = placeResult.place;
				var newButton = '<button class="itinerary-place itinerary-ad" id="p-'+place.id+'" onclick="itinerary.addPlace('+place.id+', \''+(place.name)+'\', \''+escape(place.link)+'\');">Add</button>';
				
				$(this).replaceWith(newButton);
				
			});
		},
		
		reorder: function()
		{				
			$.each(this.placesArray, function(i, place){
				place.order = i+1;
			});
		},
		
		getPlaceFromAd: function(adId)
		{		
			var placeResult = eval( '(' + $.ajax({
			  url: "/index.php?module=places&type=rpc&func=getPlaceFromAd&adId="+adId,
			  async: false
			 }).responseText + ')' );
			return placeResult.place;
		},
		
		addListingAd: function(adId, type, url, name)
		{
			var place = this.getPlaceFromAd(adId);
			if( (typeof this.places['p-'+place.id] != 'undefined') && 'ad-'+adId in this.places['p-'+place.id].children){return;}
			
			this.stopRender = true;
			
			this.addPlace(place.id, place.name, place.pagelink);
			this.places['p-'+place.id].type = place.classType;
			this.places['p-'+place.id].latitude = place.latitude;
			this.places['p-'+place.id].longitude = place.longitude;		
			
			
			var ad = new Ad();
			ad.id = adId;
			ad.type = type;
			ad.url = url;
			ad.name = name;
			this.places['p-'+place.id].children['ad-'+adId] = ad;
			
			this.stopRender = false;
			
			this.render();
			this.save();
		},
		
		renderButtons: function()
		{
			$('.itinerary-place, .itinerary-ad').removeClass('button-add');
			$('.itinerary-place, .itinerary-ad').removeClass('button-added');
			
			
			$('.itinerary-place').each(function(i){
				if(this.id in itinerary.places){
					$(this).addClass('button-added');
				}
				else
				{
					$(this).addClass('button-add');
				}
			});
			
			$('.itinerary-ad').each(function(i){
				if(itinerary.adExists(this.id.replace(/ad\-/,''))){
					$(this).addClass('button-added');
				}
				else
				{
					$(this).addClass('button-add');
				}
			});
			
			
			
		},
		
		renderMaps: function()
		{
			$('.itinerary-map').each(function(i, mapDomEl){
				var placeId = parseInt(mapDomEl.id.replace(/map\-/,''), 10);
				var offsets = itinerary.getPixelOffsets(placeId);
				$(mapDomEl).css('background-position', offsets[0]+'px '+offsets[1]+'px');
			});
		},
		
		render: function()
		{
			if(this.domEl && !this.stopRender)
			{
				var html = [];
				
				var thePlaces = this.getPlacesByOrdering(this.callbackSortPlacesByAddition, 3);
				
				
				$.each(thePlaces, function(i, place){
					if(place.url != null){
						html.push('<div class="my-discovery-item"><button class="icon-remove" onclick="itinerary.removePlace('+place.id+')">remove</button><a href="'+place.url+'"><h3>'+place.name+'</h3></a>');
					}else{
						html.push('<div class="my-discovery-item"><button class="icon-remove" onclick="itinerary.removePlace('+place.id+')">remove</button><h3>'+place.name+'</h3>');
					}
					$.each(place.children, function(i, ad){
						if(ad.url != null){
							html.push('<a href="'+ad.url+'">'+ad.name+'</a>');
						}else{
							html.push(ad.name);
						
						}
					});
					
					html.push('</div>');
				});
				
				html.push('<p><a href="/itinerary/" class="button view-my-discoveries">View My Discoveries</a></p>');
				
				this.domEl.html(html.join(''));
				
			}
			this.renderButtons();
			this.renderFullItinerary();
		},
		
		checkAllPlaceDataAvailable: function()
		{
			var placesToLoad = [];
			$.each(this.places, function(i, place){
				if(!place.isLoaded())
				{
					placesToLoad.push(place.id);
				}
			});
			
			if(placesToLoad.length>0)
			{
				var placesResult = eval( '(' + $.ajax({
				  url: "/index.php?module=places&type=rpc&func=getPlaces&placeIds="+placesToLoad.join(','),
				  async: false
				 }).responseText + ')' );
				
				$.each(placesResult.places, function(i, place){
					var key = 'p-'+place.id;
					itinerary.places[key].name = place.name;
					itinerary.places[key].type = place.classType;
					itinerary.places[key].latitude = place.latitude;
					itinerary.places[key].longitude = place.longitude;
					itinerary.places[key].url = place.pagelink;
				});
			}
			
		},
		
		renderFullItinerary: function()
		{
			if(this.domElFull && !this.stopRender)
			{
				var html = [];
				
				// check all place data is available and request from server
				this.checkAllPlaceDataAvailable();
				
				
				$.each(this.placesArray, function(i, place){
					html.push('<table width="750" border="0" cellspacing="0" cellpadding="0" class="intinerary-item"><tr><td width="20" rowspan="2">');
					html.push('<table width="20" border="0" cellspacing="0" cellpadding="0" class="itinerary-controls"><tr><td align="center"><a onclick="itinerary.moveUp('+place.id+')" class="arrow-up">up</a></td></tr><tr><td align="center">'+place.order+'</td></tr><tr><td align="center"><a onclick="itinerary.moveDown('+place.id+')" class="arrow-down">down</a></td></tr></table></td><td class="location-bar"><table width="100%" border="0" cellspacing="0" cellpadding="0"><tr><td>');
					if(place.url != null){
						html.push('<a href="'+place.url+'"><h1>'+place.name+'</h1></a><div id="saving-'+place.id+'" class="saving" style="display:none;">Saving...</div>');
					}else{
						html.push('<h1>'+place.name+'</h1><div id="saving-'+place.id+'" class="saving" style="display:none;">Saving...</div>');
					}
					html.push('</td><td align="right" valign="middle"><a onclick="itinerary.removePlace('+place.id+')"><img src="/sites/eyeballnz.com/themes/default/images/icon-remove.png" width="16" class="png_bg" border="0"/></a></td></tr></table></td></tr><tr><td class="itinerary-item">');
					html.push('<table width="721" border="0" cellspacing="0" cellpadding="0"><tr class="itinerary-dates"><td width="139" rowspan="2" valign="top"><div class="itinerary-map" id="map-'+place.id+'"></div></td><td width="369" class="itinerary-dates"><table border="0" cellspacing="0" cellpadding="0" class="date-picker"><tr><td align="right">arrival date</td><td width="120">');
					if(typeof place.arrive != 'undefined'){
						html.push('<input type="text" name="textfield" id="arrival-'+place.id+'" onchange="$(\'div#saving-'+place.id+'\').show();itinerary.updatePlace('+place.id+')"  class="datepicker" value="'+place.arrive+'" />');
						}else{
						html.push('<input type="text" name="textfield" id="arrival-'+place.id+'" onchange="$(\'div#saving-'+place.id+'\').show();itinerary.updatePlace('+place.id+')"  class="datepicker" />');
					}
					html.push('</td><td></td></tr></table></td><td width="260" align="right" class="itinerary-dates"><table border="0" cellspacing="0" cellpadding="0" class="date-picker"><tr><td>departure date</td><td width="120">');
					if(typeof place.depart != 'undefined'){
						html.push('<input type="text" name="textfield2" id="departure-'+place.id+'" onchange="$(\'div#saving-'+place.id+'\').show();itinerary.updatePlace('+place.id+')" class="datepicker"  value="'+place.depart+'" />');
						}else{
						html.push('<input type="text" name="textfield2" id="departure-'+place.id+'" onchange="$(\'div#saving-'+place.id+'\').show();itinerary.updatePlace('+place.id+')"  class="datepicker" />');
					}
					html.push('</td><td align="right"></td></tr></table></td></tr><tr><td colspan="2" valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0"><tr><td><table width="100%" border="0" cellpadding="0" cellspacing="0" class="save-items">');
					
					$.each(place.children, function(i, ad){
						html.push('<tr><td align="left" valign="top"><a href="'+ad.url+'">'+ad.name+'</a></td><td width="16" align="left" valign="top"><a onclick="itinerary.removeListingAd('+ad.id+')"><img src="/sites/eyeballnz.com/themes/default/images/icon-remove.png" class="png_bg" alt="" width="16" border="0"/></a></td></tr>');
					});
					
					var placeNotes = place.notes || '';
					html.push('</table></td></tr></table></td></tr></table></td></tr><tr><td width="20">&nbsp;</td>');
					html.push('<td class="notes-header"><div class="note-links"><a style="display:none;" onclick="$(\'div#saving-'+place.id+'\').show();itinerary.updatePlace('+place.id+');$(\'#notes-'+place.id+'\').hide();$(\'#text-notes-'+place.id+'\').html($(\'#notes-'+place.id+'\').val());$(\'#text-notes-'+place.id+'\').show();$(\'#save-notes-'+place.id+'\').hide();$(\'#edit-notes-'+place.id+'\').show();itinerary.save();" id="save-notes-'+place.id+'"><img src="/sites/eyeballnz.com/themes/default/images/icon-save.png" class="png_bg" /></a></div><div class="note-links"> <a onclick="$(\'#notes-'+place.id+'\').show();$(\'a#save-notes-'+place.id+'\').show();$(\'#text-notes-'+place.id+'\').hide();$(\'a#edit-notes-'+place.id+'\').hide();" id="edit-notes-'+place.id+'"><img src="/sites/eyeballnz.com/themes/default/images/icon-edit.png" class="png_bg"/></a></div>my notes:</td></tr><tr><td width="20">&nbsp;</td><td class="my-notes-entry"><p id="text-notes-'+place.id+'">'+placeNotes+'</p><textarea id="notes-'+place.id+'" style="display:none">'+placeNotes+'</textarea></td></tr></table>');
				});

				if(this.placesArray.length === 0)
				{
					html.push('You have not added any discoveries yet, click on the green "add" button to add places to your discoveries as you navigate the site.');
				}
				
				this.domElFull.html(html.join(''));
				this.renderMaps();
			}
		},
		
		getState: function()
		{
			var state = {places: this.places};
			return $.toJSON(state);
		},
		
		setState: function(state)
		{
			var newState = $.secureEvalJSON(state);
			this.places = newState.places;
		},
		
		load: function()
		{
			var currentTime = new Date();
			var lastSync = $.Jookie.Get("myDiscoveries", "lastsync");
			needsSync = (typeof(lastSync) == 'undefined' ||  ((currentTime.getTime() - lastSync) > 300000)); // either it has never synced or the data is stale
			
			
			if(needsSync && this.isLoggedIn)
			{
				// perform sync rpc call
				var placesResult = $.ajax({
				  url: "/index.php?module=User&type=rpc&func=get&key=mydiscoveries_places",
				  async: false
				 }).responseText;
				 
				if(placesResult.length > 0 && ! /DOCTYPE/.test(placesResult))
				{
					var placesFromServer = eval( '(' + placesResult + ')' );
				
					this.places = placesFromServer;
					$.Jookie.Set("myDiscoveries", "places", this.places);
					$.Jookie.Set("myDiscoveries", "lastsync", currentTime.getTime());
				}
				else
				{
					// fallback on cookie content and then save to server, this will usually happen first time user logs in and never saved before
					var placesCookie = $.Jookie.Get("myDiscoveries", "places");
					if(placesCookie)
					{
						this.places = placesCookie;
						this.save(true);
					}
				}
			}
			else
			{
				var placesCookie = $.Jookie.Get("myDiscoveries", "places");
				if(placesCookie)
				{
					this.places = placesCookie;
				}
			}

			this.placesArray = [];
			
			$.each(this.places, function(i, place){
				place.isLoaded = function(){return (this.latitude !== 0 && this.longitude !== 0);};
				itinerary.placesArray[place.order-1] = place;
			});
				

			
		},
		
		save: function(lazy)
		{
			$.Jookie.Set("myDiscoveries", "places", this.places);
			// save data back to server
			this.dirty = true;
			if(lazy)
			{
				setTimeout(function(){itinerary.saveToServer();}, 2000);
			}
			else
			{
				this.saveToServer();
			}
			
		},

		saveToServer: function()
		{
			
			if(this.dirty && this.isLoggedIn)
			{
				this.dirty = false;
				$.post("/index.php", { module: "User", type: "rpc", func:'set', key:'mydiscoveries_places', value: JSON.stringify(this.places)  } );			
			}
			setTimeout("$('.saving').fadeOut(500)", 1500);
		},
		
		removePlace: function(placeId)
		{
			var currentOrder = this.places['p-'+placeId].order;
			delete(this.places['p-'+placeId]);
			this.placesArray.splice(currentOrder-1, 1);
			this.reorder();
			
			this.render();
			this.save();
		},
		
		
		
		getPlacesByOrdering: function(sortCallback, limit)
		{
			if(limit===null){limit=0;}
			var orderedPlaces = [];
			$.each(this.places, function(i, place){
				orderedPlaces.push(place);
			});
			orderedPlaces.sort(sortCallback);
			orderedPlaces.reverse();
			if(limit>0)
			{
				return orderedPlaces.slice(0,limit);
			}
			else
			{
				return orderedPlaces;
			}
			
		},
		
		callbackSortPlacesByOrder: function(a, b)
		{
			if(a.order > b.order)
			{
				return 1;
			}
			else if(a.order < b.order)
			{
				return -1;
			}
			else
			{
				return 0;
			}
		}, 
		
		callbackSortPlacesByAddition: function(a ,b)
		{
			if(a.dateAdded > b.dateAdded)
			{
				return 1;
			}
			else if(a.dateAdded < b.dateAdded)
			{
				return -1;
			}
			else
			{
				return 0;
			}
		},
		
		
		
		adExists: function(adId)
		{
			var adExists = false;
			$.each(this.places, function(i,place){
				
				if (Object.size(place.children) > 0)
				{
					if (typeof place.children['ad-'+adId] != 'undefined')
					{
						adExists = true;
					}
				}
			});
			return adExists;
		},
		
		removeListingAd: function(adId)
		{
			$.each(this.places, function(i,place){
				
				if (Object.size(place.children) > 0)
				{
					if (typeof place.children['ad-'+adId] != 'undefined')
					{
						delete(place.children['ad-'+adId]);
					}
				}
			});
			
			this.render();
			this.save();
		},
		
		/**
		 * should be called whenever the arrival or departure dates change, or when the user updates notes
		 */
		updatePlace: function(placeId)
		{
			this.places['p-'+placeId].arrive = $('#arrival-'+placeId).val();
			this.places['p-'+placeId].depart = $('#departure-'+placeId).val();
			this.places['p-'+placeId].notes = $('#notes-'+placeId).val();
		},
		
		moveUp: function(placeId)
		{
			var currentIndex = null;
			$.each(this.placesArray, function(i,place){
				if(place.id == placeId)
				{
					currentIndex = i;
					return false;
				}
			});
			if(currentIndex === 0){return;}
			this.swapArrayItems(this.placesArray, currentIndex, currentIndex-1);
			//this.placesArray.swap(currentIndex, currentIndex-1);
			this.reorder();
			this.renderFullItinerary();
			this.save(true);
		},
		
		moveDown: function(placeId)
		{
			var currentIndex = null;
			$.each(this.placesArray, function(i,place){
				if(place.id == placeId)
				{
					currentIndex = i;
					return false;
				}
			});
			if(currentIndex == this.placesArray.length-1){return;}
			this.swapArrayItems(this.placesArray, currentIndex, currentIndex+1);
			//this.placesArray.swap(currentIndex, currentIndex+1);
			this.reorder();
			this.renderFullItinerary();
			this.save(true);
		},
		
		/**
		 * returns [x,y] offset to centre the map graphic over a given location
		 */
		getPixelOffsets: function(placeId)
		{
			// width and heigh of the element that contains the map
			var viewportSize = [100,100];
			// top,right,bottom,left - rough bounds of New Zealand
			var nzBounds = [-34.39302891980463, 178.56388092041016, -47.29675326174874, 166.42647743225098];
			// width, height - of nz map graphic
			var mapGraphicSize = [173,250];
			
			var latitude = this.places['p-'+placeId].latitude;
			var longitude = this.places['p-'+placeId].longitude;

			var nzBoundsDiff = [ nzBounds[1]-nzBounds[3]  , nzBounds[2]-nzBounds[0] ];
			var latitudeRelative = latitude - nzBounds[0]; // - nzBoundsDiff[1]; 
			var longitudeRelative = longitude -nzBounds[3];  // - nzBoundsDiff[0]; 
			var widthMultiplier = mapGraphicSize[0] / nzBoundsDiff[0];
			var heightMultiplier = mapGraphicSize[1] / nzBoundsDiff[1];
			
					
			var pixelOffsetWidth = (longitudeRelative * widthMultiplier)-(viewportSize[0]/2)  ;
			var pixelOffsetHeight = (latitudeRelative * heightMultiplier)-(viewportSize[1]/2) ;

			return [ - parseInt(pixelOffsetWidth,10), - parseInt(pixelOffsetHeight,10)];
		},
		
		
		
		test: function()
		{
			this.addPlace(253, 'Auckland', '/home/s1248598686');
			this.addPlace(525, 'Christchurch', '/home/test');
			this.addPlace(382, 'Invercargill', '/home/test');
			
			this.places['p-525'].arrive = '27/06/2010';
			this.places['p-525'].depart = '02/07/2010';
			this.places['p-525'].notes = 'Would be nice to visit the Cathedral in the town square.';
			this.places['p-525'].latitude = -43.526149;
			this.places['p-525'].longitude = 172.65152;
			this.places['p-525'].type = 'location';
			
			this.places['p-253'].arrive = '20/06/2010';
			this.places['p-253'].depart = '27/06/2010';
			this.places['p-253'].notes = 'Bungy jumping at the harbour bridge looks fun.';
			this.places['p-253'].latitude = -36.856411;
			this.places['p-253'].longitude = 174.768105;
			this.places['p-253'].type = 'location';
			
			this.places['p-382'].arrive = '02/07/2010';
			this.places['p-382'].depart = '10/07/2010';
			this.places['p-382'].notes = 'Meet tim.';
			this.places['p-382'].latitude = -46.413055;
			this.places['p-382'].longitude = 168.356883;
			this.places['p-382'].type = 'location';

			this.addListingAd(253, 321, 'accommodation', '/home/test_dome', 'Bobs B&amp;B');
			
		}
		
		
};

$(document).ready(function () {
	itinerary.init();
	
});
