	


//declaring the class
var App = Class.create();

//defining the rest of the class implementation
App.prototype = {
	initialize: function() {
		this.isLoggedIn = false;
		this.userType = "";
		
		var l = location.pathname

		this.isIndexPage = (l.indexOf("index.php") != -1 || l.charAt(l.length-1) == "/" );
		this.isFeaturePage = (l.indexOf("features.php") != -1);
		this.isSignupPage = (l.indexOf("signup.php") != -1);
		this.isProfilePage = (l.indexOf("profile.php") != -1);
		this.isClassPage = (l.indexOf("class.php") != -1);
		this.isGettingStartedPage = (l.indexOf("gettingstarted.php") != -1);
		this.isEnrollmentPage = (l.indexOf("enrollment.php") != -1);
		this.IE = (navigator.appName.indexOf ("Microsoft") != -1) ? 1 : 0;
	},

	initApp: function(){



		hint  = new Hint($("hintMain"));

		//Update the this.isLoggedIn
		this.fixLoginGui(true);

		this.initPage();

		if(this.isFeaturePage){
			this.initFeaturePage();
		}else if(this.isIndexPage){
			this.initIndexPage();
		}else if(this.isSignupPage){
			this.initSignupPage();
		}else if(this.isProfilePage){
			this.initProfilePage();				
		}else if(this.isClassPage){
			this.initClassPage();
		}else if(this.isGettingStartedPage){
			this.initGettingStartedPage();
		}else if(this.isEnrollmentPage){
			this.initEnrollmentPage();
		}		







		//
		// Login
		//		
		Event.observe($("username"), "keypress", function(event) {
			var code = event.keyCode;
			if(code == Event.KEY_RETURN){
				this.userLogin();	
			}
		}.bind(this));
		Event.observe($("password"), "keypress", function(event) {
			var code = event.keyCode;
			if(code == Event.KEY_RETURN){
				this.userLogin();	
			}
		}.bind(this));		
		Event.observe($("dologin"), "click", this.userLogin.bind(this));


		//
		// Logout
		//
		Event.observe($("dologout"), "click", function(){
			this.userLogout(".");
		}.bind(this));




		Event.observe($("tabLogin"), "click", function(){
			new Effect.toggle($("divLoginContents"),'slide', {duration:0.7});
		});

		this.fixMenu();

	},
	initPage: function(){

	},

	initIndexPage: function(){
		this.zoomifierPage();

		if($("showLogin")){
		 Event.observe($("showLogin"), "click", function(){
			myutils.setPageScrollHeight(0); //scroll to top of the page
			new Effect.toggle($("divLoginContents"),'slide', {duration:0.7});
		 });
		}


		var url = window.location.search.toQueryParams();
		if(url.loggedout == "1"){
			var msg = "<h3>Thank You!</h3>";
			msg += "Thank you for contributing to the Mars Public Mapping Project. Hope to see you again soon!";
			hint.show(msg, true, true);
		}



		Event.observe($("homeHelpScientistsButton"), "click", function(){
			$('homeHelpScientists').toggle();
		});

	},
	initGettingStartedPage: function(){

		if($("showLogin")){
		 Event.observe($("showLogin"), "click", function(){
			myutils.setPageScrollHeight(0); //scroll to top of the page
			new Effect.toggle($("divLoginContents"),'slide', {duration:0.7});
		 });
		}


		var url = window.location.search.toQueryParams();
		setTimeout(function(){
			if(this.isLoggedIn && (url.type == "I" || url.type == "S" || url.type == "T") ){
				var msg = "<h3>Welcome!</h3>You're now registered and logged in.<br>";
				msg += "(If you don't wish to continue right now, "+
					"<a href=\"javascript:app.userLogout('.');hint.closeAll();\">click here to log out</a>.)";
				hint.show(msg, true, true);
			}
		}.bind(this), 300);
	},

	initSignupPage: function(){
		this.initUserForm();
//		Event.observe($("regAdditionalFieldsToggle"), "click", this.refreshUserForm.bind(this, $("user_I")));
//		Event.observe($("checkClassAvailability"), "click", this.checkClassAvailability.bind(this));

		//Automatic login if signuped
		if($("loginSuccess") && $F("loginSuccess") == "1"){
			$("username").value = $F("regUsername");
			$("password").value = $F("regPassword");


			if($("loginUserType").value == "I"){
				setTimeout(function(){
					this.userLogin("gettingstarted.php?type=I");
				}.bind(this),4000);

			}else if($("loginUserType").value == "S"){
				setTimeout(function(){
					this.userLogin("gettingstarted.php?type=S");
				}.bind(this),4000);
			}else{	//LOGIN and stay in the current page (no redirection)
				this.userLogin(null,true);
			}

		}

//		this.refreshUserForm();
	},

	initEnrollmentPage: function(){
		Event.observe($("checkClassAvailability"), "click", this.checkClassAvailability.bind(this));
	},
	initProfilePage: function(){
		this.initUserForm();
	},

	initUserForm: function(){
		var elements = document.getElementsByClassName("Closeable");
		for (i = 0 ; i < elements.length ; i++) {
			new Closeable(elements[i], this.refreshUserForm.bind(this));
		}

	},
	refreshUserForm: function(box){
		if(box && box.value == "user_I" && $("regAdditionalFieldsToggle")){
			if($("regAdditionalFieldsToggle").checked){
				$('regAdditionalFields').removeClassName("closed");					
			}else{
				$('regAdditionalFields').addClassName("closed");				
			}			
		}else{
			$('regAdditionalFields').removeClassName("closed");
		}
	},

	initClassPage: function(){

	},

	initFeaturePage: function(){
		this.zoomifierPage();

		//
		// Examples
		//
		Event.observe($("closeExample"), "click", function(){
			gui.winClose();
 	             $("exIframe").src = "img/blank.gif";
		});
		//
		// Map
		//
		Event.observe($("closeMap"), "click", function(){
			$("mapImage").addClassName("hidden");
			gui.winClose();
			$("mapImage").opened = 0;
			$("mapImage").src = "img/blank.gif";

		});
		/** IE 6 Fix (if the image takes longer to load, give it another chance */
		Event.observe($("mapImage"), "error", function(){
			if(this.opened == 1){
				this.opened = 0;
				var src = this.src;
				this.src = "img/blank.gif";
				this.src = src;
			}
		});
	},

	zoomifierPage: function(){

		zoomifier = new Zoomifier('zoomifier');		

		//Store info for 10 images 
		storage  = new Storage(10); 
		
		onlyRating = false;
		if(this.isIndexPage){
			onlyRating = true;
		}

		featureIdentification =  new FeatureIdentification(null, onlyRating, function(){
			imageControl = new ImageControl();
			
		});



		Event.observe($("labelImageId"), "click", function(){
			if($("labelImageId").innerHTML){
				window.open("http://themis-data.asu.edu/img/"+ $("labelImageId").innerHTML, "_blank");
			}
		});
		Event.observe($("divMiddleImage"), "click", function(){
			if($("labelImageId").innerHTML){
				window.open("http://themis-data.asu.edu/img/"+ $("labelImageId").innerHTML, "_blank");
			}
		});



		/** Context Image **/
		Event.observe($("contextMagnify"), "click",  this.openContext.bind(this));
		Event.observe($("contextImage"), "click",  this.openContext.bind(this));
		Event.observe($("closeContext"), "click", function(){
			$("largeContextImage").addClassName("hidden");
			gui.winClose();
			$("largeContextImage").opened = 0;
			$("largeContextImage").src = "img/blank.gif";
			$("contextImageForId").innerHTML = "";
		});

		/** IE 6 Fix (if the image takes longer to load, give it another chance **/
		Event.observe($("largeContextImage"), "error", function(){
			if(this.opened == 1){
				this.opened = 0;
				var src = this.src;
				this.src = "img/blank.gif";
				this.src = src;
			}
		});

		/** End of Context Image **/
	},

	openContext: function(){
		if(!$("labelImageId").innerHTML){
			alert("No image is loaded");
			return false;
		}
		new MyProcess(function(){
			$("largeContextImage").removeClassName("hidden");
			gui.winOpen($("winContext"));
		}.bind(this));

		new MyProcess(function(){
			$("largeContextImage").opened = 1;
			$("contextImageForId").innerHTML = $("labelImageId").innerHTML;
			$("largeContextImage").src = "maps/get_map.php?image_id="+ $("labelImageId").innerHTML;

		}.bind(this));
	},



	//
	// Do the actual user login
	//
	userLogin: function(redirectURL, dontRedirect){
		var url="ajax/login.php";
		url += "?username="+$F("username");
		url += "&password="+$F("password");


		$("loginMsg").innerHTML = "Logging in...";
		myreq.httpQuery(url, function(req){
			var msg =  myreq.getCompletedText(req);

				if(myreq.isError(req) || myreq.isNotice(req)){
					$("loginMsg").innerHTML = msg;
				}else{					
					$("username").value = "";
					$("password").value = "";
					$("loginMsg").innerHTML = "";	
					var m = msg.split("|");
					if(m.length == 2 && m[0].length > 0 && m[1].length > 0){
						$("spanUsername").innerHTML = m[0];
						this.userType = m[1];
						this.isLoggedIn = true;
			
						//Go to the feature page if currently in some other page.
						if(!this.isFeaturePage && !this.isIndexPage)
							if(redirectURL){
								$("loginForm").action = redirectURL;
							}
							if(!dontRedirect){
								$("loginForm").submit();
							}
						}
	
					this.fixLoginGui(false);
					if(imageControl)
						imageControl.restart();
				}						
		}.bind(this));	
	},


	//
	// Fixes the login gui. Based on wheather the user is loggedin or not,
	// it shows the relevant information.
	// @param force - Does an http request to check if the user is indeed logged in
	fixLoginGui: function(force){
		
		
		this.fixFunction = function(){
			$("classManagement").addClassName("hidden");
//			$("classEnrollment").addClassName("hidden");
			if(this.isLoggedIn){
				$("divLogin").addClassName("hidden");
				$("divUserInfo").removeClassName("hidden");

/*
				if(this.userType == "S"){
					$("classEnrollment").removeClassName("hidden");
				}
*/
				if(this.userType == "T"){
					$("classManagement").removeClassName("hidden");
				}
			}else{
				$("divUserInfo").addClassName("hidden");
				$("divLogin").removeClassName("hidden");
			}
		}.bind(this); 
	

		if(force){
			var url="ajax/loggedin.php";
			myreq.httpQuery(url, function(req){
				var msg =  myreq.getCompletedText(req);
				if(myreq.isNotice(req)){
					this.isLoggedIn = false;
				}else{			

					var m = msg.split("|");
					if(m.length== 2 && m[0].length > 0 && m[1].length> 0){
						$("spanUsername").innerHTML = m[0];
						this.userType = m[1];
						this.isLoggedIn = true;
					}
				}
				this.fixFunction();		
			}.bind(this));
		}else{
			this.fixFunction();
		}

	},

	userLogout: function(actionSubmit){
		var url="ajax/logout.php";


		myreq.httpQuery(url, function(req){
			var msg =  myreq.getCompletedText(req);
			if(myreq.isError(req) || myreq.isNotice(req)){
				alert(msg);
			}else{													
				this.isLoggedIn = false;
				this.userType = "";
				this.fixLoginGui(false);

				if(actionSubmit){
					var formId = "form"+actionSubmit.replace(".", "_");
					var form = new Element("form");
					form.id  = formId;
					form.method = "GET";
					form.action = actionSubmit;
					var field = new Element("input", {
									type:"hidden",
									name:"loggedout",
									value:"1"});			
					
					form.appendChild(field);
					$("body").appendChild(form);
					$(formId).submit();
				}else{
					if(imageControl)
						imageControl.restart();
				}			
			}		
		}.bind(this));
	},
	

	fixMenu: function(){
		var bts = document.getElementsByClassName("menu");
		bts = $A(bts);

		bts.each(function(btn){
				btn.baseSrc = btn.src.substring(0,btn.src.length-4);

				Element.observe(btn, "mouseover", function(){
					this.src = this.baseSrc +"_hover.gif";			
				},false);
				Element.observe(btn, "mouseout", function(){
					this.src = this.baseSrc +".gif";
				},true);

				Element.observe(btn, "click", function(){

					var id= "win_"+this.id;
					if($(id)){
						gui.winOpen($(id));
						if($(id).refresh){
							$(id).refresh();
						}
					}else{
//						alert("This page does not exist!");
					}

				},true);


		}.bind(this));

	},

	checkClassAvailability: function(){
			$("classAvailableMsg").innerHTML = "";

			var url="ajax/class_available.php";
			url +="?class_id="+$F("classId");
			url +="&class_key="+$F("classKey");

			myreq.httpQuery(url, function(req){
				var msg =  myreq.getCompletedText(req);
				$("classAvailableMsg").innerHTML = msg;
			});
	},


	deinitApp: function(){

	}



};



