var filterInstances = new Array();

function Filter() {
	//Properties 
	this.AutoRefresh = false;						//true ==> rearma los objetos vinculados (combos)

	//Creation Methods
	this.AddColumn = filter_addColumn;
	this.InsertRow = filter_insertRow;
	
	//Manipulation Methods
	this.SetFilter = filter_setFilter;
	this.GetFilter = filter_getFilter;
	this.ClearFilter = filter_clearFilter;
	this.GetColumn = filter_getColumn;

	this.BindColumn = filter_bindColumn;
	this.OnBindChange = filter_onBindChange;
	this.Populate = filter_populate;				//llena los combos
	this.ResetBindObject = filter_resetBindObject;
	
	//Helper functions
	this.ColumnIndex = filter_columnIndex;
	
	//Initilization Section
	this.nCols = 0;
	this.nRows = 0;
	this.Columns = new Array();
	this.Rows = new Array();
	
	this.instanceNumber = filterInstances.length;
	filterInstances[filterInstances.length] = this;
}

function isNetscape() {
	if (navigator.appName == "Netscape") 
		return true;
	else
		return false;	
}

//Creation definitions
function filter_addColumn(sColumnName) {
	var colIndex = this.ColumnIndex(sColumnName)
	if (colIndex!=null) {
		alert('Ya existe la columna ' + sColumnName);
		return null;
	}
	else {
		this.Columns[this.nCols] = new Array();			//para agregar propiedades
		this.Columns[this.nCols].filtered = false;		//indica si tiene algún filtro aplicado
		this.Columns[this.nCols].name = sColumnName;
		this.Columns[this.nCols].filter = null;			//valor del filtro
		this.Columns[this.nCols].bindObject = null;			
		this.nCols++;
	}
}

//Bindea un objeto html (un COMBO) al Filter, para que este lo
//manipule automáticamente.
//defilterValue especifica cual es el VALUE del objeto
//para el cual la accián será eliminar el filtro
function filter_bindColumn(sColumnName, oBindObject, defilterValue, defilterText, onChangeHandler) {
	var colIndex = this.ColumnIndex(sColumnName)
	if (colIndex==null) {
		alert('No existe la columna ' + sColumnName);
		return null;
	}
	if (oBindObject==null) {
		alert('Argumento inválido oBindObject');
		return null;
	}
	if (defilterValue==null) {
		defilterValue = null;
		defilterText = null;
	}
	if (oBindObject.options.length==0 && defilterValue!=null) {
		if (isNetscape()){
			oOption = new Option(defilterText, defilterValue);
			Act = "oBindObject.options[" + oBindObject.options.length + "]=oOption";
			eval(Act);
		}else{
			o = document.createElement('OPTION');
			o.text = defilterText;
			o.value = defilterValue;
			oBindObject.options.add(o);
		}
	}
	this.Columns[colIndex].bindObject = oBindObject;
	this.Columns[colIndex].defilterValue = defilterValue;
	this.Columns[colIndex].defilterText = defilterText;
	this.Columns[colIndex].onChangeHandler = onChangeHandler;
	oBindObject.onchange = new Function('filter_onBindChange(' + this.instanceNumber + ')'); //this.OnBindChange;
	return true;
}

function filter_onBindChange(filterIndex) {
	var filter = filterInstances[filterIndex];
	var oBindObject = window.event.srcElement;
	var oColumn = null;
	
	for(var i in filter.Columns)
		if (filter.Columns[i].bindObject==oBindObject) {
			oColumn = filter.Columns[i];
			break;
		}
	if (oColumn==null)
		return false;

		
	if (oColumn.defilterValue!=null && oBindObject.value==oColumn.defilterValue ) {
		filter.ClearFilter(oColumn.name)
		filter.ResetBindObject(oColumn, true, true);
	}
	else
		filter.SetFilter(oColumn.name, oBindObject.value, true, true);
		
	for(i in filter.Columns)
		if (filter.Columns[i].bindObject!=oBindObject)
			filter.ResetBindObject(filter.Columns[i], true, true);

	if (oColumn.onChangeHandler!=null) 
		oColumn.onChangeHandler();
}

function filter_resetBindObject(oColumn, bFiltered, bGlobal) {
	var defValue = null, defText = null;
	var colValues = this.GetColumn(oColumn.name, bFiltered, bGlobal)
	var oBindObject = oColumn.bindObject;
	selected = (oBindObject.selectedIndex>0) ? oBindObject.value : null;

	if (isNetscape())
		for(;oBindObject.options.length>0;oBindObject.options[0] = null);
	else
		for(;oBindObject.options.length>0;oBindObject.options.remove(0));

	if (oColumn.defilterValue!=null) {
		AddNewOption(oBindObject, oColumn.defilterValue, oColumn.defilterText);
	}

	for(var i=0;i<colValues.length;i++)
		AddNewOption(oBindObject, colValues[i].code, colValues[i].description);

	if (oBindObject.options.length==2) {
		oBindObject.options[1].selected = true;
		this.SetFilter(oColumn.name, oBindObject.options[1].value);
	}

	if (isNetscape() && oColumn.defilterValue!=null)
		oBindObject.selectedIndex = 0;

}

