		
	
			dojo.require("dojo.io.*");
			dojo.require("dojo.xml.Parse");
			dojo.require("dojo.widget.Dialog");
			dojo.require("dojo.widget.DatePicker");
			dojo.require("dojo.event.common");
			
//constructor
var dataBuild = function() {	
		this.map;
		this.arg;			
}

dataBuild.global = function(){
	return  {
		mapcontrol: new GSmallMapControl(),
		interval: null,
		count: 0
	};	
}();

/**
 *
 * @widgetId
 * just so that i dont have to redeclare local var everytime
 *
 **/	
			dataBuild.widgetId = function(el){
				return dojo.widget.byId(el);	
			};

/**
 *
 * @cookieHandler
 * handle cookie
 *
 **/	
			dataBuild.cookieHandler = new function(){
				this.ck = dojo.io.cookie;	
			};

/**
 *
 * @currentView
 * keeping track of current view / view controller
 *
 **/	
			dataBuild.prototype.currentView = function(view){
				this.cleanup();
				dataBuild.widgetId('loading').show();
				
				this.cView = view; //default current view is storyteller
				var sv = document.getElementById('mapMenu_story');
				var mv = document.getElementById('mapMenu_marker');
							
				if(this.cView == 'storyTeller'){
					dataBuild.global.count = '0';
					dojo.html.removeClass(mv, 'selected');	
					dojo.html.addClass(sv, "selected");
					this.map.removeControl(dataBuild.global.mapcontrol);
					this.map.disableDragging();
				} else {
					dataBuild.loadStatus('Plotting markers...');													
					window.setTimeout("dataBuild.loadStatus('Displaying data')", 600);
					dojo.html.removeClass(sv, 'selected');					
					dojo.html.addClass(mv, "selected");
					this.map.addControl(dataBuild.global.mapcontrol);				
					this.map.enableDragging();
				}				
			};
			
/**
 *
 * @status text
 * better UX experience if it is not 'loading' all the time
 *
 **/	
			dataBuild.loadStatus = function(text){
				var st = document.getElementById('loadStatus');
				st.innerHTML = text;	
			};

/**
 *
 * @init
 * uhm...everything starts here.
 *
 **/					
			dataBuild.prototype.init = function(){
				 
				 dataBuild.widgetId('loading').show(); 
			 	 this.map = new GMap2(document.getElementById("map"));
			 	 this.map.setCenter(new GLatLng(41, -81), 3);
			 	 this.map.disableDragging();
			 
			     //dataBuild.cookieHandler['ck'].deleteCookie("trackfeeling");
			     
			     window.setTimeout("dataBuild.loadStatus('Preparing interface')", 800);
			 	 //start engine only if Gmap is loaded. Smoother transition.
			 	 if(this.map.isLoaded()){
					var args = new dataBuild.getArgs();
					this.permalinkEngine(args);
				 }
			 			 	
				 dojo.event.connect(['input_date'], 'onfocus', dataBuild.datePicker);
			 	 dojo.event.connect(['feeling_id'], 'onfocus', dataBuild.suggestFeeling);
			 					
			};

/**
 *
 * @dataBuild.getArgs
 * URL parser
 *
 **/			
			dataBuild.getArgs = function(str) {
			    var args = new Object();
			    var query = str || location.search.substring(1);     // Get query string
			    var pairs = query.split("&");                 // Break at ampersand
			    for(var i = 0; i < pairs.length; i++) {
			        var pos = pairs[i].indexOf('=');          // Look for "name=value"
			        if (pos == -1) continue;                  // If not found, skip ARGH!!!
			        var argname = pairs[i].substring(0,pos);  // Extract the name
			        var value = pairs[i].substring(pos+1);    // Extract the value
			        value = decodeURIComponent(value);        // Decode it, if needed
			        args[argname] = value;                    // Store as a property
			    }
			    return args;                                  // Return the object
			};