var ImageControl = Class.create();
ImageControl.prototype = {
	initialize: function(){
		this.loadInitialImage();
		this.currentImageId = null;
		this.nextImageId = null;
		this.totalSessionImages = 0;

		Event.observe($("divPreviousImage"), "click", this.previousImage.bind(this));
		Event.observe($("divPreviousImage"), "mouseover", function(){
			this.src = "img/nav_previous_hover.gif";

		});
		Event.observe($("divPreviousImage"), "mouseout", function(){
			this.src = "img/nav_previous.gif";

		});


		//Big dummy submit button on Feature page
		if(app.isFeaturePage){
			Event.observe($("divSubmitNext"), "click", this.nextImage.bind(this));
		}
		Event.observe($("divNextImage"), "click", this.nextImage.bind(this));
		Event.observe($("divNextImage"), "mouseover", function(){
			this.src = "img/nav_next_hover.gif";
		});
		Event.observe($("divNextImage"), "mouseout", function(){
			this.src = "img/nav_next.gif";

		});

	},

	
	//
	// Load the initial image (when application starts)
	//
	loadInitialImage: function(){

//		this.getInitialImageId(function(req){
		this.getNextImageId(function(req){
			var msg =  myreq.getCompletedText(req);
			if(myreq.isError(req) || myreq.isNotice(req)){
				alert(msg);
			}else{	
				this.currentImageId = msg;
				storage.addImage(this.currentImageId);
				this.totalSessionImages++;

				if(app.IE){
					//give some delay so the flash is fully loaded!				
					setTimeout(function(){
						this.loadImage(this.currentImageId);
					}.bind(this), 700);
				}else{
					this.loadImage(this.currentImageId);
				}


			}
			this.prepareNextImage();
		}.bind(this));
	},

	//	
	// Load the image to the viewer
	//
	loadImage: function(imageId){
		$("contextImage").src = "img/blank.gif";
		$("contextImage").src = "get_context_image.php?image_id="+imageId;
		featureIdentification.imageChanged(imageId);
		this.loadPreviousStars(imageId);
		zoomifier.loadImage(imageId);
		$("labelImageId").innerHTML = imageId;

	},

	//
	// The ajax script returns the image id which is 
	// used when the application starts 
	// (typically this image is already zoomified for speed purposes)
	//
	getInitialImageId: function(callback){
		var url="ajax/get_initial_image_id.php";		
		myreq.httpQuery(url, function(req){
			callback(req);
		});	
	},

	//
	// The ajax script returns the next image id to be used
	//
	getNextImageId: function(callback){
		var url="ajax/get_next_image_id.php";		
		myreq.httpQuery(url, function(req){
			callback(req);
		});	
	},


	//
	// Load the next image to the viewer
	//
	nextImage: function(){


		//If the index corresponds to an image on history 
		if(!storage.endReached()){			
				storage.next();
				this.currentImageId = storage.getCurrentImageId();
				this.loadImage(this.currentImageId);
		//ask for new image
		}else{
			var url = "ajax/is_zoomified.php?image_id="+this.nextImageId;
			myreq.httpQuery(url, function(req){
       	              var msg =  myreq.getCompletedText(req);
              	       if(myreq.isNotice(req) || myreq.isError(req)){
					alert('Next image has not been generated yet!\nPlease wait a few seconds and try again...');       
	                    	}else{				
					var nextImageId = msg;
					//Makes sure the nextImageId didn't change in the meantime
					if(nextImageId == this.nextImageId && storage.getCurrentImageId() != nextImageId){
						
						this.currentImageId = nextImageId;
						this.prepareNextImage();
						storage.addImage(this.currentImageId);
						this.loadImage(this.currentImageId);
						this.totalSessionImages++;

						if(!app.isLoggedIn && this.totalSessionImages == 3 ){
							var msg0 = '<b>Did you know</b> that ';
							msg0 += 'you can use the control buttons located below the image to zoom in/out and navigate?';
							hint.show(msg0, true, true);
						}else if(!app.isLoggedIn && this.totalSessionImages == 8){
							var msg0 = '<b>Are you getting the same images everytime you tried this website?</b><br>';
							msg0 += 'If yes, please signup and login, so you will have no repetitions and ';
							msg0 += ' have everything stored in your account!';	
//							hint.show(msg0, true, true);
						}else if( this.totalSessionImages == 100){
							var msg0 = '<b>Did you know</b> that ';
							msg0 += 'you can use the control buttons located below the image to zoom in/out and navigate?';
							hint.show(msg0, true, true);
						}




					}
				}		
			}.bind(this));
		}
	},


	//
	// Load the previous image to the viewer
	//
	previousImage: function(){
		var ok = false;
		if(!storage.beginningReached()){
			storage.previous();
	
			if(storage.imageAvailable()){	
                            this.currentImageId = storage.getCurrentImageId();
				this.loadImage(this.currentImageId);
				ok = true;
			}
		}
	
		if(!ok){
			alert("No previous images in history");
		}

	},

	//
	// Create an image id for the next image and zoomifies it if
	// neccessary.
	//
	prepareNextImage: function(){
             	this.getNextImageId(function(req){
                     var msg =  myreq.getCompletedText(req);
                     if(myreq.isError(req)){
                            alert(msg);
                     }else{
				//If the image is the same try again.
				if(msg == this.nextImageId && (msg != "" && msg != null)){
					this.prepareNextImage();	
					return false;
				}
				this.nextImageId = msg;	
				this.zoomifyImage(this.nextImageId, function(req2){
			       	var msg2 =  myreq.getCompletedText(req2);
					if(myreq.isError(req2) || myreq.isNotice(req2)){
						//alert(msg2);
					}else{
						//Preload next context image
						var im = new Image;
						im.src = "get_context_image.php?image_id="+this.nextImageId;
						im = null;
					}
				}.bind(this),false);
                     }
              }.bind(this));
	},

	//
	// Cuts the image in tiles to make it ready for the viewer
	// This will be done, before the image is actually zoomified
	// to increase the performance on the client
	//	
	zoomifyImage: function(imageId,callback, noLoading){
		var url="ajax/zoomify_image.php";
		url += "?image_id="+imageId;

		myreq.httpQuery(url, function(req){
			callback(req);
		}, noLoading);			
	},

	restart: function(){
              this.totalSessionImages = 0;
		storage.clear();
		this.loadImage(this.currentImageId);
		this.prepareNextImage();
	},

	/** Load average rating of all users about given image **/
	loadPreviousStars: function(imageId, callback){
		if(!imageId){
			alert("Image ID is missing");
			return;
		}		

		var url="ajax/get_image_rating.php";
		url += "?image_id="+imageId;
		myreq.httpQuery(url, function(req){
                     var msg =  myreq.getCompletedText(req);
			
			if(myreq.isSuccess(req)){
				var value = msg;
				featureIdentification.reloadStars(value);
				if(callback){
					callback(req);
				}
			}
		});			
	}
	
};


