view war/scripts/sti/STICore.js @ 87:593cfbd58c3e trimmed_data

CSV conversion: place name, address and descrption in CDATA blocks (prevents bugs with special characters as < etc.)
author Sebastian Kruse <skruse@mpiwg-berlin.mpg.de>
date Thu, 07 Mar 2013 14:56:13 +0100
parents ed444173aef0
children
line wrap: on
line source

/**
 * defines the core component of the Spatio Temporal Interface
 * 
 * @constructor
 */
function STICore(){

    this.map;
    this.timeplot;
    
    this.refining;
    this.individualDataSet;
    
    this.takeTime;
    
    this.history;
    this.historyIndex;
    this.lockScreenContainer;
    
    this.initialize();
	this.blocked = false;
    
};

STICore.prototype = {

	blockUI: function(){
		this.blocked = true;
		fullscreen.addFullscreen(fullscreen.loaderContent());
	},

	unblockUI: function(){
		this.blocked = false;
		setTimeout( function(){ if( !this.blocked ){ setDefinedBounds(); } }, 150 );
		fullscreen.removeFullscreen();
	},

	/**
	 * refines the given data by creating a new history entry
	 */
	refine: function(){
            if (this.refining > -2) {
            	var contains = false;
				var newDataSets = [];
				var oldDataSets = this.history[this.historyIndex].dataSets;
            	for (var i = 0; i < oldDataSets.length; i++) {
					var dataSet = oldDataSets[i].copy();
					dataSet.source = oldDataSets[i].source;
                	for (var j = 0; j < oldDataSets[i].objects.length; j++) {
                    	if ( oldDataSets[i].objects[j].percentage == 1 || this.refining > -1 && this.refining != i ){
							dataSet.addObject( oldDataSets[i].objects[j] );
                        	contains = true;
						}
                	}
					newDataSets.push(dataSet);
            	}
            	if (contains) {
           			this.addHistoryEntry( new HistoryEntry(newDataSets) );
                    this.reset();
                    this.initElements();
                }
                else {
                    alert("Your Selection contains no elements!");
                }
            }
            else {
                alert("For Refining choose an Area on the map or a Range on the Timeplot!");
			}
			return -1;
	},
	
	/**
	 * refines the given data by creating a new history entry
	 */
	refineByTime: function(minTime,maxTime){
		var minDate = new Date(parseInt(minTime));
		var maxDate = new Date(parseInt(maxTime));
		if( this.timeplot.eds.minDate.getTime() == minDate.getTime() &&
				this.timeplot.eds.maxDate.getTime() == maxDate.getTime() ){
			return;
		}
		var newDataSets = [];
		var oldDataSets = this.history[this.historyIndex].dataSets;
       	for (var i = 0; i < oldDataSets.length; i++) {
			var dataSet = oldDataSets[i].copy();
			dataSet.source = oldDataSets[i].source;
           	for (var j = 0; j < oldDataSets[i].objects.length; j++) {
           		var o = oldDataSets[i].objects[j];
           		if( o.inTime(minDate,maxDate) ){
					dataSet.addObject( o );
           		}
           	}
			newDataSets.push(dataSet);
       	}
		this.addHistoryEntry( new HistoryEntry(newDataSets) );
		this.reset();
		this.initElements();
	},

	/**
	 * refines a given dataset by a given text snippet
	 */
	refineByText: function(text,index){
		this.reset();
		var dataset = this.history[this.historyIndex].dataSets[index];
       	for (var i = 0; i < dataset.objects.length; i++) {
       		var e = dataset.objects[i];
       		if( e.name.toLowerCase().indexOf(text.toLowerCase()) != -1 ){
       			e.setPercentage(1);
       		}
       	}
       	this.updateMapAndTimeAndTable(index);
	},

	/**
	 * adds selected elements of a specific dataset as a new dataset
	 * 
	 * @param {int}
	 *            id the id of the dataset
	 */
	storeSelected: function(id){
		var dataSets = this.history[this.historyIndex].dataSets;
		if( dataSets.length == 4 ){
			alert( "The maximum number of 4 parallel datasets is reached!" );
		}
		else {
			var dataSet = dataSets[id].copy();
       		var contains = false;
           	for (var j = 0; j < dataSets[id].objects.length; j++) {
    	       	if ( dataSets[id].objects[j].percentage == 1 ){
					dataSet.addObject( dataSets[id].objects[j] );
                   	contains = true;
				}
           	}
       		if (contains) {
				this.addDataSet(dataSet);
			}
        	else {
        		alert("Your Selection contains no elements!");
        	}
      	}
	},

	/**
	 * Adds a dataset to the actual history entry
	 */
	addDataSet: function( dataSet ){
		var oldDataSets = this.history[this.historyIndex].dataSets;
		var newDataSets = oldDataSets.concat(dataSet);
		this.addHistoryEntry(new HistoryEntry(newDataSets));
		this.initElements();
        this.reset();
	},
	
    /**
	 * Sets the widgets for the core component
	 * 
	 * @param {STIMap}
	 *            map the javascript object of the map widget
	 * @param {STITimeplot}
	 *            plot the javascript object of the timeplot widget
	 */
	setElements: function(map, timeplot){
		this.map = map;
		this.timeplot = timeplot;
	},

    /**
	 * initializes the core component for the Spatio Temporal Interface. here,
	 * the handling of the search interface is defined (including undo, refine
	 * and clear selection button). furthermore, the elements (map, timeplot,
	 * tables) are instanciated.
	 */
    initialize: function(){
    
        var context = this;
        this.takeTime = false;
		this.props = new STIProps();

        this.history = [];
        
        this.history.push( new HistoryEntry([]) );
        this.historyIndex = 0;
        
        var Unselectable = {
            enable: function(e){
                var e = e ? e : window.event;
                if (e.button != 1) {
                    if (e.target) {
                        var targer = e.target;
                    }
                    else 
                        if (e.srcElement) {
                            var targer = e.srcElement;
                        }
                    if( targer.tagName == undefined ){
                    	return false;
                    }
                    var targetTag = targer.tagName.toLowerCase();
                    if ((targetTag != "input") && (targetTag != "textarea")) {
                        return false;
                    }
                }
            },
            disable: function(){
                return true;
            }
        }
        
        if (typeof(document.onselectstart) != "type filter textundefined") {
            document.onselectstart = Unselectable.enable;
        }
        else {
            document.onmousedown = Unselectable.enable;
            document.onmouseup = Unselectable.disable;
        }
        
        this.sources = [];
        try {
        	var jsonString = this.getFileString("datasources.json");
        	this.sources = eval('(' + jsonString + ')');
        }
        catch(e){        
        }

        this.overlays = [];
        try {
        	var jsonString = this.getFileString("overlaysources.json");
        	this.overlays = eval('(' + jsonString + ')');
        }
        catch(e){        
        }

        this.lockScreenContainer = document.createElement("div");
        this.lockScreenContainer.setAttribute('class','lockScreenContainer');
        document.getElementById("mainContainer").appendChild(this.lockScreenContainer);    

    },
    
    getFileString: function(url){
        var xmlhttp = false;
        if (!xmlhttp) 
            try {
                xmlhttp = new XMLHttpRequest();
            } 
            catch (e) {
                xmlhttp = false;
            }
        if (typeof ActiveXObject != "undefined") {
            if (!xmlhttp) 
                try {
                    xmlhttp = new ActiveXObject("MSXML2.XMLHTTP");
                } 
                catch (e) {
                    xmlhttp = false;
                }
            if (!xmlhttp) 
                try {
                    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
                } 
                catch (e) {
                    xmlhttp = false;
                }
        }
        xmlhttp.open('GET', url, false);
        xmlhttp.send("");
        return xmlhttp.responseText;
    },
    
    /**
	 * constructs an url to a dynamic datasource with the specific user input as
	 * attribute
	 * 
	 * @param {int}
	 *            ds the datasource index
	 * @param {String}
	 *            input the user input
	 */
    retrieveKml: function(ds,input){
    	var url = this.sources[ds].url;
// var tags = input.replace(/[^a-zA-Z0-9]/g,",");
// url += tags;
		url += input;
		
		/* test for csv flag in request parameters (see datasources.json) */
		var beginCsv = url.indexOf("csv=true");
		if (beginCsv != -1) {
			/* remove "csv=true" from request parameters */
			url = url.substr(0, beginCsv) + url.substr(beginCsv + 9);	
			/* convert csv to kml */
			this.parseCsv(url,input,ds);
		}
		else {
			/* parse kml */
			this.parseKml(url,input,ds);
		}
    },

	parseIt: function(xml,term,ds){
		var getTimeData = function( timeString ){
			try {
				var bc = false;
				if( timeString.startsWith("-") ){
					bc = true;
					timeString = timeString.substring(1);
				}
				var timeSplit = timeString.split("T");
				var timeData = timeSplit[0].split("-");
				for (var i = 0; i < timeData.length; i++) {
					parseInt(timeData[i]);
				}
				if( bc ){
					timeData[0] = "-"+timeData[0];
				}
				if (timeSplit.length == 1) {
					return timeData;
				}
				var dayData;
				if (timeSplit[1].indexOf("Z") != -1) {
					dayData = timeSplit[1].substring(0, timeSplit[1].indexOf("Z") - 1).split(":");
				}
				else {
					dayData = timeSplit[1].substring(0, timeSplit[1].indexOf("+") - 1).split(":");
				}
				for (var i = 0; i < timeData.length; i++) {
					parseInt(dayData[i]);
				}
				return timeData.concat(dayData);
			} 
			catch (exception) {
				alert("\""+timeString+"\" is no valid time/date");
				return null;
			}
		}

		var core = this;

		var time = SimileAjax.DateTime;     
        var newObjects = new Array();
        var elements = xml.getElementsByTagName("Placemark");
        var granularity = 0;

		if( elements.length == 0 ){
			this.unblockUI();
			return;
		}
		
		var xmlSerializer = new XMLSerializer();

        for (var i = 0; i < elements.length; i++) {

            var placemark = elements[i];
			var name, description, descriptionData, place, timeData, coordinates, timeStamp, timeSpan, g;
			
			try{
				var nameElement = placemark.getElementsByTagName("name"); 
				if ( (nameElement != null) && (nameElement.length > 0) && (nameElement[0].childNodes.length > 0) ){
					name = nameElement[0].childNodes[0].nodeValue;
				}
				else {
					name = "";
				}
			} catch(e) {
				name = "";
			}
	
			try{
				var descriptionElement = placemark.getElementsByTagName("description"); 
				if ( (descriptionElement != null) && (descriptionElement.length > 0) && (descriptionElement[0].childNodes.length > 0) ){

					description = $(descriptionElement).text();

					//check whether the description element contains a table
					//if yes, this data will be loaded as separate columns
					try{
						//cleanWhitespace removes non-sense text-nodes (space, tab)
						//and is an addition to jquery defined in Sti.html
						var descriptionDocument = $($.parseXML(description)).cleanWhitespace();
						
						descriptionData = new Object();

						$(descriptionDocument).find("tr").each(
							function() {
								var isHeader = true;
								var lastHeader = "";
								
								$(this).find("td").each(
									function() {
										if (isHeader) {
											lastHeader = $(this).text();
											isHeader = false;
										} else {
											var value = "";

											//if this td contains HTML, serialize all
											//it's children (the "content"!)
											$(this).children().each(
												function() {
													value += xmlSerializer.serializeToString(this);
												}
											);
											
											//no HTML content (or no content at all)
											if (value.length == 0)
												value = $(this).text();
											
											if (descriptionData[lastHeader] != null)
												//append if a field occures more than once 
												descriptionData[lastHeader] += "\n" + value;
											else
												descriptionData[lastHeader] = value;
											isHeader = true;
										}
									}
								)
							}
						);
					} catch(e) {
						//Description is either no HTML or no table
						alert(e);
					}
				}
				else {
					description = "";
				}
			} catch(e) {
				description = "";
			}
	
			try{
				var placeElement = placemark.getElementsByTagName("address"); 
				if ( (placeElement != null) && (placeElement.length > 0) && (placeElement[0].childNodes.length > 0) ){
					place = placeElement[0].childNodes[0].nodeValue;
				}
				else {
					place = "";
				}
			} catch(e) {
				place = "";
			}

			var getDate = function(timeData){
				try {
					var date;
					if (timeData.length == 6) {
	                	g = time.SECOND;		
	                	date = new Date(Date.UTC(timeData[0], timeData[1]-1, timeData[2], timeData[3], timeData[4], timeData[5]));
					}
	            	else if (timeData.length == 3) {
	                	g = time.DAY;
	                	date = new Date(Date.UTC(timeData[0], timeData[1]-1, timeData[2]));
	            	}
					else if (timeData.length == 2) {
	                   	g = time.MONTH;
	                   	date = new Date(Date.UTC(timeData[0], timeData[1]-1, 1));
	              	}
					else if (timeData.length == 1) {
	                   	g = time.YEAR;
	                   	date = new Date(Date.UTC(timeData[0], 0, 1));
	              	}
	            	if (granularity < g) {
	                	granularity = g;
	            	}
					if( timeData[0] && timeData[0] < 100 ){
						date.setFullYear(timeData[0]);
					}
	            	return date;
				} catch (e) {
					alert("\""+timeData+"\" is no valid time/date");
	            	return null;
	            }
            }

			try {
				timeData = getTimeData( placemark.getElementsByTagName("TimeStamp")[0].getElementsByTagName("when")[0].childNodes[0].nodeValue );
				if( timeData != null ){
					timeStamp = getDate(timeData);
				}
				if( timeStamp == undefined ){
					alert("No valid timestamp or timespan information for element " + i + ".");
					continue;
				}
			}
			catch(e){
				try {		
					timeStamp = undefined;		
					var timeSpanTag = placemark.getElementsByTagName("TimeSpan")[0];
					var timeDataStart = getTimeData( timeSpanTag.getElementsByTagName("begin")[0].childNodes[0].nodeValue );
					var startTime = getDate(timeDataStart);
					var timeDataEnd = getTimeData( timeSpanTag.getElementsByTagName("end")[0].childNodes[0].nodeValue );
					var endTime = getDate(timeDataEnd);
					timeSpan = { start: startTime, end: endTime };					
				}
				catch(e){
					alert("No valid timestamp or timespan information for element " + i + ".");
					continue;
				}
			}

			try {
				coordinates = placemark.getElementsByTagName("Point")[0].getElementsByTagName("coordinates")[0].childNodes[0].nodeValue;
            	var lonlat = coordinates.split(",");
            	if( lonlat[0] == "" || lonlat[1] == "" || isNaN(lonlat[0]) || isNaN(lonlat[1]) ){
					alert("No valid coordinate information for element " + i + ".");
            		continue;
            	}
            	newObjects.push(new DataObject(name, description, place, timeStamp, timeSpan, g, lonlat[0], lonlat[1], descriptionData));
			}
			catch(e){
				alert("No valid coordinate information for element " + i + ".");
				continue;
			}
        }

		var dataset = new DataSet( newObjects, term, granularity );
		dataset.source = ds;
		var status = document.getElementById("statusText");
		status.innerHTML = "Space & Time Aggregation ...";
		setTimeout( function(){ 
						core.addDataSet( dataset );
						core.unblockUI();
					},
					1 );
	},
    
    /**
	 * retrieves and loads a kml-file from the local system
	 * 
	 * @param {int}
	 *            ds the datasource index
	 * @param {File}
	 *            file the file that the user selected
	 */
	retrieveLocalKml: function(ds,filename){

		var core = this;
		if( this.blocked ){
			setTimeout( function(){ core.retrieveLocalKml(ds,filename); }, 100 );
			return;
		}
		core.blockUI();
		
		var status = document.getElementById("statusText");
		status.innerHTML = "Retrieving Data ...";
		
		var filelist = $('#localKMLFileChooser').get(0).files;
		if (filelist.length > 0){
			var file = filelist[0];
			
			var reader = new FileReader();
			
			reader.onloadend = (function(theFile) {
		        return function(e) {
					status.innerHTML = "Parsing Data ...";
					
					var localkmlDoc;
					try {
						localkmlDoc = $.parseXML(reader.result);
					} catch (e) {
						alert("KML file is not valid XML. Please check opening/closing tags and check the spelling.");
						
						core.unblockUI();
						
						return;
					}
					
					setTimeout( function(){ core.parseIt(localkmlDoc,filename,ds); }, 1 );
				};
		    })(file);
						
			reader.readAsText(file);
		}

		return;
    },
    
    /**
	 * retrieves and loads a CSV-file from the local system
	 * 
	 * @param {int}
	 *            ds the datasource index
	 * @param {File}
	 *            file the file that the user selected
	 */
	retrieveLocalCsv: function(ds,filename){

		var core = this;
		if( this.blocked ){
			setTimeout( function(){ core.retrieveLocalCsv(ds,filename); }, 100 );
			return;
		}
		core.blockUI();
		
		var status = document.getElementById("statusText");
		status.innerHTML = "Retrieving Data ...";
		
		var filelist = $('#localCSVFileChooser').get(0).files;
		if (filelist.length > 0){
			var file = filelist[0];
			
			var reader = new FileReader();
			
			reader.onloadend = (function(theFile) {
		        return function(e) {
					status.innerHTML = "Parsing Data ...";
					
					var kmlText = core.convertCsv(reader.result);
					
					var localkmlDoc;
					try {
						localkmlDoc = $.parseXML(kmlText);
					} catch (e) {
						alert("KML file is not valid XML. Please check opening/closing tags and check the spelling.");
						
						core.unblockUI();
						
						return;
					}
					
					setTimeout( function(){ core.parseIt(localkmlDoc,filename,ds); }, 1 );
				};
		    })(file);
						
			reader.readAsText(file);
		}

		return;
    },
    
    /**
	 * parses the kml-file which includes the results for a given search request
	 * 
	 * @param {File}
	 *            kmlFile
	 * @param {String}
	 *            term the term identifier for the resulting dataset
	 */
    parseKml: function(kmlFile,term,ds){
	var core = this;
	if( this.blocked ){
		setTimeout( function(){ core.parseKml(kmlFile,term,ds); }, 100 );
		return;
	}
	core.blockUI();
	$.ajax({
		url: kmlFile,
		dataType: "xml",
		beforeSend: function(){
			var status = document.getElementById("statusText");
			status.innerHTML = "Retrieving Data ...";
		},
		success: function(xml){
			var status = document.getElementById("statusText");
			status.innerHTML = "Parsing Data ...";
			setTimeout( function(){ core.parseIt(xml,term,ds); }, 1 );
		}
	});
    },

    /**
	 * converts the csv-file to a kml-file
	 * 
	 * @param {String}
	 *            text
	 */
    convertCsv: function(text){

		var status = document.getElementById("statusText");
		status.innerHTML = "Converting CSV to KML ...";   		
		/* convert here from csv to kml */
		var kmlString = '<?xml version="1.0" standalone="yes"?>\n';
			kmlString += '<kml xmlns="http://www.opengis.com/kml/ext/2.2">\n';
			kmlString += '\t<Folder>\n';
		/* define expected csv table headers (first line) */
		var expectedHeaders = new Array("Name","Address","Description","Longitude","Latitude","TimeStamp","TimeSpan:begin","TimeSpan:end");
		/* convert csv string to array of arrays using ucsv library */
		var csvArray = CSV.csvToArray(text);
		/* get real used table headers from csv file (first line) */
		var usedHeaders = csvArray[0];
		/* loop outer array, begin with second line */
		for (var i = 1; i < csvArray.length; i++) {
			var innerArray = csvArray[i];
			kmlString += '\t\t<Placemark>\n';
			/* declare few variables */                                   
			var timespanBegin = "";
			var timespanEnd = "";
			var longitude = "";
			var latitude = "";
		   	/* loop inner array */
			for (var j = 0; j < innerArray.length; j++) {
				/* Name */
				if (usedHeaders[j] == expectedHeaders[0]) {
					kmlString += '\t\t\t<name><![CDATA[' + innerArray[j] + ']]></name>\n';
				}
				/* Address */
				if (usedHeaders[j] == expectedHeaders[1]) {
					kmlString += '\t\t\t<address><![CDATA[' + innerArray[j] + ']]></address>\n';
				}
				/* Description */
				if (usedHeaders[j] == expectedHeaders[2]) {
					kmlString += '\t\t\t<description><![CDATA[' + innerArray[j] + ']]></description>\n';
				}
				/* TimeStamp */
				if (usedHeaders[j] == expectedHeaders[5]) {
					kmlString += '\t\t\t<TimeStamp>\n' +
						'\t\t\t\t<when>' + innerArray[j] + '</when>\n' +
						'\t\t\t</TimeStamp>\n';
				}
				/* TimeSpan:begin */
				if (usedHeaders[j] == expectedHeaders[6]) {
					timespanBegin = innerArray[j];
				}   						
				/* TimeSpan:end */
				if (usedHeaders[j] == expectedHeaders[7]) {
					timespanEnd = innerArray[j];
				}   						
				/* Longitude */                                                          
				if (usedHeaders[j] == expectedHeaders[3]) {                              
					longitude = innerArray[j];                                           
				}                                                                        
				/* Latitude */                                                           
				if (usedHeaders[j] == expectedHeaders[4]) {                              
					latitude = innerArray[j];
				}
			}
			/* set timespan:begin und timespan:end */
			kmlString += '\t\t\t<TimeSpan>\n' +
				'\t\t\t\t<begin>' + timespanBegin + '</begin>\n' +
				'\t\t\t\t<end>' + timespanEnd + '</end>\n' +
				'\t\t\t</TimeSpan>\n';
			/* set longitude and latitude */                                                 
			kmlString += '\t\t\t<Point>\n' +                                                 
				'\t\t\t\t<coordinates>' +                                                
				longitude +',' + latitude +                                              
				'</coordinates>\n' +
				'\t\t\t</Point>\n';
			/* end Placemark */
			kmlString += '\t\t</Placemark>\n';
		}
		kmlString += '\t</Folder>\n';
		kmlString += '</kml>\n';
		
		return kmlString;
    },
    
    /**
	 * loads the csv-file
	 * 
	 * @param {File}
	 *            csvFile
	 * @param {String}
	 *            term the term identifier for the resulting dataset
	 */
    parseCsv: function(csvFile,term,ds){
	var core = this;
   	if( this.blocked ){
   		setTimeout( function(){ core.parseCsv(csvFile,term,ds); }, 100 );
   		return;
   	}
   	core.blockUI();
   	$.ajax({
   		url: csvFile,
   		dataType: "text",
   		beforeSend: function(){
   			var status = document.getElementById("statusText");
   			status.innerHTML = "Retrieving Data ...";   		
   		},   		
   		success: function(text){
   			var status = document.getElementById("statusText");
   			status.innerHTML = "Converting CSV to KML ...";   		
   			/* convert here from csv to kml */
   			var kmlString = convertCsv(text);
			
   			/* convert string to xml */
   			var kmlXml = $.parseXML(kmlString);
   			console.log(kmlXml);
   			/* pares the converted kml data */
   			var status = document.getElementById("statusText");
   			status.innerHTML = "Parsing Data ...";
   			setTimeout( function(){ core.parseIt(kmlXml,term,ds); }, 1 );
   		}
 	});
    },
        
    /**
	 * updates the timeplot and table element. its called from the STIMap
	 * object, when objects on the map had been selected by featureSelect or
	 * polygon.
	 * 
	 * @param {boolean}
	 *            hover true, if there was a hover selection
	 */
    updateTimeAndTable: function(hover){
        updateTables(hover);
        this.timeplot.polesBySlices();
        this.refining = -1;
    },
    
    /**
	 * updates the map, timeplot and table element. its called from the STITable
	 * object, when a text selection has been done
	 */
    updateMapAndTimeAndTable: function(index){
        updateTables(hover);
        this.timeplot.polesBySlices();
        this.map.updateMap();
        this.refining = index;
    },

    /**
	 * updates the timeplot and map element. its called from the STITable
	 * object, when objects in one of the tables had been selected.
	 */
    updateTimeAndMap: function(){
        this.map.updateMap();
        this.timeplot.polesBySlices();
        this.refining = -1;
    },
    
    /**
	 * updates the table and map element. its called from the STITimeplot
	 * object, when objects in the timeplot had been selected by timestamp or
	 * -range.
	 * 
	 * @param {boolean}
	 *            hover true, if there was a hover selection
	 */
    updateTableAndMap: function(hover){
        updateTables(hover);
        this.map.updateMap();
        this.refining = -1;
    },
    
    /**
	 * initializes the sti components (map, timeplot, table) depending on the
	 * top masks of the data sets. its called after a new search was performed,
	 * refining or undo button had been clicked
	 */
    initElements: function(){
    	this.reset();
    	var dataSets = this.history[this.historyIndex].dataSets;
    	var granularity = 0;
    	for( var i=0; i<dataSets.length; i++ ){
    		if( dataSets[i].maxGranularity > granularity ){
    			granularity = dataSets[i].maxGranularity; 
    		}
    	}
    	this.timeplot.initTimeplot(dataSets, granularity);
        this.map.initObjectLayer(dataSets);
        initTables();
    },
    
    /**
	 * deletes a data set with specific index
	 * 
	 * @param {int}
	 *            index the index of the data set to delete
	 */
    deleteDataSet: function(index){
    	var color = colors[index];
        colors.splice(index, 1);
    	var oldDataSets = this.history[this.historyIndex].dataSets;
    	var newDataSets = [];
    	for( var i=0; i<oldDataSets.length; i++ ){
    		if( i != index ){
    			newDataSets.push( oldDataSets[i] );
    		}
    	}
		colors.splice( newDataSets.length, 0, color );
		this.addHistoryEntry(new HistoryEntry(newDataSets));
		this.initElements();
        this.reset();
   	},

    /**
	 * Switches to another history entry with the given index
	 * 
	 * @param {int}
	 *            index the index of the history entry to load
	 */
	switchThroughHistory: function( index ){
		this.historyIndex = index;
		this.initElements();
	},
	
    /**
	 * Adds a new history entry containing actual datasets
	 * 
	 * @param {HistoryEntry}
	 *            historyEntry the history entry to add
	 */
	addHistoryEntry: function( historyEntry ){	
		this.history = this.history.slice(0,this.historyIndex+1);
		this.history.push(historyEntry);
		this.historyIndex = this.history.length - 1;
		addHistoryItem(this.historyIndex);
	},
   
    /**
	 * adds an element to the user individual data set
	 * 
	 * @param {DataObject}
	 *            object the data object to add
	 */
    addElement: function(object){
        if (this.individualDataSet == null) {
            this.individualDataSet = new DataSet([], "individual", 0);
			var oldDataSets = this.history[this.historyIndex].dataSets;
			var newDataSets = oldDataSets.concat(this.individualDataSet);
			this.addHistoryEntry(new HistoryEntry(newDataSets));
        }
		this.individualDataSet.addObject(object);
        this.initElements();
        this.reset();
    },
    
    /**
	 * resets the core within all elements and data objects to
	 * non-selection-status
	 */
    reset: function(){
        this.refining = -2;
        var dataSets = this.history[this.historyIndex].dataSets;        
        for (var i = 0; i < dataSets.length; i++){ 
            for (var j = 0; j < dataSets[i].objects.length; j++){
                dataSets[i].objects[j].setPercentage(0);
				dataSets[i].objects[j].setHover(false);
			}
		}
        this.timeplot.resetTimeplot();
        this.map.resetMap();
        updateTables(false);
    },
	
    /**
	 * Security hover unselection of elements if browser events got stucked
	 */
	undoHover: function(update){

		this.map.hoverUnselect();
		this.timeplot.hoverUnselect(update);
	},
	
	createLink: function(){
		var c = this.map.openlayersMap.getCenter();
		var map = this.map.openlayersMap.baseLayer.id;
		var mapCenter = { lon: c.lon, lat: c.lat };
		var mapZoom = this.map.openlayersMap.getZoom();
		var data = [];
		// store complete history in data --> flow of history events
		// history event can be: loading/deleting dataset, refinement by
		// timerange/polygon at specific zoom level/point at specific zoom
		// level, a loaded link history (this)
		// flag for the ability to display stored history or not
	},
	
	lockScreen: function(){
		this.lockScreenContainer.style.visibility = "visible";
        this.lockScreenContainer.style.height = getDocHeight()+"px";
	},
	
	lockScreenMessage: function(div){
		this.lockScreenContainer.innerHTML = "";
        var lockScreenDiv = document.createElement("div");
        lockScreenDiv.setAttribute('class','lockScreen');
		this.lockScreenContainer.appendChild(lockScreenDiv);
		this.lockScreenContainer.appendChild(div);
	},
	
	unlockScreen: function(){
		this.lockScreenContainer.style.visibility = "hidden";
	}
	    
};

/**
 * defines a history entry
 * 
 * @param {DataSet[]}
 *            dataSets the datasets of this history entry
 * 
 * @constructor
 */
function HistoryEntry( dataSets ){
	this.dataSets = dataSets;
};