/**
 *
 * @dataBuild.prototype.permalinkEngine
 * URL analyzer
 *
 **/
			dataBuild.prototype.permalinkEngine = function(val){
				var feeling = val.feeling || ''; 	//have feeling?
				var gender = val.gender || ''; //have gender?
				var postdate = val.postdate || ''; //have date?
				
				document.getElementById('feeling_id').value = feeling;
				document.getElementById('input_date').value = postdate;
				
				if(feeling != ''){
					feeling = 'feeling='+val.feeling;
				}
				if(gender != ''){
					gender = '&gender='+val.gender;
				}
				if(postdate != ''){
					postdate = '&postdate='+val.postdate; 
				}
				
				this.arg = "feel.php?"
				this.arg += feeling+gender+postdate;
				
				this.xmlhttp(this.arg);
				
			};
			
/**
 *
 * @dataBuild.datePicker
 * just a date picker
 *
 **/
			dataBuild.datePicker = function(evt){
				var formDp, dpInput, dp;
				dpInput = dojo.byId('input_date');
				var currDate = (dpInput.value != '' ? dpInput.value : new Date());	
				formDp = dojo.widget.createWidget("DatePicker", {value:currDate,adjustWeeks:'true', templateCssPath: dojo.uri.dojoUri("src/widget/templates/DatePicker1.css")}, dojo.byId("dpNode")); 
				dojo.event.browser.stopEvent(evt);
				
				dojo.event.connect(formDp,'onValueChanged',function(){
					dpInput.value = formDp.getValue();	
					formDp.hide();
				});
				
				//why do we need to attach 3 events to accomplish such simple things @_@
				dojo.event.connect(['input_date'], 'onfocus', function(evt){formDp.show();dojo.event.browser.stopEvent(evt);});				
				dojo.event.connect(['input_date'], 'onclick', function(evt){formDp.show();dojo.event.browser.stopEvent(evt);});				
				dojo.event.connect(window, 'onclick', function(){formDp.hide();});				
			};
			
/**
 *
 * @suggestFeeling
 * suggest valid feeling in the 'feeling' form field
 *
 **/
			dataBuild.suggestFeeling = function(evt){
				
				var formFeel = document.getElementById('feeling_id');
				var chart = document.getElementById('colorChart');
				var LI = chart.getElementsByTagName('li');		
				var upVal = 1, curr = 0;
				formFeel.select();
				
			
				
				dojo.event.connect(formFeel, 'onkeyup', function(evt){
					
					if(evt.keyCode == 38){
						if(upVal < LI.length+1){
							chart.style.display = 'block';
							dojo.html.addClass(chart, "select_show");
							dojo.html.removeClass(LI[curr], "SR_selected");
							dojo.html.addClass(LI[LI.length-upVal], "SR_selected");	
							curr = LI.length-upVal;
							formFeel.value = LI[curr].childNodes[0].nodeValue;	
							upVal++;	
						} 				
					} else if(evt.keyCode == 40){ 
						if(curr < LI.length-1 && chart.className == 'select_show'){
							dojo.html.removeClass(LI[curr], "SR_selected");
							upVal=upVal-1;
							dojo.html.addClass(LI[LI.length-(upVal-1)], "SR_selected");	
							curr = LI.length-(upVal-1);
							formFeel.value = LI[curr].childNodes[0].nodeValue;	
						} else {				
							formFeel.select();
							upVal = 1;
							curr = 0;
							dojo.html.removeClass(chart, "select_show");
							chart.style.display = 'none';				
						}						
					} else if(evt.keyCode == 13){			
						upVal = 1;
						curr = 0;
						dojo.html.removeClass(chart, "select_show");		
						chart.style.display = 'none';			
					} else {			
						var str = formFeel.value;
						var url_q = "colorSearch.php";
						url_q = url_q + "?q="+str;
												
						if(str.length>2){							
							chart.style.display = 'block';
							dojo.io.bind({
								url: url_q,
								mimetype: "text/plain",
								preventCache: false,
								load: function(type, data, e) {
									if(data){
										var chart = document.getElementById('colorChart');
										chart.innerHTML = data;
										dojo.event.connect(['colorChart li'], 'onclick', 
										 	function(){
												chart.style.display = 'none';
											}
										);
									}	 	 	
								},
								error: function(type, error){ alert(error); }
							});
						} else {
							chart.style.display = 'none';
						}
					}
				});
			};