//Requires JavaScriptFlashGateway
var Zoomifier = Class.create();
Zoomifier.prototype = {
	initialize: function(containerId){
		var uid = new Date().getTime();

		this.flashProxy = new FlashProxy(uid, 'js/FlashJavascriptGateway/installation/JavaScriptFlashGateway.swf');
		var swf = 'MP2.swf';
		if(app.IE){
			swf += "?"+uid;
		}

		this.tag = new FlashTag(swf, '100%','100%',  '7,0,14,0');  
		var flashVars= "lcId="+uid+
		"&zoomifyImagePath=.&gZoomifyZoom=35&zoomifyToolbar=1&zoomifyToolbarIcon=2&zoomifyNavWindow=0&zoomifyClickZoom=1&zoomifyFadeInSpeed=0&zoomifyZoomSpeed=10";

		this.id = containerId+uid;		
		this.tag.setId(this.id);
		this.tag.setFlashvars(flashVars);
				
		$(containerId).innerHTML = this.tag;


		if($(containerId).firstChild){
			this.dom =  $(containerId).firstChild;
		}else{
			this.dom = null;
		}

		//Relative path to the images produced
		this.path = 'cache';

		new MyProcess(function(){
			$("contextImageIframe").setStyle("display:block");
		});
	},


	loadImage: function(imageId){
		var path = "zoomify/"+ (imageId.substr(0,4).toLowerCase()) +"xx/"+imageId;
		this.setImagePathInit(path);
		


	},
	setImagePathPreserve: function(path){
		this.flashProxy.call("ZoomifyViewerInstance.setImagePathPreservePosition",path);
	},

	setImagePathInit: function(path){             
		this.flashProxy.call("ZoomifyViewerInstance.setImagePathInit",path);
	},
	setImagePath: function(path){
		this.flashProxy.call("ZoomifyViewerInstance.setImagePath",path);
		setTimeout(this.updateView.bind(this),1000);
	},
	updateView: function(){
		this.flashProxy.call("ZoomifyViewerInstance.updateView");

	}
}


