/**
 * Holds filterconfiguration
 *
 * @access public
 * @version 0.1
 * @author Dominik Fettel, <fettel@navigate.de>
 * @param string
 * @param int
 * @param string
 * @return void
 */
function DataSetFilterConfiguration(value, col, type, caseSensitive) {
	/**
	 * The value by which the filter applies
	 *
	 * @access public
	 * @type string
	 */
	this.value = '';

	/**
	 * The col in which the filter apples. This can be "-1" so that the filter
	 * to all columns.
	 *
	 * @access public
	 * @type int
	 */
	this.col = 0;

	/**
	 * Possible FilterTypes are:
	 * ANY: .*text.*
	 * BEGINN: text.*
	 * EXACT: ^text$
	 *
	 * @access public
	 * @type string
	 */
	this.type = 'ANY';

    /**
     * True if the filters work case-sensitive
     *
     * @access public
     * @var boolean
     */
	this.caseSensitive = false;
	this.value = value;
	if(col != null) this.col = col;
	if(type != null) this.type = type;
	if(caseSensitive != null) this.caseSensitive = caseSensitive;
}

/**
 * Holds order-configuration
 *
 * @access public
 * @author Dominik Fettel, <fettel@navigate.de>
 * @param int
 * @param boolean
 * @param string
 * @return void
 */
function DataSetOrderConfiguration(col, ascending, type) {

	/**
	 * The col in which the order applies.
	 *
	 * @access public
	 * @type int
	 */
	this.col = 0;

	/**
	 * If true, the order is ascending, otherwise descending.
	 *
	 * @access public
	 * @type boolean
	 */
	this.ascending = false;

	/**
	 * Possible types
	 * alpha: alphanumerical sort
	 * num:   numeric sort
	 * date:   try to sort by date, if values are xx.xx.xxxx
	 *
	 * @access public
	 * @type string
	 */
	this.type = "alpha";

	if(col != null) this.col = col;
	if(ascending != null) this.ascending = ascending;
	if(type != null) this.type = type;
}

/**
 * Represents a gridview-column.
 *
 * @access public
 * @author Dominik Fettel, <fettel@navigate.de>
 * @param int
 * @param string
 * @return void
 */
function DatasetColumn(pos, title) {
	/**
	 * Position in GridView
	 *
	 * @access public
	 * @type int
	 */
	this.pos = 0;

	/**
	 * Title of column, first and static line of GridView, if set.
	 *
	 * @access public
	 * @type string
	 */
	this.title = '';

	/**
	 * Displays a pseudo type of date in this column. It's used i.e. for the
	 * of the sorting type.
	 *
	 * @access public
	 * @type string
	 */
	this.type = '';

	/**
	 * True, if the grid is sorted or filtered by this col
	 *
	 * @access public
	 * @type boolean
	 */
	this.active = false;

	/**
	 * True, if the grid is sortedby this col
	 *
	 * @access public
	 * @type boolean
	 */
	this.sorted = false;

	/**
	 * The applying sort direction
	 *
	 * @access public
	 * @type string
	 */
	this.sortDirection = '';

	/**
	 * True, if the grid is filtered by this col
	 *
	 * @access public
	 * @var boolean
	 */
	this.filtered = false;

	/**
	 * List of unique Values in this column
	 *
	 * @access public
	 * @var Array
	 */
	this.uniqueValues = new Array();

	if(pos != null) this.pos = pos;
	if(title != null) this.title = title;

	/**
	 * Returns the PseudoType.supposedType
	 *
	 * @access private
	 * @author Dominik Fettel, <fettel@navigate.de>
	 * @return string
	 */
	this.getDefaultType = function() {
	}
}

/**
 * Represents two-dimensional data and provids facility to order and sort them and some other usefull functions.
 *
 * @access public
 * @author Dominik Fettel, <fettel@navigate.de>
 * @param Array
 * @return void
 *
 */