/**
 *
 * @xmlhttp
 * set up xmlhttp request tunnel to grab initial data.
 * this function only runs once until we run out of 'feelings'
 *
 **/				
			dataBuild.prototype.xmlhttp = function(url){			
					url = (url == null ? 'feel.php' : url);				
					var _this = this;
					dojo.io.bind({
						url: url,
						mimetype: "text/xml",
						load: dojo.lang.hitch(_this, function(type, xml, e) {		
				 	 		dataBuild.widgetId('loading').hide();
				 	 		window.clearInterval(dataBuild.global.interval);
				 	 		dataBuild.global.count = 0;
											
							var xmlRoot = xml.getElementsByTagName('feelings')[0];	
							
                            var feeling = xmlRoot.getElementsByTagName('feeling');
							var res = document.getElementById('result');
							var noresult = dojo.widget.byId("message");	
																	
							var feelArray = []; 
							
							for(var i=0, feel; feel=feeling[i]; ++i){	
								feelArray.push(i);									
							}							
							
							if(feelArray.length > 0){
								this.splashMenu(feeling, feelArray);
							} else {
								noresult.show();
							}					
							
							//res.innerHTML = new Date() - t1;						
						
						}),
											
						error: function(type, error){ alert(error); },
						timeoutSeconds: 20,
						timeout: function(type, data, evt){
							dataBuild.widgetId('loading').hide();
							dojo.widget.byId("message").show();
						}
				  });
			};



/**
 *
 * @splashMenu
 * result menu
 *
 **/	
			dataBuild.prototype.splashMenu = function(x,y){
					var _this = this;
					var ulNav = document.getElementById('statNavigation');
					var clickVal =  dataBuild.cookieHandler['ck'].getCookie("trackfeeling_click");
					if(clickVal == 'story'){
						ulNav.style.display = 'none';
						dataBuild.widgetId('stat').lifetime = 2000;
						
						this.currentView('storyTeller');
					//	this.map.setCenter(new GLatLng(0,0), 3);	
					//	this.map.panTo(new GLatLng(41, -81));
						//GEvent.bind(this.map,"moveend", dataBuild.prototype, function() {
							_this.displayFeel(x,y);		
						//});
					} else if(clickVal == 'marker'){
						ulNav.style.display = 'none';
						dataBuild.widgetId('stat').lifetime = 2000;
						
						this.currentView('mOverload');
						//this.map.setCenter(new GLatLng(0,0), 3);	
						//this.map.panTo(new GLatLng(41, -81));						
						//GEvent.bind(this.map,"moveend", dataBuild.prototype, function() {
							_this.marker(x,y);
						//});
					} 
						var dl = document.getElementById('data_length');	
						var fel = document.getElementById('feeling_id');
						//first time visitor widget message
						dl.innerHTML = x.length+' '+fel.value;						
					 
					dataBuild.widgetId('stat').show(); 
					dataBuild.cookieHandler['ck'].setCookie("trackfeeling", "yes", 7);
				 	
					
					dojo.event.connect(['storyteller_but','sT','mapMenu_story'], 'onclick', dojo.lang.hitch(_this, function(){
						this.currentView('storyTeller');											
						//this.map.setCenter(new GLatLng(0,0), 3);	
						//this.map.panTo(new GLatLng(41, -81));
						//GEvent.addListener(this.map,"moveend", dojo.lang.hitch(_this, function() {
							this.displayFeel(x, y);			
						//}));
					}));
					
					dojo.event.connect(['marker_but','mO','mapMenu_marker'], 'onclick', dojo.lang.hitch(_this, function(){
						this.currentView('mOverload');
						//this.map.setCenter(new GLatLng(0,0), 3);	
						//this.map.panTo(new GLatLng(41, -81));						
						//GEvent.addListener(this.map,"moveend", dojo.lang.hitch(_this, function() {
							this.marker(x, y);
						//}));
					}));
			};