var FeatureIdentification = Class.create();
FeatureIdentification.prototype = {
	initialize: function(featuresArray, onlyRating, callback){

		//When some http request begins, this is set to true
		this.touched = false;
		
		//All the features have the same record id for a particular image
		this.recordId = null; 
		this.imageId = null;
		this.stars = null;

		if(onlyRating){
			if(callback){
				callback();
			}				
		}else{

			if(featuresArray){
				this.featuresArray  = featuresArray;
				this.createDom($("features"));
				if(callback){
					callback();
				}
			}else{
				this.loadFeaturesArray(function(){
					this.prepareAllFeatures();
					this.createDom($("features"));

					if(callback){
						callback();
					}				
				}.bind(this));
			}



			//Prepare feature tags
			this.prepareFeatureTags();
		}
	},


	createDom: function(container){
		if(!this.featuresArray){
			alert("Features don't exist");
			return;
		}

		this.featuresArray.each( function(ft){
			container.appendChild(ft.getFeatureHtml());
			prevCategory = ft.category;
		});
	},

	prepareAllFeatures: function(){
		if(!this.featuresArray){
			alert("Features don't exist");
			return;
		}

		var that = this;
		this.featuresArray.each( function(ft){
			ft.setOnCompleteFunction(that.featureSave.bind(that),function(req){
				var msg =  myreq.getCompletedText(req);
				if(myreq.isError(req) || myreq.isNotice(req)){
					alert('ERROR:'+msg);
				}else{	
					var recordId = msg;	
					var trustedFeatureValue = null;
					var info = msg.split("|");
					if(info.length == 2){
						recordId = info[0];
						trustedFeatureValue = info[1];
					}			
/*
							
					//If still in training mode
					if(trustedFeatureValue != null){		
						if(this.selectedValue == trustedFeatureValue){
							ft.testSucceeded(trustedFeatureValue);
						}else if(this.selectedValue != -1){
							ft.testFailed(trustedFeatureValue);
						}else{
							ft.testReset();
						}


						if(!that.hintInTrainingShowed){
							hint.show("You are going to be trained in the first 10 images. "+
							   "After that, your contribution will start!", true,true);
							that.hintInTrainingShowed = true;
						}

					}
*/
					that.itemSaved(recordId);
				}		
			}.bind(ft));
		});
	},
	resetAllFeatures: function(){
		if(!this.featuresArray){
			alert("Features don't exist");
			return;
		}
		
		this.featuresArray.each( function(ft){
			ft.featureReset();
		});
	},
	
	featureSave: function(feature, featureId, selectedValue, callback){

		if(!this.imageId){
			alert("Current Image ID has not been found, please refresh");
			return;
		}
		if(this.touched && !this.recordId){
			feature.featureReset();
			alert('Still saving the previous item. Please wait a few seconds and try again...');
			return;
		}

		this.touched = true;
	

		var url = "ajax/save.php";
		url += "?image_id="+this.imageId;
		url += "&feature_id="+featureId;
		url += "&value="+selectedValue;
		if(this.recordId){
			url += "&record_id="+this.recordId;
		}
		myreq.httpQuery(url, function(req){	
			if(feature.previousValue >= 0 && selectedValue >= 0){
			}else{
//				this.showSessionScore(selectedValue);
			}
			callback(req);
		}.bind(this));				
	},


	showSessionScore: function(currentValue){
		var total = $("totalCompleted").innerHTML;
		if(!total){
			total = 0;
		}else{
			total = parseInt($("totalCompleted").innerHTML);
		}
		if(currentValue < 0){
			total--;
			total = Math.max(0, total);
		}else{
			total++;
		}
		$("totalCompleted").innerHTML = total;
	},
	



	imageChanged: function(imageId){

		this.touched = false;
		this.imageId = imageId;		

		if(!onlyRating){
			this.resetAllFeatures();
			this.tagsPresetValue(); //reset
		}
		this.recordId = storage.getCurrentRecordId();
		this.reloadStars();

		//Load previous information
		//(i.e. if they existed previously, or when navigating previous/next)
		if(this.recordId && !onlyRating){
			this.presetFeatureValues(this.recordId);
		}
	},

	itemSaved: function(recordId, goNext){
		this.recordId = recordId;
		//Set the record id on storage for the current image
		storage.setCurrentImageRecordId(recordId);
		//update the url
		this.stars.options.actionURL = this.getStarsActionUrl();
		this.handleSaveIndicator();

		if(goNext == true){
			imageControl.nextImage();
		}
	},

	reloadStars: function(val){

		$("stars").innerHTML = "";
		var that = this;
		if(!val){
			val = 0.0;
		}
		this.stars  = new Stars({
			maxRating: 5,
			container:'stars',
			imagePath: 'img/stars/',
			value: val,
			actionURL: that.getStarsActionUrl(),
			onclick: function(star){
				//If the feauture is being saved, let it finish
				//so we will have recordId
				if(that.touched && !that.recordId){
					that.stars.options.actionURL = '';
					star.value = -1;
					star._starClear(null);
					alert('Still saving the previous item. Please wait a few seconds and try again...');
				}
				that.touched = true;
			},
			callback: function(req){
				var msg =  myreq.getCompletedText(req);
				if(myreq.isError(req) || myreq.isNotice(req)){
					alert(msg);
				}else{				
					//that.stars.locked = true;
					that.recordId = msg;

					//In the index page, stars progress to a new image
					if(app.isIndexPage){
						that.itemSaved(that.recordId, true);
					}else{
						that.itemSaved(that.recordId);
					}
				}
			}
		});
	},		
	getStarsActionUrl: function(){
		var url  = '';
		url += 'ajax/save.php?image_id='+this.imageId;

		if(this.recordId){
			url += '&record_id='+this.recordId;
		}
		url += '&rating='
		
		return url;
	},

	loadFeaturesArray: function(callback){
		var url="ajax/features.php";
		myreq.httpQuery(url, function(req){
			if(myreq.isError(req) || myreq.isNotice(req)){
				alert(msg);
			}else{				
				var xml = req.responseXML;	
				var nodes = xml.getElementsByTagName("feature");

				this.featuresArray = [];
				for(var i=0; i< nodes.length; i++){
					var ft = nodes[i];

					var featureId = myutils.getXmlNodeValue(ft, "feature_id");
					var name = myutils.getXmlNodeValue(ft, "name");
					var imgName = myutils.getXmlNodeValue(ft, "img_name");
					var parentId = myutils.getXmlNodeValue(ft, "parent_id");
					var advanced = myutils.getXmlNodeValue(ft, "advanced");
					if(!parentId){
						parentId="0";
					}
					if(advanced && advanced =="1"){
						advanced = true;
					}else{
						advanced = false;
					}
					this.featuresArray.push(new Feature(featureId, name, imgName, parentId,advanced));
				}
				callback(req);
			}						
		}.bind(this));					

	},

	getFeatureObj: function (featureId){
              if(!this.featuresArray){
                     alert("Features don't exist");
                     return;
              }
		var obj = null;
              this.featuresArray.each( function(ft){
			if(ft.featureId == featureId){
				obj = ft;
			}
              });

		return obj;
	},

	//Retrieves the info from the database for a given recordId anr
	//repopulates the buttons
	presetFeatureValues: function(recordId, callback){
		if(!this.featuresArray){
			alert("Features don't exist");
			return;
		}

		if(!recordId){
			alert("No record ID");
			return;
		}

		var url = "ajax/get_image_record_info.php?record_id="+recordId;
		myreq.httpQuery(url, function(req){
			var msg =  myreq.getCompletedText(req);
			if(myreq.isError(req) || myreq.isNotice(req)){
				alert(msg);
			}else{
				var items = msg.split("|");
				for(var i=0; i< items.length; i++){
					var featureId = null;
					var featureInfo = items[i].split("=");

					if(featureInfo && featureInfo.length == 2){
						var name = featureInfo[0];
						var value = featureInfo[1];
						var prefix = name.substring(0,1);

						if(prefix == "F"){
							featureId = name.substring(1);
							var ft =  this.getFeatureObj(featureId);
							if(ft){
			                                   ft.featurePresetValue(value);
							}
						}else if(prefix == "R"){
							this.reloadStars(value);						
						}else if(prefix == "T"){
							this.tagsPresetValue(value);
						}
					}

				}
			}
			if(callback){
				callback();
			}
		}.bind(this));	
	
	},


	prepareFeatureTags: function(){
		this.prevTagsValue = "";
		Event.observe($("featureTags"), 'focus', function(){
			this.prevTagsValue = $F("featureTags");
		}.bind(this));
		//Save the tags on event
		Event.observe($("featureTags"), 'blur', function(){		
			if(this.prevTagsValue != $F("featureTags")){
				this.tagsSave($F("featureTags"),
				function(req){
					var msg =  myreq.getCompletedText(req);
					if(myreq.isError(req) || myreq.isNotice(req)){
						alert(msg);
					}else{
						this.recordId = msg;
						this.itemSaved(this.recordId);
					}
                       	}.bind(this));
			}
		}.bind(this));
	},

	tagsSave: function(tags, callback){
		if(!this.imageId){
			alert("Current Image ID has not been found, please refresh");
			return;
		}
		if(this.touched && !this.recordId){
			alert('Still saving the previous item. Please wait a few seconds and try again...');
			return;
		}

		this.touched = true;
	
		var url = "ajax/save.php";
		url += "?image_id="+this.imageId;
		url += "&tags="+tags+" ";
		if(this.recordId){
			url += "&record_id="+this.recordId;
		}


		myreq.httpQuery(url, function(req){	
			if(callback){
				callback(req);
			}
		}.bind(this));
	},

	tagsPresetValue: function(value){
		if(value){
			$("featureTags").value = value;
		}else{
			$("featureTags").value = "";
		}
	},


	handleSaveIndicator: function(){			
		var eff = new Effect.Appear('savedIndicator', { to: 1,  duration: 0.5  });	
		setTimeout(function(){
			var eff2  = new Effect.Fade('savedIndicator', { to: 0,  duration: 0.5  });
		}, 500);
	}
	

};