function filter_populate() {
	for(var i in this.Columns) {
		if (this.Columns[i].bindObject!=null) 
			this.ResetBindObject(this.Columns[i], true, true);
	}
}

function filter_insertRow(vValues) {
	var vRow,i,k;
	if (vValues.length!=2*this.nCols) {
		alert('Se han especificado valores insuficientes para el registro. Debieran especificarse ' + 2*nCols);
		return null;
	}
	else {
		vRow = new Array();
		for(i=0,k=0;i<this.nCols*2;i+=2,k+=2) {
			vRow[i] = vValues[k];		//codigo
			vRow[i+1] = vValues[k+1]	//descripcion
		}
		this.Rows[this.nRows++] = vRow;
	}
	return this.nRows;
}

//Manipulation

//sColumnName	: nombre de la columna a filtrar
//filterValue	: codigo por el que se va a filtrar o null (elimina el filtro)
//Retorna un valor boolean indicando si quedo algun filtro en la columna
function filter_setFilter(sColumnName, filterValue) {
	var colIndex = this.ColumnIndex(sColumnName);
	if (colIndex == null) {
		alert('No existe la columna "'+ sColumnName + '"');
		return null;
	}
	else
		this.Columns[colIndex].filter = filterValue;
}

//Retorna true si la columna tiene algun filtro activo
function filter_getFilter(sColumnName) {
	var colIndex = this.ColumnIndex(sColumnName);
	if (colIndex == null) {
		alert('No existe la columna "'+ sColumnName + '"');
		return null;
	}
	else
		return this.Columns[colIndex].filter != null;
}

//Borra todo los filtros de la columna
function filter_clearFilter(sColumnName) {
	var colIndex = this.ColumnIndex(sColumnName);
	if (colIndex == null) {
		alert('No existe la columna "'+ sColumnName + '"');
		return null;
	}
	else {
		this.Columns[colIndex].filter = null;
		return true;
	}
}

//Retorna un arreglo con los valores de la columna especificada
//si bFiltered es true, retorna solo los valores filtrados y
//si bGlobal es false, solo usando el filtro de esa columna o,
//si bGlobal es true, usando todos los filtros (de las demás columnas)
//El formato del arreglo es R[row][code,description]
function filter_getColumn(sColumnName, bFiltered, bGlobal) {
	var colIndex = this.ColumnIndex(sColumnName);
	if (colIndex == null) {
		alert('No existe la columna "'+ sColumnName + '"');
		return null;
	}
	else {
		var vResult = new Array(), i, k, v;
		
		if(bFiltered==null) bFiltered = true;
		if(bGlobal==null) bGlobal = true;
		
		
		for(i=0;i<this.Rows.length;i++) {
			bAdd = true;
			if (bFiltered) {
				if (bGlobal) {
					for(k=0,col=0;k<this.nCols*2;k+=2,col++) {
						bAdd = bAdd && ((this.Columns[col].filter!=null && this.Rows[i][k]==this.Columns[col].filter) || (this.Columns[col].filter==null));
					}
				}
				else {
					bAdd = (this.Columns[colIndex].filter!=null && this.Rows[i][colIndex*2]==this.Columns[col].filter) || (this.Columns[colIndex].filter==null);
				}
			}

			if (bAdd) {
				//no retorno duplicados
				for(v=0;v<vResult.length;v++) {
					if (vResult[v].code == this.Rows[i][colIndex*2]) {
						bAdd = false;
						break;
					}
				}
				if (bAdd) {
					vResult[vResult.length] = new Array();
					vResult[vResult.length-1].code = this.Rows[i][colIndex*2];
					vResult[vResult.length-1].description = this.Rows[i][colIndex*2+1];
				}
			}
		}
		return vResult;
	}
}


//Helper
function filter_columnIndex(sColumnName) {
	var nCol = 0;
	for(var c in this.Columns) {
		if (sColumnName==this.Columns[c].name) 
			return nCol;
		nCol++;
	}
	return null;
}

//Constructor definition (for use with VBS)
function CreateFilter() {
	return new Filter();
}


function AddNewOption(oSelect,value, text)
{
	if (isNetscape()) {
		oOption = new Option(text, value);
		Act = "document.forms." + oSelect.form.name + "." + oSelect.name + ".options[" + oSelect.options.length + "]=oOption";
		eval(Act);
	}
	else {
		o = document.createElement('OPTION');
		o.text = text;
		o.value = value;
		oSelect.options.add(o);
	}
}