function Dataset(data, titles) {
	/**
	 * True if value is part of array items
	 *
	 * @access private
	 * @author Dominik Fettel, <fettel@navigate.de>
	 * @param Object test
	 * @param Array array
	 * @return boolean
	 * @todo Umbennen in _inArray da private
	 */
	this.inArray = function (test,  array) {
		var returnValue = false;
		for(var i=0;i<array.length;i++) {
			if(test == array[i]) {
				returnValue = true;
				break;
			}
		}
		return returnValue;
	}
	/**
	 * Data unfiltered and unsorted.
	 *
	 * @access public
	 * @type Array
	 */
	this.baseData = data;

	/**
	 * Column titles
	 *
	 * @access public
	 * @var Array
	 */
	this.columnTitles = new Array();

	/**
	 * A sorted copy of baseData, if the data is not filtered,
	 * otherwise a sorted copy of baseData
	 *
	 * @access public
	 * @type Array
	 */
	this.filteredData = null;

	/**
	 * Filtered copy of baseData
	 *
	 * @access public
	 * @type Array
	 */
	this.resultData = data;

	/**
	 * True if the Dataset was filtered.
	 *
	 * @access public
	 * @type boolean
	 */
	this.isFiltered = false;

	/**
	 * The current filterconfiguration
	 *
	 * @access public
	 * @type DataSetFilterConfiguration
	 */
	this.currentFilterConfig = null;

	/**
	 * True if the Dataset was sorted.
	 *
	 * @access public
	 * @type boolean
	 */
	this.isOrdered = false;

	/**
	 * The current order-configuration
	 *
	 * @access public
	 * @type DataSetOrderConfiguration
	 */
	this.currentOrderConfig = null;

	/**
	 * The columns of this dataset
	 *
	 * @type DatasetColumn[]
	 */
	this.cols = new Array();

	if(titles != null) this.columnTitles = titles;


	try {
		for(var i=0;i<data[0].length;i++) {
			var title = "";
			if(this.columnTitles[i]) title = this.columnTitles[i];
			this.cols[i] = new DatasetColumn(i, title);
			this.cols[i].uniqueValues.push(data[0][i]);

			for(var j=0;j<data.length;j++) {
				if(!this.inArray(data[j][i], this.cols[i].uniqueValues)) this.cols[i].uniqueValues.push(data[j][i]);
			}
		}
		for(var i=0;i<this.cols.length;i++)  {

			for(var j=0;j<this.cols[i].uniqueValues.length;j++)  {
				var ps = new PseudoType(this.cols[i].uniqueValues[j]);
				if(i==4) {
					var alskdjf;
				}
				if(this.cols[i].type != "") {
					if(this.cols[i].type != ps.supposedType) this.cols[i].type = "string";
				} else this.cols[i].type = ps.supposedType;
			}
		}
	} catch (execption) {
	 	alert("data wasnt't formated propper. ");
	}




	/**
	 * Filters the baseData or the sortedData in case the baseData
	 * was sorted
	 *
	 * @access public
	 * @author Dominik Fettel, <fettel@navigate.de>
	 * @param DataSetFilterConfiguration
	 * @return void
	 */
	this.filterBy = function(config) {
		if(this.isFiltered) {
			var batch = this.resultData;
		} else {
			var batch = this.baseData;
		}
		this.currentFilterConfig = config;
		this.isFiltered = true;

		this.filteredData = new Array();

		for(var i=0;i<batch.length;i++) {
			var sample = batch[i][config.col];
			var test = config.value;
			if(!config.caseSensitive) {
				sample = sample.toLowerCase();
				test = test.toLowerCase();
			}
			if(config.col > -1) {
				switch(config.type) {
					case "ANY":
						if(sample.indexOf(test) > -1) this.filteredData.push(batch[i]);
						break;
					case "BEGINN":
						if(sample.indexOf(test) == 0) this.filteredData.push(batch[i]);
						break;
					case "EXACT":
						if(sample == test) this.filteredData.push(batch[i]);
						break;
				}
			} else {
				/**
				 * @todo Filter over all columns
				 */
			}
		}
		if(this.isOrdered) {
			this.orderBy(this.currentFilterConfig);
		} else this.resultData = this.filteredData;
	}
	/**
	 * Resets the filter
	 *
	 * @access public
	 * @author Dominik Fettel, <fettel@navigate.de>
	 * @return void
	 */
	this.resetFilter = function (){
		this.isFiltered = false;
		this.resultData = this.baseData;
		this.currentFilterConfig = null;
	}

	/**
	 * Sorts the baseData. Faithful old bubble sort.
	 *
	 * Possible types
	 * alpha: alphanumerical sort
	 * num:   numeric sort
	 * date:   try to sort by date, if values are xx.xx.xxxx
	 *
	 * @access public
	 * @author Dominik Fettel, <fettel@navigate.de>
	 * @param DataSetOrderConfiguration
	 * @return void
	 */
	this.orderBy = function(config) {
		this.isOrdered = true;
		this.currentOrderConfig = config;
		var ascending = config.ascending;
		if(config.type == "") {
			config.type = this.cols[config.col].type;
		}
		var type = config.type;
		var col = config.col;

		var m = /([0-9]{2})\.([0-9]{2})\.([0-9]{4})/;
		if(this.isFiltered) var batch = this.filteredData;
		else var batch = this.baseData;
		for(var i=0;i<batch.length-1;i++) {
			var ind = i;
			for(var j=i;j<batch.length;j++) {
				var sample = batch[ind][col];
				if(type == "date") {
					m.exec(sample);
					sample = RegExp.$3+""+RegExp.$2+""+RegExp.$1;
				}
				if(type == "string") {
					sample = this.normalizeString(sample);
				}
				var test   = batch[j][col];
				if(type == "date") {
					m.exec(test);
					test = RegExp.$3+""+RegExp.$2+""+RegExp.$1;
				}
				if(type == "string") {
					test = this.normalizeString(test);
				}
				if(ascending) {
					switch(type) {
						case "date":
						case "int":
							if(Number(sample) > Number(test)) ind = j;
							break;
						default:
							if(sample > test) ind = j;
							break;
					}
				} else {
					switch(type) {
						case "date":
						case "int":
							if(Number(sample) < Number(test)) ind = j;
							break;
						default:
							if(sample < test) ind = j;
							break;
					}
				}
			}
			var clip = batch[i];
			batch[i] = batch[ind];
			batch[ind] = clip;
		}
		this.resultData = batch;
	}
	this.normalizeString = function(input) {
		var r = input;
		r = r.replace("Ä","A");
		r = r.replace("Ö","O");
		r = r.replace("Ü","U");
		r = r.replace("ä","a");
		r = r.replace("ö","o");
		r = r.replace("ü","u");
		return r.toLowerCase();
	}
}