var Hint = Class.create();
Hint.prototype = {
	initialize: function(container){
		this.container = container;
		if(this.container){
			this.container.addClassName("hintMain");
		}
		this.total = 0;
	},
	
	show: function(msg, clearAll, effect){
		var divItem = new Element('div', {className: 'hintItem'});		
		var divItemContent = new Element('div');	
		divItemContent.innerHTML = msg + ' &nbsp; &nbsp; &nbsp; &nbsp;';
		this.total++;
		var divClose = new Element('span', {className: 'hintItemClose'});
		divClose.innerHTML = '<a href="javascript:void(0);">Close</a>';
		divItemContent.appendChild(divClose);
		Event.observe(divClose, 'click', function(){
			this.container.removeChild(divItem);
			this.total = Math.min(0, this.total-1);
		}.bind(this));

		if(clearAll){
			this.container.innerHTML = "";
		}		

		divItem.appendChild(divItemContent);
		if(effect){
			new MyProcess(function(){
				divItem.setStyle("display:none");
				this.container.appendChild(divItem);
				new Effect.SlideDown(divItem, {duration:1.5});
				
			}.bind(this),2000);
		}else{
			this.container.appendChild(divItem);
		}
	}, 

	closeAll: function(){
		while ( this.container.childNodes.length >= 1 ){
			this.container.removeChild( this.container.firstChild );
		}
		this.total = 0;
	},

	getTotal: function(){
		return this.total;
	}
};

