function db_escape(str){	
	if(typeof str !=='string') return str;
	str=addslashes(str);
	str=str.replace(";", "\;");
//	str=str.replace("<", "&lt");		
	return str;
}
function db_unescape(str){
	if(typeof str !=='string') return str;
	
	str=str.replace(/\;/gi,';');
	str=str.replace('<nl>','\n');
//	str=str.replace(/&lt/gi,'<');
	str=stripslashes(str);
	return str;
}

/* Peter Tracey peter@levelthreesolutions.com
It takes an array of fieldnames
Example:  ["field1", "field2"]
and a 2-dimensional array of the dataset data
Example: [["field1row1data", "field2row1data"], ["field1row2data", "field2row2data"]]
*/

function datasetEditFlag(keyVal){
	if(keyVal==undefined) keyVal=undefined
	this.keyVal=keyVal
	this.isNew=false;
	this.dirties = new Array();
}
function datasetField(arrDef) {
	var idx=0;
	this.alias 		= (arrDef[idx]!==undefined) ? arrDef[idx] : '-?'  ; idx++;
	this.caption	= (arrDef[idx]!==undefined) ? arrDef[idx] : '-?'  ; idx++;
	this.type 		= (arrDef[idx]!==undefined) ? arrDef[idx] : 's'	; idx++;
	this.updatable 	= (arrDef[idx]!==undefined) ? arrDef[idx] : false	; idx++;
	this.format		= (arrDef[idx]!==undefined) ? arrDef[idx] : '0.,'  	; idx++;
	this.width	 	= (arrDef[idx]!==undefined) ? arrDef[idx] : 0	; idx++;	
	this.hidden	 	= (arrDef[idx]!==undefined) ? arrDef[idx] : false	; idx++;
	this.defaultVal	= (arrDef[idx]!==undefined) ? arrDef[idx] : ''	; idx++;
	this.stampVal 	= (arrDef[idx]!==undefined) ? arrDef[idx] : ''	; idx++;
	this.dropdown 	= (arrDef[idx]!==undefined) ? arrDef[idx] : ''	; idx++;
	this.dropdownCol= (arrDef[idx]!==undefined) ? arrDef[idx] : 0 	; idx++;		
	this.onchange	= '';
	this.required	= false;
//	log(arrDef,this.alias , this.format)
	this.value 		= '';
	
	this.align = this.type.match(/i|n/gi) ? 'right' :'left' ;
	this.toString=function() {    	
    	if(this.type=='s') return this.value;
    	if(this.type=='b') return this.value;
    	if(this.type=='i') {
    		return this.value;
    	}
    	if(this.type=='n') {    	
   			format =this.format;    			
    		return number_format(this.value, format[0], format[1], format[2]);
    	}
    	if(this.type=='d') {
   			if (this.format=='') this.format=xDateFormat;
    		return cDate(this.value, this.format );    	
    	}
		return  this.value;
        
    }		
	
}