/**
 *
 * @cleanup
 * it is like a...reset/garbage collection?
 *
 **/	
			dataBuild.prototype.cleanup = function(){
				var topM = document.getElementById('mapMenu');
				window.clearInterval(dataBuild.global.interval);
				GEvent.clearInstanceListeners(this.map);
				this.map.clearOverlays();
				dataBuild.widgetId('stat').hide();	
				topM.style.display="inline";					
			};

/**
 *
 * @marker
 * Set up marker on the map.
 *
 **/	
			dataBuild.prototype.marker = function(xmlNode, selArray){
				
				var _this = this;
				dataBuild.cookieHandler['ck'].setCookie("trackfeeling_click", "marker", -1);
				 		
				var m_display = new dojo.xml.Parse();
				
				dataBuild.global.count = 0;
				var markerThrottle = function(){
					// reach the end of message queue, regenerate.
					if(dataBuild.global.count == selArray.length){
				
					} else {						
						displayNodes = m_display.parseAttributes(xmlNode[selArray[dataBuild.global.count]]);
						_this.engine(displayNodes, 1);										
					}
				};	
			  	
			  	dataBuild.global.interval = window.setInterval(markerThrottle, 300);

								
				dataBuild.widgetId('loading').hide();
						
			};

/**
 *
 * @engine
 * Content building engine. Parsing xml and display then nicely.
 *
 **/			
			dataBuild.prototype.engine = function(d, type){
				
				
				
				//alert(d.state.value);
				var isMarker = type || '';						
				var pointN;
				var t = d.sentence;				
				var stateN = d.state;				
				var countryN = d.country;
				var placeN = (stateN == null ? d.country.value : d.state.value+', '+d.country.value );	
				var laT = d.lat;
				var loN = d.lon;
				var geN = d.gender;
				var postdateN = d.postdate;
				var imageid_value = d.imageid.value;
                var imageidN;
				var bornN = d.born;
				var epochN = d.posttime;
				var feelingN = (d.feeling != null ? d.feeling.value : '' );	
				var urlN = d.posturl;
				
				var now = new Date();
				var year  = now.getYear();
				var currentT = Math.round(now.getTime()/1000.0);
				var howlongago = currentT - epochN.value;
				if (howlongago > 60){
					if (howlongago > 3600){
						howlongago = Math.round(howlongago / 3600)+' hours';
					} else {
						howlongago = Math.round(howlongago / 60)+' minutes';					
					}
				} else {
					howlongago = howlongago+' seconds';
				}
				
				//if(laT){
					pointN = new GLatLng(laT.value, loN.value);
					
				/*} else{
					
					var geocoder = new GClientGeocoder();
					var addr = countryN.value;
					
					pointN = function(){
					//try{
						if (geocoder) {
					        geocoder.getLatLng(
					          addr,
					          function(point) {
					              if(point){
					              	return new GLatLng(point);					            
					              } else {
					              	//need to figure out a good way to handle this error,
					              	//obviously no one lives in 0,0
					              	return new GLatLng(41, -81);		
					              }   
					          }
					        );
				      	}	
					//} catch(e){return new GLatLng(0,0);};	
					geocoder.reset();
					};
						
				}*/
				
				var imageSrc = dataBuild.getImgPath(postdateN.value, imageid_value, 'full');
				var imagePrecache = new Image();
				imagePrecache.src = imageSrc;
				
				
				if(year < 2000) { year = year + 1900; }
				bornN = (bornN == null ? '' : year-bornN.value+' years old' );	
				
				imageidN = '<img src="'+imageSrc+'" style="float:left;margin:3px 11px 0 0;" />';			
				
				
				if(geN){
					geN = (geN == 0 ? 'from a '+bornN+' female' : 'from a '+bornN+' male' );						 	
				}
				else if(bornN != ''){								 	
				 	geN = 'from a '+bornN;
				}
				else{
					geN = 'from someone';
				}
				
				var thinkingGif = (isMarker == 1 ? '.' : ' <img src="images/feel-load.gif" />' );
									
				this.map.innerHTML = '<div style="margin:14px 0 0;width:420px;height:220px;overflow:auto;">'+imageidN+'<p style="margin-top:0;"><span class="feeling">'
+t.value+'.</span><span class="mapFrom">'+howlongago+' ago, '+geN+' in '+placeN+''+ thinkingGif +' </span> <a href="'+urlN.value+'" class="sourcelink" target="_blank"> [read more]</a></p></div>'
				
				var content = this.map.innerHTML;
			
				if(isMarker != 1){
					//this.map.panTo(pointN);
				
					//GEvent.bind(this.map,"moveend", dataBuild.prototype, function() {
			    		this.map.openInfoWindowHtml(pointN,content);
			    	//});
			    	
					
				}
				else{
					 
					var gicons = [];
					var markerURL = (feelingN != '' ? 'images/icons/'+fC[feelingN]+'.png' : 'images/icons/unknown.png' );
					   
					gicons[feelingN] = new GIcon(G_DEFAULT_ICON, markerURL);					
					gicons[feelingN].shadow = "images/icons/pin_shadow.png";
					gicons[feelingN].iconSize = new GSize(16, 28);
						
									
					var marker = new GMarker(pointN, {title:t.value, icon:gicons[feelingN]});
					GEvent.addListener(marker, "click", function() {marker.openInfoWindowHtml(content);});
					this.map.addOverlay(marker);		
				}		
				dataBuild.global.count++;				
			};