var Storage = Class.create();
Storage.prototype = {
	initialize: function(size){
		this.imageIdList = []; //(Sorted from the oldest to the most recent)
		this.recordIdList = []; //(Sorted from the oldest to the most recent)
		this.MAX_HISTORY_SIZE = size; //The previous images history 

		this.clear();
	},
	inBound: function(){
		return (this.currentImageIndex >= 0 && this.currentImageIndex  <= this.MAX_HISTORY_SIZE - 1);
	},

	previous: function(){		
		if(!this.beginningReached() && this.inBound()){
			this.currentImageIndex--;
		}else{
			alert("Cannot proceed, out of bounds!");
		}		

//		this.showContent();
	},

	next: function(){		
		if(!this.endReached() && this.inBound()){
			this.currentImageIndex++;
		}else{
			alert("Cannot proceed, out of bounds!");
		}

//		this.showContent();
	},


	addImage: function(imageId){
		if(!imageId){
			return;
		}
		//Shift all elements by one to the left
		for(var i=0; i< this.MAX_HISTORY_SIZE-1; i++){
			this.imageIdList[i] = this.imageIdList[i+1];
			this.recordIdList[i] = this.recordIdList[i+1];
		}
		this.minIndexReached = Math.max(this.minIndexReached - 1, 0);

		this.imageIdList[this.MAX_HISTORY_SIZE-1] = imageId;
		this.recordIdList[this.MAX_HISTORY_SIZE-1] = null;
//		this.showContent();
	},
	
	beginningReached: function(){
		return(this.currentImageIndex <= this.minIndexReached || this.currentImageIndex <= 0)
	},

	endReached: function(){
		return (this.currentImageIndex >= this.MAX_HISTORY_SIZE - 1);
	},

	
	getCurrentImageId: function(){
		return this.imageIdList[this.currentImageIndex];
	},

	getCurrentRecordId: function(){
		return this.recordIdList[this.currentImageIndex];
	},
	setCurrentImageRecordId: function(recordId){
		this.recordIdList[this.currentImageIndex] = recordId;
	},

	imageAvailable: function(){
		if(this.inBound()){
			if(this.imageIdList[this.currentImageIndex] != null){
				return true;
			}
		}
		return false;
	},


	showContent: function(){
		$("log"). innerHTML += "Image ID List: "+ this.imageIdList +"\n<br>"+
			"\nRecord ID List: "+ this.recordIdList+"\n<br>";

	},

	clear: function(){
		this.currentImageIndex = this.MAX_HISTORY_SIZE - 1;
		this.minIndexReached= this.MAX_HISTORY_SIZE;
		for(var i=0; i< this.MAX_HISTORY_SIZE; i++){
			this.imageIdList[i] = null;
			this.recordIdList[i] = null;
		}

	}

};


var Feature = Class.create();
Feature.prototype = {
	initialize: function(id, name, imgName, parentId, advanced){

		this.featureId = id;		
		this.name = name;
		this.imgName = imgName;
		this.dom = null;		
		this.selectedValue = null;
		this.previousValue = null;
		this.parentId = parentId;
		this.btnArray = null;
	
		this.isHeader = false;		
		if(this.parentId == "0"){
			this.isHeader = true;
		}
		this.advanced = advanced;

		this.createDom();
	},
	
	createDom: function(){
		var div;

		if(this.isHeader){
			div =  new Element("div",{className:"featureCategory"});
			div.innerHTML = '<img src="img/feature_headers/'+this.imgName+'" '+
					      +' alt="'+this.name +'" />';

			div.title = this.name;
			Event.observe(div, "click", this.handleFeatureVisibility.bind(this));
		}else{

			this.imgTestStatus = new Element("img", {className: "featureTestStatus"});
			this.imgTestStatus.src = "img/button_non.gif";
		
			
			var divName = new Element("div");
			divName.addClassName("featureName");
//			if(!this.advanced){
				divName.innerHTML = '<a href="javascript:void(0)" title="Click to see an example">'+this.name+'</a>';
				Event.observe(divName, "click", this.openExample.bind(this));
//			}else{
//				divName.innerHTML = this.name;
//			}



			divMap = new Element("div", {className: "featureMap"});
			divMap.innerHTML = '<a href="javascript:void(0);">Map</a>';	
			divMap.title = "See Map Coverage";
			Event.observe(divMap, "click", this.openMap.bind(this));


			var divControl = new Element("div", {className: "featureControl"});

			var btnYes = new Element("div", {className: "featureBtn"});
			btnYes.optValue = 1;
			btnYes.innerHTML = "Yes";
		
			var btnNo = new Element("div" , {className: "featureBtn"});
			btnNo.optValue = 0;
			btnNo.innerHTML = "No";
		
			var btnNotSure = new Element("div" , {className: "featureBtn"});
			btnNotSure.optValue = 2;
			btnNotSure.innerHTML = "Not Sure";

			this.btnArray = [btnYes, btnNo, btnNotSure];


			this.assignEventHandlers();


			div =  new Element("div",{className:"feature"});
			if(this.advanced){
				div.addClassName("hidden");
			}

			divControl.appendChild(btnYes);
			divControl.appendChild(btnNo);
			divControl.appendChild(btnNotSure);

			var imgBackground =  new Element("img", {className: "featureBackground"});
			imgBackground.src = 'img/feature_headers/field_fill.gif';

			var imgBottom =  new Element("img", {className: "featureBottom"});
			imgBottom.src = 'img/feature_headers/field_bottom.gif';

			div.appendChild(this.imgTestStatus);
			div.appendChild(divName);
			div.appendChild(divMap);

			div.appendChild(divControl);
			div.appendChild(imgBackground);
			div.appendChild(imgBottom);
		}

		this.dom = div;
	},

	getFeatureHtml: function(){
		return this.dom;
	},


	buttonify: function(divBtn ,onClickHandler){

		var that = this;
		Event.observe(divBtn, 'mouseover',  function(){
			Element.addClassName(this,"featureBtnOver");
		});
		Event.observe(divBtn, 'mouseout', function(){
			Element.removeClassName(this,"featureBtnOver");
		});

		Event.observe(divBtn, 'click', function(){			
			var value;
			if(that.selectedValue == this.optValue){
				//unselect
				value = that.selectButtonAndReturnValue(null);
			}else{
				//select
				value  = that.selectButtonAndReturnValue(this);
			}
			Element.removeClassName(this,"featureBtnOver");
			if(onClickHandler){											
				onClickHandler(value);
			}
		});
	},
	assignEventHandlers: function(){
		if(!this.isHeader){
			this.buttonifyArray( function(value){
				//-1 is considered as deletion
				this.featureCompleted( value);
			}.bind(this));
		}
	},

	buttonifyArray: function(onClickHandler){
		var that = this;
		this.btnArray.each( function(btn){
			that.buttonify(btn, onClickHandler);
		});
	},

	selectButtonAndReturnValue: function(selBtn){
		var value;
		if(selBtn && selBtn.optValue != null){
			value = selBtn.optValue;
		}else{
			value = -1;
		}
		if(!this.selectButton(value)){
			value = -1;
		}

		return value;
	},

	featureCompleted: function(value){
		this.previousValue = this.selectedValue;
		this.selectedValue = value;		

		//Custom event
		if(this.onCompleteFunction){
			
			this.onCompleteFunction(this,
						   this.featureId, 
						   this.selectedValue, 
						   this.onCompleteFunctionCallback);

		}else{
			alert("Nothing to do...");
		}

	},
	
	featureReset: function(){		
		if(!this.isHeader){
			this.previousValue = this.selectedValue;
	              this.selectedValue = this.selectButtonAndReturnValue(null);

			this.testReset();
		}
	},
	selectButton: function(value){
		var fixed = false;
		this.btnArray.each( function(btn){
			if(value == btn.optValue){
				fixed = true;
				Element.addClassName(btn, "featureBtnFixed");
			}else{
				Element.removeClassName(btn, "featureBtnFixed");
			}
		});
		return fixed;
	},

	getSelectedButton: function(value){
		var b = null;
		this.btnArray.each( function(btn){
			if(value == btn.optValue){
				b = btn;
			}
		});
		return b;
	},
	

	featurePresetValue: function(value){
		if(!this.isHeader){
			this.previousValue = null;
			this.selectedValue = value;				
			this.selectButton(this.selectedValue);
		}
	},
	
	setOnCompleteFunction: function(func, callback){
		this.onCompleteFunction = func;
		this.onCompleteFunctionCallback = callback;
	},


	handleFeatureVisibility: function(){
		featureIdentification.featuresArray.each(function(ft){
			if(ft.parentId == this.featureId){
				if(ft.dom.hasClassName("hidden")){
					ft.dom.removeClassName("hidden");

					//Handle tags field
					if(ft.advanced){
						$("divFeatureTags").removeClassName("hidden");	
					}
				}else{
					ft.dom.addClassName("hidden");
					//Handle tags field
					if(ft.advanced){
						$("divFeatureTags").addClassName("hidden");	
					}

				}
			}
		}.bind(this));
	},


	openExample: function(){
		$("exIframe").src = "example.php?feature_id="+this.featureId;		
		gui.winOpen($("winExample"));
	},

	openMap: function(){
		new MyProcess(function(){
			var parentFeature = featureIdentification.getFeatureObj(this.parentId);
			var label = "";
			if(parentFeature){
				label += parentFeature.name + " - ";
			}			
			label += this.name;
			$("mapFeature").innerHTML = label;
			$("mapImage").removeClassName("hidden");
			gui.winOpen($("winMap"));
		}.bind(this));

		new MyProcess(function(){
			$("mapImage").opened = 1;
			$("mapImage").src = "maps/get_map.php?feature_id="+this.featureId;
			
		}.bind(this));
	},


	testSucceeded: function(correctAnswer){
//		this.testReset();
		this.imgTestStatus.src= "img/button_correct.gif";
//		var btn = this.getSelectedButton(correctAnswer);
//		btn.addClassName("featureTestSucceeded");
	},

	testFailed: function(correctAnswer){
//		this.testReset();
		this.imgTestStatus.src = "img/button_incorrect.gif";
//		var btn = this.getSelectedButton(correctAnswer);
//		btn.addClassName("featureTestFailed");
	},
	testReset: function(){
		this.imgTestStatus.src = "img/button_non.gif";
//		this.btnArray.each( function(btn){
//			btn.removeClassName("featureTestSucceeded");
//			btn.removeClassName("featureTestFailed");
//		});
	}



};