function dataset(arrColumns,arrData) {	
	if(arrColumns==undefined)	arrColumns=[];
	if(arrData==undefined)		arrData=[1,[]];
	
	this.columns = arrColumns;	
	this.data =  arrData[1];
	this.pageCount= arrData[0];
	this.record = 0;
	this.position = 1;
	this.pageNo=1;	
	this.eof = false;
	this.bof = false;	
	this.callUpdate=null;
	this.dontCallback=false
	
	this.initialize=function(oid){
		this.columns.count = this.columns.length;
		this.recordCount = this.data.length;
		this.unescapeData();
		this._deletedRows = new Array(0);
		this.addFlags();
		this.fields= new Array();
		for (var i=0; i<this.columns.length; i++) {
			var fld = new datasetField(this.columns[i])
			this.fields.push(fld);
		}
		this.reposition();
	}

	this._flag = function (r){
		if (r==undefined) r = this.record;		
		try { return this.data[r][this.flagIdx]
		 }catch(e){
		 alert('flag err row:'+r)} 
	}

	
	this.addFlags = function() {
		this.flagIdx = this.columns.count + 1;		
		var keyVal=undefined;
		for (var i = 0; i < this.data.length; i++){
			if(this.keyIndex>=0) keyVal=this.data[i][this.keyIndex]
			this.data[i][this.flagIdx]=new datasetEditFlag(keyVal)
		} 
	}	
	this.unescapeData=function(){
		for (var r = 0; r < this.data.length; r++){
			for (var c = 0; c < this.columns.count; c++){
				this.data[r][c] = db_unescape(this.data[r][c])
			}
		}
	}
	

	this.colIndex = function (x) {
		if (isNaN(x*1)) {
			for (var i=0; i<this.columns.length; i++) 
				if (this.columns[i][0].toUpperCase() == x.toUpperCase()) return i;
		} else if (x < this.columns.count && x>=0) {
			return x;
		}
		
		log("dataSet.colIndex error: Field item (" + x + ") not found.");
		
	}

	this.field = function (x)	{
		i= this.colIndex(x);
		if(i==undefined) alert("dataSet.field error: Field item (" + x + ") not found.");
		return this.fields[i] 
	}

	this.move 	= function (i)	{this.record += i-1;		this.reposition();	}
	this.moveTo = function (i)	{this.record = i-1;			this.reposition();	}
	this.first 	= function ()	{this.record = 0;			this.reposition();	}
	this.next 	= function ()	{this.record++;				this.reposition(0);	}
	this.previous =function ()	{this.record--;				this.reposition(1);	}
	this.last 	= function () 	{this.record = this.data.length-1;	this.reposition();}
	
	this.reposition = 	function (iDirection) {
//		if(this.record < 0) this.record = -1;
		if(this.record < 0) this.record = 0;
		if(this.record > this.data.length) this.record = this.data.length;	
		this.position = this.record +1;		
		switch(iDirection) {
		case 0 : // forward - check eof
			if (this.record == this.data.length) this.eof = true;
			else this.eof = false;
			break;
		case 1 : // backward - check bof
			if (this.record == -1) this.bof = true;
			else this.bof = false;
			break;		
		default :
			if (this.record == this.data.length || this.data.length == 0) this.eof = true;
			else this.eof = false;
			if (this.record == -1 || this.data.length == 0) this.bof = true;
			else this.bof = false;
		}
		
		this.readRow();	
		if(!this.dontCallback && this.callReposition) eval(this.callReposition);
	}
	this.readRow = function(){
		for (var i=0; i<this.columns.length; i++) {
			try { fldVal=this.data[this.record][i];	 }catch(e){fldVal=''} 
			this.fields[i].value=fldVal;
		}

	}
	this.addNew = function (xFields, xValues) {		
		this.__newRow = new Array(this.columns.length);
		for (var i = 0; i < this.__newRow.length; i++) this.__newRow[i]='' ; 
		this.__newRow[this.flagIdx]=new datasetEditFlag();
		this.__newRow[this.flagIdx].isNew=true;
		
		this.data[this.data.length] =this.__newRow;
		this.recordCount = this.data.length;		
		
		this.dontCallback=true;
		this.last();
		this.dontCallback=false;
		
		if(this.callAddnew) eval(this.callAddnew);
		if (xFields || xFields===0) this.update(xFields, xValues);
		for (var i=0; i<this.columns.length; i++) {			
			if(this.field(i).defaultVal){
				if(this.field(i).value=='') this.update(i, this.field(i).defaultVal)
			}
			if(this.field(i).stampVal){
				this.update(i, this.field(i).stampVal)
			}
		}
		
		
	}
	this.update = function (xFields, xValues) {
		if(this.eof || this.bof) return;		
		this.record = this.position-1;
		
		if ( (typeof(xFields) == "string")|| (typeof(xFields) == "number")) {
			i= this.colIndex(xFields);
			if(this.field(i).stampVal) xValues =this.field(i).stampVal;

			this.data[this.record][i] = xValues + "";
			this._flag().dirties.uniqueAdd(i);
			
			this.readRow();
			if(this.field(i).onchange) eval(this.field(i).onchange); 
			if(this.field(i).hasTotal) this.calcTotal(i);
			if(this.callUpdate) eval(this.callUpdate);
			
		 }else {
			if (xFields.length) for (var i=0; i<xFields.length; i++) this.update(xFields[i], xValues[i]);
			this._flag().dirties.uniqueAdd(i);
			//readRow and callUpdate executed from first if branch
		}
		return true;
	}
	this.calcTotal = function(col){	
		t=0;
		for (var r = 0; r < this.data.length; r++){			
			t+=xval(this.data[r][col]) 
		} 		
		this.field(i).total=t;		
	}	
	this.deleteRow = function () {
		this._deletedRows.push(this.data[this.record]);
		this.data.remove(this.record);
		this.recordCount = this.data.length;
		this.record--;
		this.position--;
		this.reposition();
	}

	this.deleteRows = function (aRows) {
		for (var i = 0; i < aRows.length; i++){
		 var _record = aRows[i]-1
		 this._deletedRows.push(this.data[_record]);
		 this.data[_record].deleted=true
		} 
		var newData=[]
		for (var i = 0; i < this.data.length; i++){
		 if(!this.data[i].deleted) newData.push(this.data[i])
		}
		this.data=newData;
		this.recordCount = this.data.length;
		this.record--;
		this.position--;
		this.reposition();
	}
	
	this.findFirst = function(fld,str){
		col= this.colIndex(fld);
		for (var i = 0; i < this.data.length; i++){
			if((this.data[i][col]+'').like(str)){
				this.moveTo(i+1);
				return i+1;
				break;
			}
		} 		
		return false;
	}
	this.findNext = function(fld,str){
		col= this.colIndex(fld);
		for (var i = this.record+1; i < this.data.length; i++){
			if((this.data[i][col]+'').like(str)){
				this.moveTo(i+1);
				return i+1;
				break;
			}
		}
		return false;
	}
	this.findPrev = function(fld,str){
		col= this.colIndex(fld);
		for (var i = this.record; i >=0; i--){
			if((this.data[i][col]+'').like(str)){
				this.moveTo(i+1);
				return i+1;
				break;
			}
		}
		return false;
	}

	
	
	this.sort = function (index, sortasc){
		if(sortasc==undefined) sortasc=true;
		i= this.colIndex(index);
		var asDate= (this.field(i).type=='d')
		this.data.multiSort(i,sortasc,asDate);

	}

	this.refreshFields = function (){
		srv = new clsAjaxCall('database.cls', this.oid, 'getFields()')
		srv.runAJAX(); 

		var newFields= new Array();		
		var allColumns = eval(srv.response);
		for (var i=0; i<allColumns.length; i++) {
			var fName = allColumns[i][0];
			var fld = null;
			for (var f=0; f<this.columns.length; f++) {
				if (this.columns[f][0].toUpperCase() == fName.toUpperCase()) {
					fld = this.field(fName)
					fld.type=allColumns[i][2];
					fld.align = fld.type.match(/i|n/gi) ? 'right' :'left' ;
					continue;
				}
			}
			if(fld==undefined) 	fld = new datasetField(allColumns[i]);			
			newFields.push(fld);			
		}
		this.fields= newFields;
		this.columns = allColumns
		this.columns.count = allColumns.length;		
	}
	
	this.refresh = function (){
	
		srv = new clsAjaxCall('database.cls', this.oid, 'refresh()')
		srv.setVar ("pageNo",this.pageNo)
		srv.runAJAX(); 
		var arrData = eval(srv.response);
		this.pageCount= arrData[0];
		this.data =  arrData[1];
		if(this.pageNo>this.pageCount) this.pageNo=this.pageCount;

		//check fields
		if(this.data.length){
			if(this.data[0].length!==this.columns.count) this.refreshFields();			
		}
		this.unescapeData();
		
		this._deletedRows = new Array(0);
		this.addFlags();				

		this.recordCount = this.data.length;
		this.moveTo(this.position);
		if(this.eof)this.last();
		
		return true;	
	}
	
	this.applyFilter = function (fld, fldVal, reset){	
		if(reset==undefined) reset=true;
		srv = new clsAjaxCall('database.cls', this.oid, 'applyFilter()')
		srv.setVar ("fld",fld)
		srv.setVar ("fldVal",fldVal)
		srv.setVar ("reset",reset)		
		srv.runAJAX();		
	}
	this.check = function (){	
		srv = new clsAjaxCall('database.cls', this.oid, 'check()')
		srv.runAJAX(); 		
	}
	
	this.save = function (){
		if(this.keyIndex<0) {
			log('dataset.Save: keyIndex<0');
			return false;
		}
		
		this.dontCallback=true;
		var crtPosition= this.position

		srv = new clsAjaxCall('database.cls', this.oid, 'saveData()')
		
		var arrUpdate = "Array( ";
  		var arrAddNew = "Array( ";  		

		this.first();
        while (!this.eof)        {
        	var dirties=this._flag().dirties;
        	if(dirties.length){
        		
		        record = "";
		        for(i=0; i<this.columns.count; i++)     {        	
//	 	        	fName = this.field(i).alias;
					if((this.field(i).updatable && dirties.uniqueExists(i)) || i == this.keyIndex){
			        	fVal = db_escape(this.field(i).value);
//			        	fVal = (this.field(i).value);
			        	if(this.field(i).type=='n') fVal=xval(fVal);
			            record += ""+i+"=>'"+fVal+"'";
			            if(i<this.columns.count-1)record += ",";
			        }
		        }
		        record += ")";

		        if(this._flag().isNew){
		        	arrAddNew+= "Array("+ record + ",";
		        }else{
		        	key="-1=>'"+this._flag().keyVal+"',";
		        	arrUpdate+= "Array("+key+ record + ",";
		        }
	        }
	        this.next();	        
        }  
        
        this.moveTo(crtPosition);
        this.dontCallback=false
        
        arrAddNew = arrAddNew.replaceLastChar(")");
        arrUpdate = arrUpdate.replaceLastChar(")");

		arrDelete = "Array(";
		for (r = 0 ; r< this._deletedRows.length;r++){
			
			if(this._deletedRows[r][this.flagIdx].isNew) continue;
        	fVal = this._deletedRows[r][this.flagIdx].keyVal;
            arrDelete+= "'"+fVal+"'";
        	if(r!== this._deletedRows.length-1)arrDelete+= ",";			
		}
		arrDelete+= ")";
		
		if(arrUpdate=='Array()' && arrAddNew=='Array()' && arrDelete=='Array()') return true;
				
		srv.setVar ("update",arrUpdate)
		srv.setVar ("addnew",arrAddNew)
		srv.setVar ("delete",arrDelete)
		
		srv.runAJAX(); 
		
//		this.initialize();
		
		if(srv.response.match(/error/gi)) return false
			else return true;
		

	}

	this.requiredMissing=function(){
		var requires=[];
		for (var i = 0; i < this.fields.length; i++){
			if(this.field(i).required) requires.push(i)
		}
		if(requires.length==0) return -1
		
		this.first();
		while (!this.eof){
			for (var i = 0; i < requires.length; i++){				
				if( this.field(requires[i]).value=='' ){					
					return requires[i]
				}
			}
			this.next();
		}
		
		return -1

	}
	
//	this.initialize();
}


	