/**
 *
 * @getImgPath
 * convert imageID to actual image path
 *
 **/			
			dataBuild.getImgPath = function(postdate, imageid, imagesize){
			    var imgpath = "http://images.wefeelfine.org/data/images/";
			    imgpath += postdate.replace(/-/g,'/');
			    imgpath += "/"+imageid;
			    if(imagesize == "thumb") imgpath += "_thumb.jpg";
			    else imgpath += "_full.jpg";
			    return imgpath;
			};
					
/**
 *
 * @displayFeel
 * this is the iterator/controller. Whether we initiate a new ajax call,
 * iterate the existing xml nodes, or alert widget control, it is all here.
 *
 **/				
			
			dataBuild.prototype.displayFeel = function(xmlNode, selArray){		
				
				GEvent.clearInstanceListeners(this.map);
								
				var display = new dojo.xml.Parse();
				var displayNodes = display.parseAttributes(xmlNode[selArray[0]]);
				dataBuild.cookieHandler['ck'].setCookie("trackfeeling_click", "story", -1);
				
				dataBuild.widgetId('loading').hide();
				 		
				this.engine(displayNodes);				
				var _this = this;	
				var displayFeelThrottle = function(){
					// reach the end of message queue, regenerate.
					if(dataBuild.global.count == selArray.length){
						dataBuild.loadStatus('Loading data...');
						window.window.clearInterval(dataBuild.global.interval);
						dataBuild.widgetId('loading').show(); 
						_this.xmlhttp(_this.arg);
					} else {						
						displayNodes = display.parseAttributes(xmlNode[selArray[dataBuild.global.count]]);
						_this.engine(displayNodes);										
					}
				};	
			  	
			  	dataBuild.global.interval = window.setInterval(displayFeelThrottle, 7000);
			   		
			};
			
		 dojo.addOnLoad(function(){
		 	var fire = new dataBuild();
			
		 	fire.init();
			fire.cleanup();
		 });
		 
		 //clean, clear and garbage collection
		 dojo.addOnUnload(GUnload);