var MyRequest = Class.create();
MyRequest.prototype = {

	initialize: function(){

	},


	/*****************************************************************************
	* Does a typicall Ajax query  and returns the response object
	* @param httpQuery - is the query is the path to serverside file 	  
	* @param callBack - a reference to the function to be called as callback
	*****************************************************************************/

	httpQuery:function(httpQuery, callBack, noLoading){
		var params;
		var loc;
		var params;
		var loc;

		//split the parameters and the real location
		var qstIndex =  httpQuery.indexOf("?");	
		if(qstIndex != -1){
			loc  = httpQuery.substring(0,qstIndex);
			params = httpQuery.substring(qstIndex+1, httpQuery.length);
		}else{
			loc  = httpQuery;
  			params = "";
		}
	

		//Remove the trailing whitespace from each field	
		var paramsHash = $H(params.toQueryParams());
		paramsHash.each(function(pair){
			var key = pair[0];
			var value = pair[1];
			if(!value)
				this[key] ="";
			else
				this[key] = value.strip();
		}.bind(paramsHash));
		params = paramsHash.toQueryString();
		//End of trail removal

		if(!noLoading){
			if($("loadingSemaphore")){
				$("loadingSemaphore").removeClassName("hidden");
			}
		}
		new Ajax.Request(loc,{
 	      	      	evalScripts:true,
			asynchronous:true,
			parameters: params,
        	        method: 'post',
			//Parse the XML and populate the menu list if succeeded
			onComplete: function(req){
				//Normalize the data if the XML is very big, since some 
				//browsers dont' handle it.
				if(req.responseXML && req.responseXML.normalize)
					req.responseXML.normalize();
				if(!noLoading &&  $("loadingSemaphore")){
					$("loadingSemaphore").addClassName("hidden");
				}
				callBack(req);
			}

		});
		
	},

	//Return the current response of the http request
	getResponse: function(obj){
		var status = "";
		if(!obj){
			status = "Problem";
		}else if(obj.readyState == 0){
			status =  "Sending";
		}else if(obj.readyState == 1){
			status = "Loading";
		}else if(obj.readyState == 2){
			status = "Loaded";
		}else if(obj.readyState == 3){
			status = "XML Ready";
		}else if(obj.readyState == 4){
			if(obj.status == 200){
				var str = obj.responseText;
				if (str.match(/^ERROR:/i)) {
					status = str;
				}else if (str.match(/Parse error/i)) {
					status = str;
				}else if (str.match(/^NOTICE:/i)) {
					status = str;
				}else{
				  status = "OK";
				}
			 }else if(obj.status == 404){
				status = "Not Found";
		 	}else{
				status = "Problem: #"+obj.status;
		 	}
		}
		return status;
	},

	//Returns true if the response was OK
	isSuccess: function(req){
		var str = this.getResponse(req);
		if (str.match(/^OK$/i)) {					
			return true;
		}else{
			return false;
		}
	},	

	//Returns true if the response was just a mesage
	isNotice: function(req){
		var str = this.getResponse(req);
		if (str.match(/^NOTICE:/i)) {					
			return true;
		}else{
			return false;
		}
	},
	//Returns true if the response was just a mesage
	isError: function(req){
		var str = this.getResponse(req);
		if (str.match(/^ERROR:/i)) {					
			return true;
		}else{
			return false;
		}
	},
	getCompletedText: function(req){
		var str = req.responseText;

		var str;
		m  = str.match(/^NOTICE:(.*)/i);
		if(!m)
			m  = str.match(/^ERROR:(.*)/i);
		if(!m)
			m  = str.match(/^DONE:(.*)/i);

		if (m)
			return m[1];		
		else
			return this.getResponse(req);
	}
};

