/*
    JSDB - JavaScript Runtime Database v0.3
    Copyright (C) 2007  Ingo Volkmann
	Visit my site and get in contact with me at http://en.myinterests.de

    This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License 
	as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
	without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
	See the GNU General Public License for more details at http://www.gnu.org/licenses/gpl.html
*/

	// db objects
	function jsdbTable(cols) {
		
		// create table
		this.rows = new Array();
		this.cols = new Array('id');
		for( var i=0; i < cols.length; i++ )
			void this.cols.push(cols[i]);
		
		// insert row
		this.insertRow = function(data) {
			void data.unshift(this.rows.length + 1);		// auto increment id
			var obj = new jsdb_Insert(this.cols, data);
			void this.rows.push(obj);
		}
		
		// update row
		this.updateRow = function(data, where, and) {
			for( var i=0; i < this.rows.length; i++ ) {	
				eval("if( this.rows[i][where[0]]" + where[1] + "where[2]" + this.parseAnd(and) + ") { for( var a=0; a < data.length; a++ ) { if( !jsdb_isInt(a/2) ) { continue; } this.rows[i][data[a]] = data[a+1]; } } " );
			}
		}
		
		// delete row
		this.deleteRow = function(where, and) {
			for( var i=0; i < this.rows.length; i++ ) {	
				eval("if( this.rows[i][where[0]]" + where[1] + "where[2]" + this.parseAnd(and) + ") { this.rows[i] = ''; } " );
			}
		}
		
		// select row
		this.selectRow = function(where, and, order) {
			var selected = new Array();
			for( var i=0; i < this.rows.length; i++ ) {	
				if( typeof this.rows[i].id != 'undefined' ) {
					if( where )
						eval("if( this.rows[i][where[0]]" + where[1] + "where[2]" + this.parseAnd(and) + ") { void selected.push(this.rows[i]); } " );
					else
						eval("void selected.push(this.rows[i]);" );
				}
			}
			return this.parseOrder(selected, order);
		}
						 
		// parse and-arguments from where clause
		this.parseAnd = function(and) {
			var andStr = '';
			if( and ) {
				for( var i=0; i < and.length; i=i+3 ) {
					andStr += ' && this.rows[i].' + and[i] + ' ' + and[i+1] + ' \'' + and[i+2] + '\' ';
				}
			}
			//alert(andStr);
			return andStr;
		}

		// parse order by
		this.parseOrder = function(selected, order) {
			if( order ) {
				for( var i=0; i < order.length; i=i+2 ) {
					eval( "var tmp" + i + " = new Array();" );
					for( var k=0; k < selected.length; k++ ) {
						eval( "void tmp" + i + ".push(selected[k]." + order[i] + ");" ); 
					}
					eval( "tmp" + i + ".sort(jsdb_natcasesort);" );
					eval( "if( order[i+1] == 'desc' ) tmp" + i + ".reverse();" );
					var tmpSel = new Array();
					eval( "for( var k=0; k < tmp" + i + ".length; k++ ) { for( var m=0; m < selected.length; m++ ) { if( selected[m]." + order[i] + " == tmp" + i + "[k] ) { void tmpSel.push(selected[m]); continue; } } }" );
					selected = tmpSel;
				}
			}
			return selected;
		}
		
	}
	
	// functions
	// new row object
	function jsdb_Insert(cols, data) {
		for( var i=0; i < cols.length; i++ )
			this[cols[i]] = data[i];
	}
	
	// remove element from array
	function jsdb_delArrayEl(array, element) {
		for( var i = element; i < array.length; i++ ) {
			array[i] = array[i+1];
		}
		array.pop();
		return array;
	}
	
	// in_array
	function jsdb_in_array(array, value) {
		for( var i=0; i < array.length; i++ )
			if( array[i] == value )
				return true;
		return false;
	}
	
	// is int
	function jsdb_isInt(x) {
		var y = parseInt(x);
		if (isNaN(y)) return false;
		return x == y && x.toString() == y.toString();
	} 

	// the stand alone natsort algorithm (documentation included) is available at http://en.myinterests.de
	var jsdb_natsortLimit = 20;
	var jsdb_natsortType = 1;
	// natsort
	function jsdb_natsort(a,b) { // case sensitive
	
		if( jsdb_natsortType == 1 ) { // lower cases between the upper cases
			var replaceArray= new Array('0','1','2','3','4','5','6','7','8','9','A','a','B','b','C','c','D','d','E','e','F','f','G','g','H','h','I','i','J','j','K','k','L','l','M','m','N','n','O','o','P','p','Q','q','R','r','S','s','T','t','U','u','V','v','W','w','X','x','Y','y','Z','z','_');
		} else if( jsdb_natsortType == 2 ) { // lower cases after all upper cases
			var replaceArray= new Array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','_');
		}
		
		a = a.toString();
		if( a.length > jsdb_natsortLimit ) a = a.substr(0,jsdb_natsortLimit);
		a = a.replace(/\W/g, '_');
		var aArr = a.split('');
		for( var i=0; i < replaceArray.length; i++ ) {
			for( var k=0; k < aArr.length; k++ ) {
				if( aArr[k] == replaceArray[i] ) {
					if( i < 10 ) aArr[k] = parseInt(i);
					else aArr[k] = i.toString();
				}
			}
		}
		
		b = b.toString(); 
		if( b.length > jsdb_natsortLimit ) b = b.substr(0,jsdb_natsortLimit);
		b = b.replace(/\W/g, '_');
		var bArr = b.split('');
		for( var i=0; i < replaceArray.length; i++ ) {
			for( var k=0; k < bArr.length; k++ ) {
				if( bArr[k] == replaceArray[i] ) {
					if( i < 10 ) bArr[k] = parseInt(i);
					else bArr[k] = i.toString();
				}
			}
		}
		
		aArr = jsdb_natsort_combineInt(aArr);
		bArr = jsdb_natsort_combineInt(bArr);
		for( var i=0; i < aArr.length; i++ ) {
			if( aArr[i] != bArr[i] ) {
				if( typeof aArr[i] == typeof bArr[i] ) {
					return (aArr[i]==bArr[i]) ? 0 : (aArr[i]>bArr[i]) ? 1 : -1;
				} else {
					if( typeof aArr[i] == 'string' && typeof bArr[i] == 'number' ) return 1;
					if( typeof aArr[i] == 'number' && typeof bArr[i] == 'string' ) return -1;
				}
			}  
		}
		
		return 0;
	}
	// natcasesort
	function jsdb_natcasesort(a,b) { // not case sensitive
	
		var replaceArray= new Array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','_');
		
		a = a.toString();
		if( a.length > jsdb_natsortLimit ) a = a.substr(0,jsdb_natsortLimit);
		a = a.replace(/\W/g, '_');
		var aArr = a.split('');
		for( var i=0; i < replaceArray.length; i++ ) {
			for( var k=0; k < aArr.length; k++ ) {
				if( !jsdb_isInt(aArr[k]) && aArr[k].toLowerCase() == replaceArray[i] ) {
					aArr[k] = i.toString();
				} else if( aArr[k] == replaceArray[i] ) {
					aArr[k] = parseInt(i);
				}
			}
		}
		
		b = b.toString(); 
		if( b.length > jsdb_natsortLimit ) b = b.substr(0,jsdb_natsortLimit);
		b = b.replace(/\W/g, '_');
		var bArr = b.split('');
		for( var i=0; i < replaceArray.length; i++ ) {
			for( var k=0; k < bArr.length; k++ ) {
				if( !jsdb_isInt(bArr[k]) && bArr[k].toLowerCase() == replaceArray[i] ) {
					bArr[k] = i.toString();
				} else if( bArr[k] == replaceArray[i] ) {
					bArr[k] = parseInt(i);
				}
			}
		}
		
		aArr = jsdb_natsort_combineInt(aArr);
		bArr = jsdb_natsort_combineInt(bArr);
		for( var i=0; i < aArr.length; i++ ) {
			if( aArr[i] != bArr[i] ) {
				if( typeof aArr[i] == typeof bArr[i] ) {
					return (aArr[i]==bArr[i]) ? 0 : (aArr[i]>bArr[i]) ? 1 : -1;
				} else {
					if( typeof aArr[i] == 'string' && typeof bArr[i] == 'number' ) return 1;
					if( typeof aArr[i] == 'number' && typeof bArr[i] == 'string' ) return -1;
				}
			}  
		}
		
		return 0;
	}
	// natsort helper - jsdb_natsort_combineInt
	function jsdb_natsort_combineInt(array) {
		
		for( var i=0; i < array.length; i++ ) {
			if( typeof array[i] == 'number' && typeof array[i+1] == 'number' ) {
				var num = array[i].toString() + array[i+1].toString();
				array[i] = parseInt(num);
				array = jsdb_delArrayEl(array, i+1);
				jsdb_natsort_combineInt(array);
				break;
			}
		}
		
		while( array.length < jsdb_natsortLimit ) void array.push('00');
		return array;
		
	}
	
	
