if (Garmin == undefined) var Garmin = {};
if (Garmin.Foto == undefined) Garmin.Foto = {};


/** Foto Connect is a Garmin Communicator - Google Maps - Photo Service mashup.
 * This class contains the various UI component creation methods.
 * @constructor 
 */
Garmin.Foto.FotoConnectUI = Class.create();
Garmin.Foto.FotoConnectUI.prototype = {

	garminDisplayId: "garminDisplay",
	plugInNotInstalledDialogId: "pluginNotInstalled",
	communicatorDialogId: "garminDisplayWindow",
	savePhotosButtonId: "savePhotosButton",
	communicatorCloseButtonId: "communicatorCloseButton",
	advancedSearchDivId: "advancedSearchDiv",
	advancedSearchToggleId: "advancedSearchToggle",
	pageHeaderId: "headerDiv",
	// string the locale stored in the cookie
	localeCookie: null,
	// string the count of the number of photos the user has remaining
	count: null,
	// boolean used is toggleStaggingControls to decide if new
	// request in photoCounter should be made to toggle html for the photoCounter.
	// this way the counter doesn't show when the user removes all the photos and 
	// is taken back to the getting started template.
	newRequest: true,
	communicatorPluginButton: null,
	//path to image folder set on photos.xhtml
	imagePath: $("imagePath").innerHTML,
	
	initialize: function() {
		Ext.QuickTips.init();
		display = this.createGarminDeviceDisplay();
		this.integrateCommunicator();
		
		var map = this.createGoogleMap();
		var paginator = new Garmin.Foto.PageControl(null, 10, null, bundle_photos.photoPaginatorLabel);
		
		map.addControl(paginator);
		
		//instantiate PhotoLoader and load photos from a default location
		loader = new Garmin.Foto.PhotoLoader(map, paginator);
		loader.previewPhoto(null);
		
		paginator.setPageChangeCallback(loader.setPage); //TODO should be an event
		loader.updateMap();
		this.toggleStaggingControls(false);
		this.toggleAdvancedSearch(false);
		this.generateLayout();
		this.iFrameLoader = loader;
		
	},
	
	/**
	 * initialized at page load. Used to show drop down menu for language select
	 */
	generateLayout: function() {
		this.localeCookie = this.readCookie("PrimaryGarminUserLocalePref");
		/**
		 * creates combo box for language select.  store isn't localized because we want
		 * it to be standardized rather than changing for every language.
		 * Grabs value from localeCookie if exists; otherwise english.
		 */
		var localeField	= new Ext.form.ComboBox({
            store: new Ext.data.SimpleStore({ //simple string for drop down
                fields: ['id', 'display'],
                data : [['en', 'English'], ['da', 'Dansk'], ['de', 'Deutsch'], 
                		['es', 'Espa\u00F1ol'], ['fr', 'Fran\u00E7ais'], ['it', 'Italiano'], 
                		['ja', '\u65E5\u672C\u8A9E'], ['nl', 'Nederlands'], ['no', 'Norsk'], 
                		['pt', 'Portugu\u00EAs'], ['fi', 'Suomi'], ['sv', 'Svenska'], 
                		['zh', '\u7B80\u4F53\u4E2D\u6587'], ['zh_TW', '\u7E41\u9AD4\u4E2D\u6587']]
            }),
            value: (this.localeCookie == null) ? 'English' : this.localeCookie.toString(),
            valueField:'id',
            displayField:'display',
			renderTo: 'locale',
            mode: 'local',
            triggerAction: 'all',
            width:120
		});
		/**
		 * select event, sets localeCookie to the new preferred language set
		 * to expire for one year.
		 * reloads the page with the new i18n text
		 */
		localeField.on('select', function(){
			var localeValue = localeField.value;
			fotoConnect.setCookie('PrimaryGarminUserLocalePref', localeValue, 365);
			parent.location.reload();
		});
		/**
		 * populates the terms of service link on the bottom of the map with language
		 * as a param.  currently google doesn't have that text i18d yet, so this is 
		 * pointless, but it will pay off in the future
		 */
		$('googleTosLink').innerHTML = bundle_photos.terms;
	},
	
	/**
	 * function used to read cookies, receives all cookies, splits at ";",
	 * then parses through to find the cookie with the given name
	 * 
	 * @param name string for cookie you want read
	 * @return null if cookie isn't found, value of cookie if found
	 */
	readCookie: function(name) {
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
		}
		return null;
	},
	
	/**
	 * creates a cookie with specified params, coverts number of days 
	 * to time
	 * 
	 * @param name string the name of cookie created
	 * @param value string the value of the cookie created
	 * @param days integer days from now for cookie to expire
	 */	
	setCookie: function(name,value,days) {
		if (days) {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
		}
		else var expires = "";
		document.cookie = name+"="+value+expires+"; domain=garmin.com; path=/";
		document.cookie = name+"="+value+expires+"; domain=my.garmin.com; path=/";
		document.cookie = name+"="+value+expires;
	},
	
	/**
	 * sets this.count, and parses the resource bundle value to insert the new value w
	 * which is 50 - whatever this.count is.  reassigns whatever insertCount function 
	 * returns to the html.
	 * 
	 */
	displayCounter: function(){
		if (loader.username != null){
			this.setCount();
			var insertValue = 50 - this.count;
			var totalCount = this.insertCount(bundle_photos.photoConnectUI_remain, insertValue);
			$("counter").innerHTML = totalCount;
			
		}
	},
	
	/**
	 * replaces the {text} with the insertValue of the count of photos remaining to download
	 * 
	 * @param completeString String the value with braces retrieved from the resource bundle
	 * @param insertValue integer the number of photo downloads the user has remaining.
	 * @return String the i18n version of the photos remaining string with the proper amount 
	 * remaining inserted
	 */
	insertCount: function(completeString, insertValue){
		var totalCount = completeString.replace(/{(.+?)}/, insertValue);
		return totalCount;
		
	},
	
	/**
	 * reads counter cookie given the current date to find out how many
	 * photo downloads the user has remaining.  sets count variable accordingly
	 * 
	 * @return counterString string the value of "counter" plus todays date, used 
	 * for setting the cookie
	 */
	setCount: function(){
		var d = new Date().getDate();
		var counterString = "counter" + d;
		this.count = this.readCookie(counterString);
		if (this.count == null){
			this.count = 0;
		}else{
			this.count = parseInt(this.count);
		}
		return counterString;
	},
	
	createGarminDeviceDisplay: function() {
 		//configure Communicator DeviceDisplay instance for saving photo URLs:
	    var display = new Garmin.DeviceDisplay(this.garminDisplayId, {
	    
	    	/* unlock key */
	    	pathKeyPairsArray: [
				"http://integrationmb.garmin.com:8080/","587d1ca803d315c0b5c013dcfa851f52",
				"http://localhost.garmin.com","b6df6908d586eccc42c8b99e67d9698d",
				"http://connectwebtest.garmin.com:8080/","c68c868059345adc01e26f653773526f",
				"http://connecttest.garmin.com:8080/", "3b8fca2252575983767e51fcde9820a7",
				"http://connectdev.garmin.com", "dea6c638fffb791c7c96a703c988198f",
				"http://connectstg.garmin.com/","b8923d2e5bae7d627704c36235f430d2",
				"http://connect.garmin.com", "94606747b59e385d00732f85a4e0face"
			],
	    	
	    	/* component show/hide */
			showFindDevicesElement: true,
	    	showReadDataElement: false,
	    	showStatusElement: true,
	    	showWriteDataElement: true,
	    	
	    	findDevicesButtonText: bundle_photos.findDeviceButton,
	    	writeDataButtonText: bundle_photos.sendButton, 
	    	cancelWriteDataButtonText: bundle_photos.cancelButton,

			/* texts */
			deviceSelectLabel: "",
			lookingForDevices: 
				"<p>"+
					bundle_photos.lookingForDevices+
				"</p><img style='margin-top:10px;' src='"+this.imagePath+"/processing.gif' />",
			foundDevices: bundle_photos.chooseDevice,
			writtenToDevice: bundle_photos.writtenToDevice,
			noDeviceDetectedStatusText:  bundle_photos.noDeviceDetectedStatusText,

	    	//useLinks: true,
	    	unlockOnPageLoad: false,
	    	autoFindDevices: false,
	    	showCancelFindDevicesButton: false,
	    	autoSelectFirstDevice: false,
	    	autoReadData: false,
	    	autoWriteData: false,
			writeDataType:	Garmin.DeviceControl.FILE_TYPES.gpi,
			
			/** Override method - returns an array of photo URL-path pairs */
			getGpiWriteDescription:	function() {
				var array = [];
				loader.getStagedPhotoArray().each( function(photo) {
					array.push( photo.photoURL() );
					array.push( loader.getDevicePhotoPath() + photo.uniqueFileName() );
					//log( photo.photoURL() + " -> " + loader.getDevicePhotoPath() + photo.uniqueFileName());
				});
				return array;
			},
			
			/** Override method - returns a unique name by appending timestamp */
			getWriteDataFileName: function() {
				var ext = loader.getKmlWriteMode() ? "kml" : display.options.writeDataType;
				var fileName = "Panoramio_" + 
					new Garmin.DateTimeFormat().format("#{year}#{month}#{day}T#{hour}#{minute}#{second}", true) + 
					"." + ext; 
				//log("getWriteDataFileName(): " + fileName);
				return fileName;
			},
			
			/** Override method - supports two types of output: 1) KML 2) GPX waypoints */
			getWriteData: function() { 
				//log("getWriteData: loader.getKmlWriteMode=()"+loader.getKmlWriteMode());
				if (loader.getKmlWriteMode()) {
					var kml = loader.createKML();
					//$("kmlOutput").innerHTML = kml;
					return kml
				} else {
					var waypoints = '';
						loader.getStagedPhotoArray().each( function(photo) {
							
							
							var title = photo.getTitle() ? photo.getTitle().escapeHTML() : "panoramio_" + photo.getPhotoID();
							waypoints +=
							    '<wpt lat="' + photo.getLat() + '" lon="' + photo.getLng() + '">' +
							        '<name>' + title + '</name>' +
						        	'<src>Panoramio</src>' +
						        	'<link href="' + loader.getDevicePhotoPath() + photo.uniqueFileName() + '">' +
							            '<type>image/jpeg</type>' +
							        '</link>' +
							        '<link href="' + photo.getOwnerURL() + '">' +
							            '<text>' + photo.getOwnerName().escapeHTML() + '</text>' +
							            '<type>text/html</type>' +
							        '</link>' +
							        '<link href="' + photo.getPhotoPageURL() + '">' +
							            '<type>text/html</type>' +
							        '</link>' +
							        '<sym>Scenic Area</sym>' +
							        '<extensions>' + 
							        	'<gpxx:WaypointExtension xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3">' +
							        		'<gpxx:Categories>' +
							        			'<gpxx:Category>Photos</gpxx:Category>' +
							        		'</gpxx:Categories>' +
							        	'</gpxx:WaypointExtension>' +
							        '</extensions>' +
							    '</wpt>';
						});
						var xml = 
							'<?xml version="1.0" encoding="UTF-8"?>' +
							'<gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
							      'xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd" ' +
							      'version="1.1" creator="http://connect.garmin.com/">' +
							    waypoints +
							'</gpx>';
						//log("getWriteData(): xml =" + xml);
						return xml;
					
				}
			},
			
			/** Override method - handles 3 separate post-write functions:
			 * 1) KML write - resets back to GPI/GPX mode
			 * 2) 2 phase write - GPI followed by GPX write - handles state change between writes and initiates 2nd phase write 
			 */
			afterFinishWriteToDevice: function(success, display) { 
				if (loader.getKmlWriteMode()) {
					loader.setKmlWriteMode(false); // always reset this;
					display.options.writeDataType = Garmin.DeviceControl.FILE_TYPES.gpi;
					this.showCommunicatorEndState();
				} else { 
					if (display.options.writeDataType == Garmin.DeviceControl.FILE_TYPES.gpi) { // phase 1 - write gpi
						display.options.writeDataType = Garmin.DeviceControl.FILE_TYPES.gpx; //switch to phase 2
						display.writeToDevice();
						
						display.findDevicesButton.disabled = true;
						display.writeDataButton.disabled = true;
					} else { // phase 2 - write gpx
						display.options.writeDataType = Garmin.DeviceControl.FILE_TYPES.gpi; //switch back
						this.showCommunicatorEndState();					
					}
				}				
			}.bind(this),
			
			/** Override method 
			*/
			afterFinishFindDevices: function(devices, display) {
				if (devices.length > 0) {
					display.findDevicesButton.disabled = true;
				}
			},
			
			/** Override method - always reset write mode to GPI */
			customExceptionHandler: function(error) {
				loader.setKmlWriteMode(false); // always reset this;
				display.options.writeDataType = Garmin.DeviceControl.FILE_TYPES.gpi;
				//TODO - the following code should be replaced with: display.defaultExceptionHandler(error);
	    	    		//log("customExceptionHandler(): error="+error);
				var errorStatus;
				var hideFromBrowser = false;
				if(error.name == "BrowserNotSupportedException") {
					errorStatus = error.message;
					if (display.options.hideIfBrowserNotSupported) {
						hideFromBrowser = true;
					}
				} else if (error.name == "PluginNotInstalledException" || error.name == "OutOfDatePluginException") {
					errorStatus = error.message;
					errorStatus += " <a href=\""+Garmin.DeviceDisplay.LINKS.pluginDownload+"\" target=\"_blank\">"  + 
						display.options.downloadAndInstall + "</a>";
				} else if (Garmin.PluginUtils.isDeviceErrorXml(error)) {
					errorStatus = Garmin.PluginUtils.getDeviceErrorMessage(error);	
				} else {
					errorStatus = error.name + ": " + error.message;	
				}						
	 			display.setStatus(bundle_photos.errorOccuredText + "<div style='margin-top: 15px; font-size: 14px;'>" + 
	 				errorStatus + "</div>");
				display.resetUI();				
				
				this.showCommunicatorEndState();
				
				//if no status UI div is defined, make sure the user sees the error
				if (!display.options.showStatusElement && !hideFromBrowser) {
					if (error.name == "PluginNotInstalledException" || error.name == "OutOfDatePluginException") {
						if (window.confirm(error.message+"\n" + display.options.installNow)) {
							window.open(Garmin.DeviceDisplay.LINKS.pluginDownload, "_blank");
						}
					} else {
						alert(errorStatus);
					}
				}
			}.bind(this)
		});
		
		display.buttonBar = document.createElement("div");
		Element.extend(display.buttonBar);
		display.buttonBar.addClassName(display.options.elementClassName);
		display.mainElement.insertBefore(display.buttonBar, display.aboutElement);
		
		display.buttonBar.appendChild(display.findDevicesButton);
		display.buttonBar.appendChild(display.writeDataButton);
		display.buttonBar.appendChild(display.cancelWriteDataButton);
		display.buttonBar.style.textAlign="center";
		
		display.statusElement.appendChild(display.deviceSelectElement);
		
		return display;
	},
	
	//these two basicDialog calls have to be changed when ext is updated to window.
	integrateCommunicator: function() {
		pluginNotInstalledDialog = new Ext.BasicDialog(this.plugInNotInstalledDialogId, {
		        width:460,
		        height:320,
		        resizable: false,
  		        collapsible: false,
		        shadow: "frame"
		});
		
		communicatorDialog = new Ext.BasicDialog(this.communicatorDialogId, {
		        width:460,
		        height:300,
		        resizable: false,
		        collapsible: false,
		        shadow: "frame"
		});

		if (PluginDetect.detectGarminCommunicatorPlugin()) {
			this.communicatorPluginButton = document.createElement("input");
			this.communicatorPluginButton.id = 'sendButton';
			this.communicatorPluginButton.type = "button";
			this.communicatorPluginButton.value = bundle_photos.communicatorPluginButton;
			this.communicatorPluginButton.disabled = true;
			/**
			 * when the user clicks the send to device button, the counter cookie is 
			 * gotten to find out how many photos the user can download, which is outputted
			 * beneath the button.  the cookie is updated with a new value every time the button
			 * is pressed with the new value of the amount of photos to add plus the current count
			 * the user has already downloaded.
			 * 
			 * If the user has already exceeded the amount of photos downloaded or if the amount
			 * the user chooses to send exceeds the 50 they're allowed, a message pops up alerting the 
			 * user of such.
			 */
			this.communicatorPluginButton.onclick = function() {
				var counterString = this.setCount();
				if (this.count + loader.getStagedPhotoArray().length <= 50){
					this.setCookie(counterString, loader.getStagedPhotoArray().length + this.count, 1);
					if ($(this.communicatorDialogId).style.visibility == "hidden") {
						this.displayCounter();				
						communicatorDialog.show(this.communicatorPluginButton);
						display.startFindDevices();
					}
				}else{
					$("popUpContent").innerHTML = 
						"<div id='popupDownloadLimit'>" +
							"<div class='popupLarge'>" +
								"<div class='popupCloseButton'>" +
									"<a onclick='Ext.get(\"popupDownloadLimit\").toggle()'>" +
									"<img src='"+this.imagePath+"/icon_close.png' /></a>" +
								"</div>"+bundle_photos.popups_download+"<br /><br />" +
        						bundle_photos.popups_download_50 + "<br /><br />" +
        						bundle_photos.popups_download_remain+"" +
        					"</div>" +
        				"</div>"
				}
			}.bind(this);
			$(this.savePhotosButtonId).appendChild(this.communicatorPluginButton);
		}
	},
	
	resetCommunicatorState: function() {
		Element.show(display.buttonBar);
		var closeButton = $(this.communicatorCloseButtonId);
		if (closeButton) {
			Element.remove(closeButton);
		}
	},
	
	showCommunicatorEndState: function() {
		Element.hide(display.buttonBar);
		var closeButtonBox = $(this.communicatorCloseButtonId);
		if (!closeButtonBox) {
			closeButtonBox = document.createElement("div");
			Element.extend(closeButtonBox);
			closeButtonBox.id = this.communicatorCloseButtonId;
			closeButtonBox.style.textAlign = "center";
			var closeButton = document.createElement("input");
			Element.extend(closeButton);
			closeButton.type = "button";
			closeButton.value = bundle_photos.closeButton;
			closeButton.addClassName(display.options.actionButtonClassName);
			closeButton.disabled = false;
			closeButton.onclick = function() {
				communicatorDialog.hide();
				this.resetCommunicatorState();
			}.bind(this);
			closeButtonBox.appendChild(closeButton);
			display.mainElement.appendChild(closeButtonBox);
		}
	},
	createGoogleMap: function() {
		//Google Map setup
		var map = new GMap2(document.getElementById("mapDiv"));
		map.addControl(new GMapTypeControl());
		map.addControl(new GLargeMapControl());
		map.enableScrollWheelZoom();
		map.disableDoubleClickZoom();
		new GKeyboardHandler(map);
		map.setCenter(new GLatLng(37.808563, -122.409004), 11);
		GEvent.addListener(map, "moveend", function() { //moveend includes zoomend and dragend
			log("Map moveend ");
			//loader.updateMap(true);
		});
		return map;
	},
	
	toggleStaggingControls: function(enable) {	
		enable = enable != null ? enable : false;
		this.toggleAnchor("saveAsKmlLink", enable);
		var communicatorElement = new Ext.Element(this.communicatorPluginButton);
		if (this.communicatorPluginButton != null) {			
			enable = enable != null ? enable : communicatorElement.removeClass("hidden");
			if (enable) {
				this.communicatorPluginButton.disabled = false;
				communicatorElement.removeClass("hidden");
				if (this.newRequest){
					Ext.get("counter").toggle(true);
					this.displayCounter();
					this.newRequest = false;				
				}
			} else {		
				this.communicatorPluginButton.disabled = true;
				communicatorElement.addClass("hidden");
				Ext.get("counter").toggle(false);
				this.newRequest = true;
			}
		}
	},

	toggleAdvancedSearch: function(show) {
		var isVisible = $(this.advancedSearchDivId).visible();
		$("advancedSearchDiv").style.visibility="visible";
		$(this.advancedSearchToggleId).innerHTML = isVisible ? bundle_photos.advancedSearch : bundle_photos.hideAdvancedSearch;
		Element.toggle(this.advancedSearchDivId);
		var headerHeight = Ext.get(this.pageHeaderId).getComputedHeight();
		if (isVisible) { 
			$("searchBoxWrapper").setStyle({backgroundPosition: '0 0'});
		} else {
			$("searchBoxWrapper").setStyle({backgroundPosition: '0 -100px'});
		}
	},

	toggleAnchor: function(anchor, enable){
		anchor = $(anchor);
		if (enable) {
			anchor.onclick = anchor.onclick_backup;
			//anchor.setAttribute('href', anchor.attributes['href_bak'].nodeValue);
			anchor.style.color="blue";
		} else {
			//var href = anchor.getAttribute("href");
			if(anchor.onclick && anchor.onclick != "" && anchor.onclick != null) {
				//anchor.setAttribute('href_bak', href);
				anchor.onclick_backup = anchor.onclick;
			}
			anchor.onclick = null;				
			//anchor.removeAttribute('href');
			anchor.style.color="gray";
		}
	}


};