var Gui = Class.create();

Gui.prototype = {
	initialize:function(){

	},


	//Opens a nested window with the window (div) passed as argument
	winOpen: function(win){
		if(app.isFeaturePage || app.isIndexPage){
			if(navigator.userAgent.indexOf("Firefox") >= 0  && zoomifier.dom){
				zoomifier.dom.style.visibility = "hidden";
			}
			//hack for div on top of flash
			$("zoomifierIframe").style.display="block";
		}

		//load the win into the window
		$("windowContainer").appendChild(win);

		//show the nested window

		var h = myutils.getPageSize()[1];

		if(h){
			$("windowWrapper").setStyle("height:"+h+"px");
		}

		Element.removeClassName($("windowWrapper"), "hidden");
		Element.removeClassName(win, "hidden");


		


	},
	
	//Closes all the app windows 
	winClose: function(){
		//hide  the nested window
		Element.addClassName($("windowWrapper"), "hidden");

		//Select all the windows inside the windowContainer
		var wins = $A($("windowContainer").getElementsByClassName("window"));
		//Hide all the windows
		wins.each(function(win){
			Element.addClassName(win, "hidden");

		});

		if(app.isFeaturePage || app.isIndexPage){
			if(navigator.userAgent.indexOf("Firefox") >= 0  && zoomifier.dom){
				zoomifier.dom.style.visibility = "visible";
			}
			//remove hack for div on top of flash		
			$("zoomifierIframe").style.display="none";
		}
	},

	isWinOpen: function(win){
		if( !$("windowWrapper")  || !win){
			alert("Window does not exist");
			return false;
		}

		if( $("windowWrapper").hasClassName("hidden") && win.hasClassName("hidden")){
			return false;
		}else{
			return true;
		}		
	}
}

var MyUtils = Class.create();
MyUtils.prototype = {

	initialize: function(){

	},
	
	//Returns the node value by giving the parentNode and nodeName
	//This assumes that there is only one nodeName under parentNode
	//i.e. func.getXmlValue(markerNode, "name") returns xxx
	//<marker>
	//<name>xxx</name>
	//<address>yyy</address>
	//</marker>
	
	getXmlNodeValue: function(parentNode, nodeName){
		var node =  parentNode.getElementsByTagName(nodeName);
		var value = "";
		if(node && node.length > 0 ){
			node = node[0];
			if(node.firstChild){				
				value = node.firstChild.nodeValue;
				value=value.replace(/\n/g,"<br>"); 
			}
		} 
		return value;
	},


	setPageScrollHeight: function(value)
	{	
		if(document.documentElement != null && document.documentElement.scrollTop != null){
			document.documentElement.scrollTop = value;
		}else if(document.body.scrollTop != null){
			document.body.scrollTop = value;
		}else if(window.pageYOffset != null){
			window.pageYOffset = value;
		}

	},

	getPageSize: function(){

		var xScroll, yScroll;

		if (window.innerHeight && window.scrollMaxY) { 
			xScroll = document.body.scrollWidth;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else if (document.documentElement && document.documentElement.scrollHeight > document.documentElement.offsetHeight){ // Explorer 6 strict mode
			xScroll = document.documentElement.scrollWidth;
			yScroll = document.documentElement.scrollHeight;
		} else { // Explorer Mac...would also work in Mozilla and Safari
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}

		var windowWidth, windowHeight;
		if (self.innerHeight) { // all except Explorer
			windowWidth = self.innerWidth;
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		} 

		// for small pages with total height less then height of the viewport
		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		} else { 
			pageHeight = yScroll;
		}

		// for small pages with total width less then width of the viewport
		if(xScroll < windowWidth){ 
			pageWidth = windowWidth;
		} else {
		pageWidth = xScroll;
		}


		arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight) 
		return arrayPageSize;
	}

};


// This class is an emulation of the process. In a multithreaded fashion.
var MyProcess = Class.create();
MyProcess.prototype = {
	initialize: function(arg, time){
		if(!time){
			time = 0;
		}
		setTimeout(arg, time);
	}
};




var Closeable = Class.create();
Closeable.prototype = {
	initialize : function(parent, callback) {
		this.parent = parent;		
		this.callback = callback;

		this.trigs = Array();
		this.targs = Array();
		this.actuators = Array();

		this.trigs = this.childrenWith(parent, "ClTrig");

		for(var i=0; i< this.trigs.length; i++){
			this.actuators[i] = this.trigs[i].getElementsByTagName("input")[0];		
			if(this.actuators[i].type == "checkbox"){
				this.targs[i] = this.childrenWith(parent, "ClTarg");
			}else{
				this.targs[i] = document.getElementsByClassName(this.actuators[i].value);
			}
			Event.observe(this.trigs[i], "click", this.update.bindAsEventListener(this));
		}
		this.update(null);
	},

	update : function(e) {
		var c = 0;

		if(this.trigs.length == 1){
			if (this.actuators[0].checked) {			
				this.parent.addClassName("optopen");
				this.targs[0][0].removeClassName("closed");
			} else {				
				this.parent.removeClassName("optopen");
				this.targs[0][0].addClassName("closed");
			}

		}else {
			this.parent.removeClassName("optopen");
			for(var i=0; i<this.trigs.length; i++){				
				if(this.targs[i]){
				  for(var j=0; j<this.targs[i].length; j++){
					if(this.targs[i][j]){
						this.targs[i][j].addClassName("closed");
					}
				  }
				}
			}
			for(var i=0; i<this.trigs.length; i++){
				for(var j=0; j<this.targs[i].length; j++){
					if(this.targs[i]){
					 if(this.actuators[i].checked && this.targs[i] && this.targs[i][j]){
						this.parent.addClassName("optopen");
						this.targs[i][j].removeClassName("closed")
						c = i;
					 }
					}
				}
			}			
		}
		// var $content = $("outer").innerHTML;
		// $("outer").innerHTML = $content;
		// if ($blah) alert($content);
		if(this.callback){
			this.callback(this.actuators[c]);

		}

	},

	// fixes for broken scriptaculous functions
	// (childrenWith at least is fixed in latest version, not part of jslib)
	childrenWith : function(element, className) {

		var children = $(element).getElementsByTagName('*');
		var elements = new Array();
	
		for (var i = 0; i < children.length; i++) {
					
			if (Element.hasClassName(children[i],className)){
				elements.push(children[i]);
			}
		}
		return elements;
	}

}








var zoomifier;
var imageControl;
var featureIdentification;
var storage;
var hint;

var app = new App();
var myreq = new MyRequest();
var myutils = new MyUtils();
var gui = new Gui();


Event.observe(window, "load", app.initApp.bind(app))
Event.observe(window, "unload", app.deinitApp.bind(app))
//document.observe("contentloaded", app.initApp)

