//************** The AQUA Project (AJAX Quick Utilities for Applications)
//************** Author: SICON (http://sicon-it.com)
//*************************************************************************

//************** Collection 
//************************************************************************

function Collection(){
	this.index = 0;
	this.currentIndex = 0;
	this.items = new Array();
	this.add = function(item){
		var _index = this.index;
		this.items[_index] = item;
		this.index++;	
		return _index;
	}
	this.set = function(item,_index){
		this.items[_index] = item;
	}
	this.get = function(_index){
		return this.items[_index];
	}
	this.size = function(){
		return this.items.length;
	}
	this.remove = function(index){
		this.items.splice(index, 1);
		this.index--;
	}
	this.clear = function(){
		this.items = new Array();
		this.index = 0;
		this.currentIndex = 0;
	}
	this.firstIndex = function(){
		if(this.index == 0){
			return null;	
		}else{
			this.currentIndex = 1;
			return 0;
		}
	}
	this.nextIndex = function(){
		if(this.currentIndex == this.index){
			this.currentIndex = 0;
			return null;
		}else{
			var _item = this.items[this.currentIndex];
			this.currentIndex++;
			if(_item){
				return this.currentIndex - 1; 
			}
			return this.nextIndex();
		}
	}
}

//************** StringBuilder 
//*************************************************************************

function StringBuilder(value){
    this.items = new Array("");
	this.append  = function (value){
		if (value){
			this.items.push(value);
		}
	}
	this.clear = function (){
		this.items.length = 1;
	}
	this.toString = function (){
		return this.items.join("");
	}
	this.append(value);
}


//************** CSS Styling 
//*************************************************************************

function Style(){
	this.items = new Collection();
	this.styleString = null;
	this.getItem = function(rule){
		var index = this.items.firstIndex();
		while(index!=null){
			if(this.items.get(index).rule == rule){
				return this.items.get(index).value;
			}
			index = this.items.nextIndex();
		}
		return '';
	}
	this.setItem = function(rule, value){
		var index = this.items.firstIndex();
		while(index!=null){
			if(this.items.get(index).rule == rule){
				this.items.set(new StyleItem(rule,value),index);
				this.items.currentIndex = 0;
				return;
			}
			index = this.items.nextIndex();
		}
		this.items.add(new StyleItem(rule,value));	
	}
	this.setStyleString = function(_value){
		this.styleString = _value;	
	}
	this.toString = function(){
		var str = '';
		if(this.styleString != null){
			str = styleString;
			if(str.lastIndexOf(';') != str.length -1){
				str += ';';	
			}
		}
		var i = this.items.firstIndex();
		while(i!=null){
			str += this.items.get(i).toString();
			i = this.items.nextIndex();
		}
		if(str != ''){
			str = 'style="'+str+'"';	
		}
		return str;
	}
}

function StyleItem(_rule,_value){
	this.rule = _rule;	
	this.value = _value;
	this.toString = function(){
		return this.rule + ':' + this.value + ';';	
	}
}

//************** Events 
//*************************************************************************

function Events(){
	this.events = new Collection();
	this.set = function(event,action){
		var i = this.events.firstIndex();
		while(i!=null){
			if(this.events.get(i).event == event){
				this.events.get(i).action = action;
				this.events.currentIndex = 0;
				return;
			}
			i = this.events.nextIndex();
		}
		this.events.add(new AQUAEvent(event,action));
	}
	this.remove = function(event){
		var i = this.events.firstIndex();
		while(i!=null){
			if(this.events.get(i).event == event){
				this.events.remove(i);
				this.events.currentIndex = 0;
				return;
			}
			i = this.events.nextIndex();
		}
	}
	this.toString = function(){
		var str = '';
		var i = this.events.firstIndex();
		while(i!=null){
			str += this.events.get(i).toString() + ' ';
			i = this.events.nextIndex();
		}
		return str;
	}
}

function AQUAEvent(_event, _action){
	this.event = _event;
	this.action = _action;
	this.toString = function(){
		return this.event + '="' + this.action + '"';
	}
}

//************** OptionSelector 
//*************************************************************************

function OptionSelector(_id, _action){
	this.config = new ConfigurationItem();
	this.id = _id;
	this.action = _action;
	this.options = new Array();
	this.setOption = function(key, text){
		for(var i=0;i<this.options.length;i++){
			if(this.options[i].key == key){
				this.options[i] = new OptionItem(key, text);	
				return;
			}
		}
		this.options[this.options.length] = new OptionItem(key, text);	
	}
	this.toString = function(){
		this.config.prepare();
		var s = '<select onchange="'+this.action+'" id="'+this.id+'" class="'+this.config.css+'" '+this.config.style.toString()+'>';
		var options = '';
		for(var i=0;i<this.options.length;i++){
			options	+= '<option value="'+this.options[i].key+'">'+this.options[i].text+'</option>';
		}
		s += options + '</select>';
		return s;
	}
	
}

function OptionItem(_key, _text){
	this.text = _text;
	this.key = _key;
}


//************** DataGrid 
//*************************************************************************


function GridMap(){}
GridMap.instances = new Collection();

function ConfigurationItem(){
	this.height = '';
	this.css = ''; // Css classes to be aplied (Separete each class with a white space)
	this.style = new Style(); // Specific style properties
	this.visible = true;
	this.prepare = function(){
		if(this.visible){
			this.style.setItem("visibility", "visible");	
		}else{
			this.style.setItem("visibility", "hidden");	
		}
	}
}

function DataGridConfig(){
	
	//--DATAGRID
	this.containerConfig = new ConfigurationItem(); 
	this.containerConfig.css = 'aqua-grid-container';
	this.scrollWidth = 17;
	this.showToolTip = false;
	
	//--TABLES
	this.cellspacing = 0;
	this.cellpadding = 0;
	this.borderWidth = 0;
	
	//--FOOTER
	this.footerConfig = new ConfigurationItem();
	this.footerConfig.visible = true;
	this.footerConfig.height = 20;
	this.footerConfig.css = 'aqua-grid-footer';
	
	//--CAPTION
	this.captionConfig = new ConfigurationItem();
	this.captionConfig.css = 'aqua-grid-caption';
	this.captionConfig.height = 20;
	this.captionConfig.style.setItem("text-align","left");
	this.captionConfig.style.setItem("width","50%");
	
	//--HEADER
	this.headerConfig = new ConfigurationItem();
	this.headerConfig.height = 30;
	this.headerConfig.css = 'aqua-grid-header';
	
	//--PAGING
	this.pagingConfig = new ConfigurationItem();
    this.pagingConfig.NextText = 'Next';
    this.pagingConfig.PreviousText = 'Previous';
    this.pagingConfig.NoRowsText = 'No rows to display'; 
	// [FIRST] = index of the first item/row on the actual viewing page
    // [LAST] = index of the last  item/row on the actual viewing page
    // [TOTAL] = total count of items/rows
    this.pagingConfig.text = 'Showing from [FIRST] to [LAST] of [TOTAL]';   // Page Status text
	this.pagingConfig.style.setItem("text-align","right");
	this.pagingConfig.style.setItem("width","50%");
	this.pagingConfig.css = 'aqua-grid-paging';
	
	//-- BODY
	this.bodyConfig = new ConfigurationItem();
	this.bodyConfig.rowHeight = 20;
	this.bodyConfig.css = 'aqua-grid-body';
	
	this.showSelectedRow = true;
	this.selectedRowColor = '#B9CEFF';
	this.showPagesInFooter = true;
	this.navegationText = 'Go to:&nbsp;';
	
	this.prepare = function(){
		this.containerConfig.prepare();
		this.pagingConfig.prepare();
		this.headerConfig.prepare();
		this.bodyConfig.prepare();
		this.footerConfig.prepare();
		this.captionConfig.prepare();
	}
}

function DataGrid(config){
	
	this.selectedIndex = -1;
	this.selectedRow = null;
	this.config = config;
	if(!this.config){
		this.config = new DataGridConfig();	
	}
	
	//--BEHAVIOR 
	this.allowPaging = false;
	this.pageSize = -1; 
	this.autoSelectRow = true;
	
	//--CONTENT
	this.columnHeaders = new Collection();
	this.dataRows = new Collection();
	this.firstIndex = 0;
	this.lastIndex = 0;
	this.parent = null;
	this.id = GridMap.instances.add(this);
	this.gridModel;
	
	//EVENTS
	this.onRender = function(){}
	
	//CONTENT
	this.footer = '&nbsp;';             	// Footers text/html
	this.caption = '&nbsp;';                // Title displayed on the left top corner of the Grid
	this.bodyHeight = -1;
	
	
	//FUNCTIONS
	this.addDataRow = function(){
		var dataRow = new DataRow();
		this.dataRows.add(dataRow);
		return dataRow;
	}

	this.addColumnHeader = function(_html, _w){
		this.columnHeaders.add(new ColumnHeader(_html,_w));
	}
	
	this.getPagingText = function(){
            
		// [FIRST] = index of the first item/row on the actual viewing page
		// [LAST] = index of the last  item/row on the actual viewing page
		// [TOTAL] = total count of items/rows
		
		if(!(this.config.pagingConfig.visible)){
			return '&nbsp;';
		}
		var size = this.dataRows.size();
		if(size < 1){
			return this.config.pagingConfig.NoRowsText;
		}

		var navigation = '';
		var text = '';
		var from = this.firstIndex + 1;
		var to = this.lastIndex + 1;
		
		text = this.config.pagingConfig.text.replace("[FIRST]", from);
		text = text.replace("[LAST]", to);
		text = text.replace("[TOTAL]", size);
		
		if(this.allowPaging){
			if(from > 1){
				navigation += '<a href="javascript:GridMap.instances.get('+this.id+').render(\'prev\');">' + this.config.pagingConfig.PreviousText + '</a>';	
			}if(to < size){
				if(navigation != '') navigation += '&nbsp;-&nbsp;';
				navigation += '<a href="javascript:GridMap.instances.get('+this.id+').render(\'next\');">' + this.config.pagingConfig.NextText + '</a>';
			}
		}
		
		if(navigation != ''){
			navigation = ' (' + navigation + ')';
			text += navigation;
		}
		return text;		
	}
	
	this.render = function(dir){
		var _firstIndex = 0;
		var _lastIndex = this.dataRows.size()-1;
		if(this.allowPaging){
			if(!dir){
				_lastIndex = (this.lastIndex + (this.pageSize) - 1);
				if(_lastIndex >= this.dataRows.size()){
					_lastIndex = this.dataRows.size()-1;
				}
			}else{
				if(dir == 'next'){
					_firstIndex = this.firstIndex + (this.pageSize);
					_lastIndex = this.lastIndex + (this.pageSize);
					if(_lastIndex >= this.dataRows.size()){
						_lastIndex = this.dataRows.size() - 1;
					}	
				}else if(dir == 'prev'){
					_firstIndex = (this.firstIndex - (this.pageSize));
					_lastIndex = (_firstIndex + (this.pageSize)-1);
					if(_firstIndex < 0){
						_firstIndex = 0;
					}
				}
			}
			this.firstIndex = _firstIndex;
			this.lastIndex = _lastIndex;
			this.do_render(_firstIndex, _lastIndex);
		}else{
			this.firstIndex = _firstIndex;
			this.lastIndex = _lastIndex;
			this.do_render(_firstIndex, _lastIndex);		
		}
	}
	
	this.do_render = function(_firstIndex, _lastIndex){
		var _link = this.getPagingText();
		var headers = new StringBuilder('<tr>');
		var width = 0;
		var i = this.columnHeaders.firstIndex();
		while(i!=null){
			if(this.gridModel.getIsSortableColumn(i)){
				this.columnHeaders.get(i).style.setItem('text-decoration', 'underline');
				this.columnHeaders.get(i).style.setItem('cursor', 'pointer');
				this.columnHeaders.get(i).events.set('onmouseover', 'this.style.textDecoration = \'none\'');
				this.columnHeaders.get(i).events.set('onmouseout', 'this.style.textDecoration = \'underline\'');
				this.columnHeaders.get(i).events.set('onclick', 'GridMap.instances.get('+this.id+').do_sort('+i+')');
			}
			headers.append(this.columnHeaders.get(i).toString());
			width += this.columnHeaders.get(i).width;
			i = this.columnHeaders.nextIndex();
		}
		headers.append('<td class="aqua-grid-scroll"></td></tr>');
		var rows = new StringBuilder('');
		for(var i=_firstIndex;i<=_lastIndex;i++){
			var index = this.dataRows.get(i).dataCells.firstIndex();
			while(index!=null){
				this.dataRows.get(i).dataCells.get(index).style.setItem("width", this.columnHeaders.get(index).width+"px");
				index = this.dataRows.get(i).dataCells.nextIndex();
			}		
			rows.append(this.dataRows.get(i).toString(this.config.showToolTip, this.config.bodyConfig.rowHeight, i, this.id));
		}
		width += parseInt(this.config.borderWidth) + parseInt(this.config.cellspacing * 2) + parseInt(this.config.scrollWidth) + parseInt(this.config.cellpadding * 2);
	    if(this.config.borderWidth > 0) width += (parseInt(this.columnHeaders.size() + 1) * 2) + this.config.borderWidth;
		this.config.containerConfig.style.setItem("width", width + "px");
		this.config.headerConfig.style.setItem("width", (width+this.config.scrollWidth) + "px");
		this.config.bodyConfig.style.setItem("height", ((_lastIndex - _firstIndex)  * this.config.bodyConfig.rowHeight)+"px");
		this.config.bodyConfig.style.setItem("width", width + "px");
		this.config.prepare();
		var html = '<table cellpadding="0" cellspacing="0" border="0" id="aqua_datagrid" '+this.config.containerConfig.style.toString()+' class="'+this.config.containerConfig.css+'">'+
					'	<tr>'+
					'		<td style="height:'+this.config.captionConfig.height+'px;">&nbsp;</td>'+
					'		<td '+this.config.captionConfig.style.toString()+' class="'+this.config.captionConfig.css+'">'+this.caption+'</td>'+
					'		<td '+this.config.pagingConfig.style.toString()+' class="'+this.config.pagingConfig.css+'">'+_link+'</td>'+
					'	</tr>'+
					'	<tr>'+
					'		<td style="height:'+this.config.headerConfig.height+'px;">&nbsp;</td>'+
					'		<td colspan="2">'+
					'				<table '+this.config.headerConfig.style.toString()+' class="'+this.config.headerConfig.css+'" cellpadding="'+this.config.cellpadding+'" cellspacing="'+this.config.cellspacing+'" border="'+this.config.borderWidth+'">'+
					'					<tr>'+
					headers.toString()+
					'					</tr>'+
					'				</table> '+
					'		</td>'+
					'	</tr>'+
					'	<tr>'+
					'		<td style="height:'+this.config.bodyConfig.height+'px;">&nbsp;</td>'+
					'		<td colspan="2">'+
					'			<div style="height:'+this.config.bodyConfig.height+'px; width:'+(width + this.config.scrollWidth)+'px; overflow:auto; margin:0px; text-align:left">'+
					'				<table id="aqua_central_table_'+this.id+'" '+this.config.bodyConfig.style.toString()+' class="'+this.config.bodyConfig.css+'" cellpadding="'+this.config.cellpadding+'" cellspacing="'+this.config.cellspacing+'" border="'+this.config.borderWidth+'">'+
					rows.toString()+
					'				</table> '+
					'			 </div>'+
					'		</td>'+
					'	</tr>';
		if(this.config.footerConfig.visible){
			if(this.allowPaging && this.config.showPagesInFooter){
				html += '	<tr>'+
						'		<td style="height:'+this.config.footerConfig.height+'px;">&nbsp;</td>'+
						'		<td colspan="2" '+this.config.footerConfig.style.toString()+' class="'+this.config.footerConfig.css+'">'+ this.config.navegationText +
						this.getPagesLinks(this.id) +
						'		</td>'+
						'	</tr>';
			}else{
				html += '	<tr>'+
						'		<td style="height:'+this.config.footerConfig.height+'px;">&nbsp;</td>'+
						'		<td colspan="2" '+this.config.footerConfig.style.toString()+' class="'+this.config.footerConfig.css+'">'+
						this.footer +
						'		</td>'+
						'	</tr>';
			}
		}
		html += '</table>';
		this.parent.innerHTML = html;
		if(this.dataRows.size() > 0 && this.allowPaging){
			var i = 1;
			var page_dom = _('grid_'+this.id+'_page_' + i);
			while(page_dom){
				_('grid_'+this.id+'_page_' + i).style.fontWeight = 'normal';
				i++;
				page_dom = _('grid_'+this.id+'_page_' + i);
			}
			var page = (_firstIndex / this.pageSize) + 1;
			_('grid_'+this.id+'_page_'+page).style.fontWeight = 'bold';
		}
		this.onRender();
	}
	
	this.getCellAt = function(rowIndex, cellIndex){
		return _('grid_'+this.id+'_cell_' + rowIndex + '_' + cellIndex);
	}
	
	this.getDataCellAt = function(rowIndex, cellIndex){
		var dr = this.dataRows.get(rowIndex);
		return dr.dataCells.get(cellIndex);
	}
	
	this.setValueAt = function(rowIndex, cellIndex, value){
		this.getCellAt(rowIndex, cellIndex).innerHTML = value;
		this.getDataCellAt(rowIndex, cellIndex).innerHTML = value;
	}
	
	this.setModel = function(gridModel){
		this.gridModel = gridModel;
		this.updateData(true);
		this.gridModel.datagrid = this;
	}
	
	this.updateData = function(updateHeaders){
		var headers = this.gridModel.getColumnsHeaders();
		if(updateHeaders){
			this.columnHeaders.clear();
			for(var index=0;index<headers.length;index++){
				this.addColumnHeader(headers[index], this.gridModel.getHeaderSize(index));
			}
		}
		var collection = this.gridModel.array;
		this.dataRows.clear();
		for(var index=0;index<collection.length;index++){
			var r = this.addDataRow();
			for(var _index=0;_index<headers.length;_index++){
				r.addDataCell(this.gridModel.getValueAt(index,_index));
				var style = this.gridModel.getStyleAt(index,_index);
				if(style){
					var i = style.items.firstIndex();
					while(i!=null){
						var style_item = style.items.get(i);
						r.dataCells.get(_index).style.setItem(style_item.rule, style_item.value);
						i = style.items.nextIndex();
					}	
				}
			}
		}
	}
	
	this.removeDataRow = function(index){
		this.dataRows.remove(index);
		if(this.dataRows.size() > this.lastIndex){
			this.do_render(this.firstIndex, this.lastIndex);
			return;
		}else{
			this.lastIndex--;
			if(this.firstIndex > this.lastIndex){
				this.render('prev');		
				return;
			}
			this.do_render(this.firstIndex, this.lastIndex);
		}
	}
	
	this.selectRow = function(index){
		this.selectedIndex = index;
		if(this.config.showSelectedRow){
			var row = _('grid_'+this.id+'_row_' + index);
			row.style.backgroundColor = this.config.selectedRowColor;
			if(this.selectedRow && row != this.selectedRow){
				var r = this.dataRows.get(index);
				this.selectedRow.style.backgroundColor = r.style.getItem('background-color');
			}
			this.selectedRow = row;
		}
	}
	
	this.goToPage = function(page){
		var pages = this.dataRows.size() / this.config.pageSize;
		pages = Math.round(pages + 0.49);
		if(page > pages){
			throw "Page index out of bounds";	
		}
		var fL = (page * this.pageSize);
		var fI = fL - this.pageSize;
		fL = fL - 1;
		if(fL > (this.dataRows.size()-1)){
			fL = this.dataRows.size()-1;
		}
		this.firstIndex = fI;
		this.lastIndex = fL;
		this.do_render(fI, fL);
		var i = 1;
		var page_dom = _('grid_'+this.id+'_page_' + i);
		while(page_dom){
			_('grid_'+this.id+'_page_' + i).style.fontWeight = 'normal';
			i++;
			page_dom = _('grid_'+this.id+'_page_' + i);
		}
		_('grid_'+this.id+'_page_' + page).style.fontWeight = 'bold';
	}
	
	this.getPagesLinks = function(id){
		var pages = this.dataRows.size() / this.pageSize;
		pages = Math.round(pages + 0.49);
		var str = '';
		var style = 'style="font-weight:bold;"';
		for(var i=1;i<=pages;i++){
			str += '<a '+style+' id="grid_'+this.id+'_page_'+i+'" href="javascript:GridMap.instances.get('+id+').goToPage('+i+')">'+i+'</a>&nbsp;';	
			style = '';
		}
		return str;
	}
	
	this.do_sort = function(headerIndex){
		var s = this.columnHeaders.get(headerIndex).getSorter();
		s.index = headerIndex;
		s.model = this.gridModel;
		s.do_sort();
		this.lastIndex = 0;
		this.firstIndex = 0;
		this.updateData(false);
		this.render();
	}
	
}

function ColumnHeader(_innerHTML, _width){
	this.sorter = null;
	this.innerHTML = _innerHTML;
	this.events = new Events();
	this.style = new Style();
	this.style.setItem("width", _width + "px");
	this.width = _width;
	this.toString = function(){
		return '<td '+this.events.toString()+' '+this.style.toString()+'><div style="overflow:hidden; width:100%">'+this.innerHTML+'</div></td>';
	}
	this.getSorter = function(){
		if(!this.sorter){
			this.sorter = new DataGridSorter();	
		}
		return this.sorter;
	}
}
	
function DataRow(){
	this.dataCells = new Collection();
	this.events = new Events();
	this.style = new Style(); // Specific style for the current row
	this.addDataCell = function(_html){
		this.dataCells.add(new DataCell(_html));
	}	
	this.toString = function(show, rowHeight, _index, id){
		var str = '<tr id="grid_'+id+'_row_'+_index+'" onclick="GridMap.instances.get('+id+').selectRow('+_index+')" '+this.events.toString()+' '+this.style.toString()+'><td style="height:'+rowHeight+'px"></td>';
		var i = this.dataCells.firstIndex();
		while(i!=null){
			str += this.dataCells.get(i).toString(show, _index, i, id);
			i = this.dataCells.nextIndex();
		}
		return str += '</tr>';
	}
}

function DataCell(_innerHTML){
	this.style = new Style(); // Specific style for the current cell
	this.events = new Events();
	this.innerHTML = _innerHTML;
	this.toString = function(showTip, rowIndex, cellIndex, grid_id){
		var width = parseInt(this.style.getItem('width').replace('px', ''));
		var left = parseInt(this.style.getItem('padding-left').replace('px', ''));
		var right = parseInt(this.style.getItem('padding-right').replace('px', ''));
		if(left){
			width = width - parseInt(left);
		}else{
			width = width - 5;	
		}
		width -= 5;
		if(right){
			width = width - parseInt(right);
		}
		if(this.innerHTML.indexOf('</') != -1 || this.innerHTML.indexOf('/>') != -1){		
			return '<td id="grid_'+grid_id+'_cell_'+rowIndex+'_'+cellIndex+'" '+this.events.toString()+' '+this.style.toString()+'><div style="overflow:hidden; width:'+width+'px">'+this.innerHTML+'</div></td>';	
		}else{
			if(showTip){
				this.events.set('onmouseover', 'ShowTip(event)');
			}
			return '<td id="grid_'+grid_id+'_cell_'+rowIndex+'_'+cellIndex+'" '+this.events.toString()+' '+this.style.toString()+'><div style="overflow:hidden; width:'+width+'px">'+this.innerHTML+'</div></td>';
		}
	}
}

function GridModel(array){
	this.array = array;
	this.getIsSortableColumn = function(headerIndex){
		return false;	
	}
	this.getColumnsHeaders = function(){
		throw "This method must be implemented by the custom model";	
	}
	this.getHeaderWidth = function(headerIndex){
		throw "This method must be implemented by the custom model";	
	}
	this.getValueAt = function(rowIndex, cellIndex){
		throw "This method must be implemented by the custom model";	
	}
	this.getDecodedValueAt = function(rowIndex, cellIndex){
		throw "This method must be implemented by the custom model";	
	}
	this.getSortTypeAt = function(cellIndex){
		return DataGridSorter.STRING;	
	}
	this.getStyleAt = function(rowIndex, cellIndex){
		return false;
	}
}

//************** SORTER
//*************************************************************************

var ACTIVE_SORTER = null;
function DataGridSorter(){
	this.index;
	this.model;
	this.dir = 'ASC';
	this.do_sort = function(){
		ACTIVE_SORTER = this;
		AQUA_quick_sort(this.model.array);
		if(this.dir == 'ASC'){
			this.dir = 'DESC';				
		}else{
			this.dir = 'ASC';	
		}
	}
}

DataGridSorter.STRING = 1;
DataGridSorter.INT = 2;
DataGridSorter.FLOAT = 3;
DataGridSorter.DATE = 4;
DataGridSorter.DATE_TIME = 5;

function AQUA_array_swap(array, a, b)
{
	var tmp=array[a];
	array[a]=array[b];
	array[b]=tmp;
	return array;
}


function AQUA_partition(array, begin, end, pivot)
{
	var piv=ACTIVE_SORTER.model.getDecodedValueAt(pivot, ACTIVE_SORTER.index);
	if(ACTIVE_SORTER.model.getSortTypeAt(ACTIVE_SORTER.index) == DataGridSorter.STRING){
		piv = piv.toLowerCase();	
	}else if(ACTIVE_SORTER.model.getSortTypeAt(ACTIVE_SORTER.index) == DataGridSorter.INT){
		piv = parseInt(piv);	
	}else if(ACTIVE_SORTER.model.getSortTypeAt(ACTIVE_SORTER.index) == DataGridSorter.FLOAT){
		piv = parseFloat(piv);	
	}
	array = AQUA_array_swap(array, pivot, end-1);
	var store=begin;
	var ix;
	for(ix=begin; ix<end-1; ++ix) {
		if(ACTIVE_SORTER.dir == 'ASC'){
			var _piv=ACTIVE_SORTER.model.getDecodedValueAt(ix, ACTIVE_SORTER.index);
			if(ACTIVE_SORTER.model.getSortTypeAt(ACTIVE_SORTER.index) == DataGridSorter.STRING){
				_piv = _piv.toLowerCase();	
			}else if(ACTIVE_SORTER.model.getSortTypeAt(ACTIVE_SORTER.index) == DataGridSorter.INT){
				_piv = parseInt(_piv);	
			}else if(ACTIVE_SORTER.model.getSortTypeAt(ACTIVE_SORTER.index) == DataGridSorter.FLOAT){
				_piv = parseFloat(_piv);	
			}
			if(_piv<=piv) {
				array = AQUA_array_swap(array, store, ix);
				++store;
			}
		}else{
			var _piv=ACTIVE_SORTER.model.getDecodedValueAt(ix, ACTIVE_SORTER.index);
			if(ACTIVE_SORTER.model.getSortTypeAt(ACTIVE_SORTER.index) == DataGridSorter.STRING){
				_piv = _piv.toLowerCase();	
			}else if(ACTIVE_SORTER.model.getSortTypeAt(ACTIVE_SORTER.index) == DataGridSorter.INT){
				_piv = parseInt(_piv);	
			}else if(ACTIVE_SORTER.model.getSortTypeAt(ACTIVE_SORTER.index) == DataGridSorter.FLOAT){
				_piv = parseFloat(_piv);	
			}
			if(_piv>=piv) {
				array = AQUA_array_swap(array, store, ix);
				++store;
			}
		}
	}
	array = AQUA_array_swap(array, end-1, store);
	return store;
}


function AQUA_qsort(array, begin, end)
{
	if(end-1>begin) {
		var pivot=begin+Math.floor((end-begin)/2);
		pivot=AQUA_partition(array, begin, end, pivot);
		AQUA_qsort(array, begin, pivot);
		AQUA_qsort(array, pivot+1, end);
	}
}


function AQUA_quick_sort(array)
{
	AQUA_qsort(array, 0, array.length);
}

	
//************** AJAX 
//*************************************************************************

var error_url = 'feedback.jsp';

function AQUAX(){
	this.xhr = null;
	this.a = false;
	this.loading = false;
	this.method;
	this.url;
	this.params = new Array();
	this.callback_method;
	this.addParam = function(key,value){
		this.params[this.params.length] = new Param(key,value);
	}
	this.send = function(){
		var _url = '?ajax=true';
		for(var i=0;i<this.params.length;i++){
			_url += this.params[i];	
		}
		this.xhr = newXMLHttpRequest();
		var oncallback = this.oncallback;
		var callback_method = this.callback_method;
		var _this = this;
		if(this.method == AQUAX.GET){
			this.xhr.open(this.method, this.url + _url, true);
			this.xhr.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
			this.xhr.onreadystatechange = function(){oncallback(callback_method, _this);}
			this.loading = true;
			this.xhr.send(null);
		}else if(this.method == AQUAX.POST){
			this.xhr.open(this.method, this.url, true);
			this.xhr.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"); 
			this.xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			this.xhr.setRequestHeader("Content-length", _url.length);
			this.xhr.setRequestHeader("Connection", "close");	
			this.xhr.onreadystatechange = function(){oncallback(callback_method, _this);}
			this.loading = true;
			this.xhr.send(_url.replace('?',''));
		}else{
			throw "Invalid Ajax method";	
		}
	}
	this.oncallback = function(callback_method, __active_aquax){
		if (__active_aquax.xhr.readyState == 4) {
			__active_aquax.loading = false;
			var text = __active_aquax.xhr.responseText;
			try{
				if(text){
					var object = eval('('+text+')');
					if(object.type == "error"){
						window.onbeforeunload = function(){}
						document.location.href = error_url;
					}else if(object.type == "ok"){							
						callback_method(object);
					}
				}else{
					callback_method(null);
				}
			}catch(E){}
		}	
	}
	this.abort = function(){
		this.xhr.abort();
		this.loading = false;
	}
}

AQUAX.GET = "GET";
AQUAX.POST = "POST";
AQUAX.parseObject = function(r){
	return Transport.parseObject(eval('('+r.value+')'));	
}
AQUAX.parseList = function(r){
	return Transport.parseList(eval('('+r.value+')'));	
}

function Param(_key, _value){
	this.key = _key;
	this.value = _value;
	this.toString = function(){
		if(!this.value.serialize){
			return "&" + this.key + "=" + this.value;
		}else{
			return "&" + this.key + "=" + this.value.serialize();
		}
	}
}

function newXMLHttpRequest(){
	try {
		var xhr = new ActiveXObject("Msxml2.XMLHTTP");
	} catch (e) {
		try {
			xhr = new ActiveXObject("Microsoft.XMLHTTP");
		} catch (E) {
			xhr = false;
		}
	}
	if (!xhr && typeof XMLHttpRequest != 'undefined') {
		xhr = new XMLHttpRequest();
	}
	return xhr;
}

//************** DIALOG
//*************************************************************************

function DialogConfig(){
	this.showHeader = true;
	this.showTitle = true;
	this.showCloseButton = true;
	this.closeOnOutClick = false;
	this.alertOnRender = true;
	this.alertOnOutClick = true;
	this.dialogCss = 'aqua-dialog-div';
	this.dialogOffCss = 'aqua-dialog-div-off';
	this.dialogStyle = new Style();
	this.dialogStyle.setItem('width', '500px');
	this.dialogStyle.setItem('height', '100px');
	this.headerStyle = new Style();
	this.backgroundStyle = new Style();
	this.backgroundCss = 'aqua-screen-transblock';
	this.actionOnCss = 'dialog-action-on';
	this.actionCss = 'dialog-action';
}

function Dialog(_config){
	if(!_config)_config = new DialogConfig();
	this.config = _config;
	this.actions = new Collection();
	this.html = '';
	this.autoFit = false;
	this.image;
	this.title;
	this.addAction = function(text, action, img){
		this.actions.add(new DialogAction(text, img, action));
	}
	this.prepare = function(){
		var div = document.createElement('div');
		div.id = 'screen_block';
		div.className = this.config.backgroundCss;
		div.style.height = getPageAttributes()[1] + 'px';
		var container = document.createElement('div');
		container.id = 'dialog_container';
		container.className = 'aqua-dialog-container';
		var dialog = document.createElement('div');
		dialog.id = 'dialog_div';
		var style = this.config.dialogStyle.toString().replace('style="', '').replace('"', '');
		container.innerHTML = '<table id="table_dialog" cellpadding="0" border="0" cellspacing="0" class="noneborder" style="width:100%; height:'+parseInt(getPageAttributes()[3])+'px">'+
							  ' 	<tr><td colspan="2" id="cell_scroll"></td></tr>'+
							  '    <tr><td style="width:1px;"></td>'+
							  '    <td id="cell_dialog"></td></tr>'+
							  ' 	<tr><td colspan="2" id="cell_bottom"></td></tr>'+
							  '</table>';
		container.onclick = function(event){
			var src = null;
			if(window.event){
				src = window.event.srcElement;
			}else{
				src = event.target;	
			}
			if(src.id == 'cell_dialog' || src.id == 'cell_scroll' || src.id == 'cell_bottom' || src.id == 'aqua_dialog_contentiner'){
				alert_dialog(4,true);	
			}
		}
		div.onclick = function(event){
			var src = null;
			if(window.event){
				src = window.event.srcElement;
			}else{
				src = event.target;	
			}
			if(src.id == 'screen_block'){
				alert_dialog(4,true);	
			}
		}
		container.style.height = getPageAttributes()[1] + 'px';
		_('body','tag')[0].appendChild(div);
		_('body','tag')[0].appendChild(container);
		_('cell_scroll').style.height = getPageScroll() + 'px';
		_('cell_dialog').style.height = getPageAttributes()[3] + 'px';
		var hh = (parseInt(getPageAttributes()[1]) - parseInt(getPageScroll()) - parseInt(getPageAttributes()[3]));
		if(hh < 0)hh=0;
		_('cell_bottom').style.height = hh + 'px';
		document.getElementById('cell_dialog').appendChild(dialog);
	}
	this.update = function(){
		var dialog = _('dialog_div');
		var style = this.config.dialogStyle.toString().replace('style="', '').replace('"', '');
		dialog.style.cssText = style;
		dialog.setAttribute('style', style);
		document.getElementById('cell_dialog').appendChild(dialog);	  
	}
	this.hide = function(){
		if(_('dialog_container')){
			_('body','tag')[0].removeChild(_('dialog_container'));
			_('body','tag')[0].removeChild(_('screen_block'));
			var nav = navigator.userAgent;
			if(nav.indexOf('MSIE') != -1){			
				var b = _('body', 'tag')[0];
				b.onkeydown = function(){window.event.returnValue = true;}
			}else{
				window.onkeydown = function(evt){return true;}
			}
		}
		//AQUA_toggleFlash('visible');
		window.onresize = function(){}
	}
	this.isVisible = function(){
		return _('dialog_container');
	}
	this.render = function(){
		//AQUA_toggleFlash('hide');
		if(!_('screen_block')){
			this.prepare();
		}else{
			//this.update();	
		}
		var html = '';
		var image_html = '';
		if(this.image){
			image_html = '<tr><td><table  class="noneborder" cellpadding="0" cellspacing="0" border="0"><tr><td class="aqua_dialog_image"><img src="'+this.image+'" /></td><td class="aqua_dialog_title" style="width:100%;">'+this.title+'</td></tr></table></td></tr>';
		}else if(this.title){
			image_html = '<tr><td><table  class="noneborder" cellpadding="0" cellspacing="0" border="0"><tr><td class="aqua_dialog_image"><img src="dialog/que.png" /></td><td class="aqua_dialog_title" style="width:100%">'+this.title+'</td></tr></table></td></tr>';
		}
		var style_box = '';
		if(!this.config.autoFit){
			style_box += "width:" + this.config.dialogStyle.getItem('width') + ";";
			style_box += "height:" + this.config.dialogStyle.getItem('height') + ";";
		}
		var actions_height = '0px';
		var actions_html = '';
		if(this.actions.size() > 0){
			actions_height = '40px';
			var actions = '';
			var index = this.actions.firstIndex();
			var sep = '';
			while(index!=null){
				var style = '';
				if(this.actions.get(index).image){
					style = 'style="background-image:URL('+this.actions.get(index).image+')"';
				}
				actions += sep + '<td><input onclick="'+this.actions.get(index).action+'" onmouseover="this.className = \''+this.config.actionOnCss+'\'" onmouseout="this.className = \''+this.config.actionCss+'\'" type="button" class="'+this.config.actionCss+'" value="'+this.actions.get(index).text+'" '+style+'a /></td>';
				sep = '<td style="width:20px"></td>';
				index = this.actions.nextIndex();
			}
			actions_html = '<div style="width:100%;"><table  class="noneborder" cellspacing="0" cellpadding="0" border="0" style="margin:0 auto;">'+
					   '	<tr>'+actions +
					   '	</tr>'+
					   '</table></div>';
			
		}
		var html =		  '<div id="aqua_dialog_contentiner" style="padding:20px">'+
						  '	<table cellpadding="0" cellspacing="0" border="0" style="margin:0 auto; margin-top:0px; width:auto">'+
						  '		<tr>'+
						  '			<td style="background-image:url(dialog/red-bg.png); width:20px; height:20px;"></td>'+
						  '			<td style="background-image:url(dialog/red-bgcolor.png);"></td>'+
						  '			<td style="background-image:url(dialog/red-bg.png); background-repeat:no-repeat; width:20px; height:20px; background-position:-20px 0px"></td>'+
						  '		</tr>'+
						  ' 		<tr>'+
						  '			<td style="background-image:url(dialog/red-bgcolor.png); width:20px;"></td>'+
						  '			<td class="aqua_active_dialog" id="aqua_dialog_content" style="'+style_box+'">'+
						  '				<table cellpadding="0" cellspacing="0" border="0" style="margin-top:0px;">'+ image_html + 
						  '					<tr><td class="aqua_dialog_html">'+this.html+'</td></tr>'+
						  '					<tr><td class="aqua_dialog_actions" style="text-align:right">'+actions_html+'</td></tr>'+
						  '				</table>'+
						  '			</td>'+
						  '			<td style="background-image:url(dialog/red-bgcolor.png); width:20px;"></td>'+
						  '		</tr>'+
						  '		<tr>'+
						  '			<td style="background-image:url(dialog/red-bg.png); width:20px; height:20px; background-position:0px -20px"></td>'+
						  '			<td style="background-image:url(dialog/red-bgcolor.png);"></td>'+
						  '			<td style="background-image:url(dialog/red-bg.png); width:20px; height:20px; background-position:20px -20px"></td>'+
						  '		</tr>'+
						  '	</table>'+
						  '</div>';
		_('dialog_div').innerHTML = html;
		var nav = navigator.userAgent;
		if(nav.indexOf('MSIE') != -1){
			_('dialog_div').focus();
			var b = _('body', 'tag')[0];
			b.onkeydown = function(){
				var evt = window.event;	
				var charCode = (evt.which) ? evt.which : evt.keyCode;
				if(charCode == 9){
					AQUA_CD_focusedElement.setAttribute('focused', null);
					AQUA_CD_focusedElement = document.activeElement;
					AQUA_CD_focusedElement.setAttribute('focused', "focused");
					AQUA_CD_focusElement();	
					evt.cancelBubble = true;
					evt.returnValue = false;
				}			
			}
		}else{
			document.getElementsByTagName("body")[0].blur();
			window.onkeydown = function(evt){
				var charCode = (evt.which) ? evt.which : evt.keyCode;
				if(charCode == 9){
					AQUA_CD_focusedElement.setAttribute('focused', null);
					AQUA_CD_focusedElement = document.activeElement;
					AQUA_CD_focusedElement.setAttribute('focused', "focused");
					AQUA_CD_focusElement();
					evt.preventDefault();
				}
			}
		}
		AQUA_CD_focusedElement = null;
		AQUA_CD_focusElement();
		alert_dialog(4, true);
		window.onresize = function(){
			_('screen_block').style.height = getPageAttributes()[1] + 'px';
			_('dialog_container').style.height = getPageAttributes()[1] + 'px';
			if((parseInt(getPageAttributes()[1]) - parseInt(getPageScroll()) - parseInt(getPageAttributes()[3])) > 0){
				_('cell_bottom').style.height = (parseInt(getPageAttributes()[1]) - parseInt(getPageScroll()) - parseInt(getPageAttributes()[3])) + 'px';
				_('cell_scroll').style.height = getPageScroll() + 'px';
				_('cell_dialog').style.height = getPageAttributes()[3] + 'px';
			}
		}
	}
}

function alert_dialog(i, v){
	if(_('aqua_dialog_content')){
		if(v){
			_('aqua_dialog_content').className = 'aqua_active_dialog';
		}else{
			_('aqua_dialog_content').className = 'aqua_inactive_dialog';
		}
		if(i>0){
			window.setTimeout('alert_dialog('+(i-1)+', '+!v+')', 50);
		}
	}
}

Dialog.prototype.disableActions = function(){
	var i = 0;
	while(_('dialog-action-' + i)){
		_('dialog-action-' + i).disabled = true;
		i++;
	}
}

Dialog.prototype.enableActions = function(){
	var i = 0;
	while(_('dialog-action-' + i)){
		_('dialog-action-' + i).disabled = false;
		i++;
	}
}


function DialogAction(_text, _image, _action){
	this.image = _image;
	this.text = _text;
	this.action = _action;
}

function AQUA_CD_focusElement(){	
	AQUA_CD_setNextFocusedElement();
	if(AQUA_CD_focusedElement){
		AQUA_CD_focusedElement.focus();
	}else{
		AQUA_CD_setNextFocusedElement();
		if(AQUA_CD_focusedElement){
			AQUA_CD_focusedElement.focus();	
		}
	}
}

function AQUA_CD_setNextFocusedElement()
{
  var domElement = _('dialog_div');
  AQUA_CD_setNextFocusedElement_rec(domElement, 1);
}

function AQUA_CD_setNextFocusedElement_rec(currentElement, depth)
{
  if (currentElement)
  {
    var j;
    var tagName=currentElement.tagName;
	if(tagName){
		var disabled = currentElement.disabled;
		if(tagName.toLowerCase() == 'a' || tagName.toLowerCase() == 'input' || tagName.toLowerCase() == 'select' || tagName.toLowerCase() == 'textarea' || tagName.toLowerCase() == 'button' || tagName.toLowerCase() == 'object'){
			if(!disabled && !AQUA_isHidden(currentElement)){
				if(AQUA_CD_focusedElement == null){
					AQUA_CD_focusedElement = currentElement;
					AQUA_CD_focusedElement.setAttribute('focused', "focused");
					return;
				}else if(currentElement.getAttribute('focused') != null){
					if(currentElement.getAttribute('focused') == "focused"){
						currentElement.setAttribute('focused', null);
						AQUA_CD_focusedElement = null;
					}
				}
			}
		}
	}
    var i=0;
    var currentElementChild=currentElement.childNodes[i];
    while (currentElementChild)
    {
      AQUA_CD_setNextFocusedElement_rec(currentElementChild, depth+1);
      i++;
      currentElementChild=currentElement.childNodes[i];
    }
  }
}

function AQUA_isHidden(el){
	while(el){
		if(el.style){
			if(el.style.visibility == 'hidden' || el.style.display == 'none'){
				return true;	
			}
		}
		el = el.parentNode;
	}
	return false;
}

//************** TRANSPORT 
//*************************************************************************


function Transport(_class){
	this._class = _class;
	this.properties = new Array();
	this.objects = new Array();
	this.setProperty = function(key, value){
		for(var i=0;i<this.properties.length;i++){
			if(this.properties[i].key == key){
				this.properties[i] = new TransportProperty(key, value);	
				return;
			}
		}
		this.properties[this.properties.length] = new TransportProperty(key, value);	
	}
	this.setProperties = function(props){
		for(var i=0;i<props.length;i++){
			if(!isEmpty(props[i][1])){
				this.setProperty(props[i][0], props[i][1]);	
			}else{
				this.removeProperty(props[i][0]);	
			}
		}
	}
	this.setObject = function(key, o){
		for(var i=0;i<this.objects.length;i++){
			if(this.objects[i].key == key){
				this.objects[i] = new TransportObject(key, o);
				return;
			}
		}
		this.objects[this.objects.length] = new TransportObject(key, o);
	}
	this.removeObject = function(key){
		for(var i=0;i<this.objects.length;i++){
			if(this.objects[i].key == key){
				this.objects.splice(i, 1);
				return;
			}
		}
	}
	this.removeProperty = function(key){
		for(var i=0;i<this.properties.length;i++){
			if(this.properties[i].key == key){
				this.properties.splice(i, 1);
				return;
			}
		}
	}
	this.getProperty = function(key){
		for(var i=0;i<this.properties.length;i++){
			if(this.properties[i].key == key){
				return this.properties[i].value;
			}
		}
		return null;
	}
	this.$ = function(key, alt){
		var v = this.getProperty(key);
		if(v == null){
			if(alt)return alt;
			return '';
		}else{
			return v.decoded();
		}
	}
	this.h$ = function(key, alt){
		var v = this.getProperty(key);
		if(v == null){
			if(alt)return alt;
			return '';
		}else{
			return v.html();
		}
	}
	this.o$ = function(key){
		var _ob = this.getObject(key);
		if(_ob){
			try{
				var ob = Transport.parseObject(_ob);	
				return ob;
			}catch(e){
				return _ob;
			}
		}else{
			return null;	
		}
	}
	this.getObject = function(key){
		for(var i=0;i<this.objects.length;i++){
			if(this.objects[i].key == key){
				return this.objects[i].value;
			}
		}
		return null;
	}
	this.toXML = function(){
		var obj = '<object class="quartzoft.ajax.transport.Transport">';
		obj += '<void property="_class"><string>'+this._class+'</string></void>';
		
		var strprops = '<object class="java.util.ArrayList">';
		for(var i=0;i<this.properties.length;i++){
			strprops += '<void method="add"><object class="quartzoft.ajax.transport.TransportProperty">'+
			'<void property="key"><string>'+this.properties[i].key+'</string></void>'+
			'<void property="value"><string>'+this.properties[i].value.decimal()+'</string></void></object></void>';
		}
		strprops += '</object>';		
		var strobjs = '<object class="java.util.ArrayList">';
		for(var i=0;i<this.objects.length;i++){
			var _obj = this.objects[i];
			strobjs += '<void method="add"><object class="quartzoft.ajax.transport.TransportObject">'+
			'<void property="key"><string>'+_obj.key+'</string></void>';
			var _value = _obj.value;
			if(_obj.value._class){
				var auxt = Transport.parseObject(_obj.value);
				_value = auxt.toXML();
			}else if(_obj.value.constructor.toString().indexOf("function Array") != -1){
				var list = Transport.parseList(_obj.value);
				_value = '<object class="java.util.ArrayList">';
				for(var c=0;c<list.length;c++){
					if(list[c].toXML){
						_value += '<void method="add">' + list[c].toXML() + '</void>';	
					}
				}	
				_value += '</object>';
			}
			strobjs += '<void property="value">'+_value+'</void></object></void>';
		}
		strobjs += '</object>';
		obj += '<void property="properties">'+strprops+'</void>';
		obj += '<void property="objects">'+strobjs+'</void>';
		obj += '</object>';
		return obj;

	}
	this.serialize = function(){
		var xml = '<?xml version="1.0" encoding="UTF-8"?><java version="1.5.0_04" class="java.beans.XMLDecoder">' + this.toXML() + '</java>';
		return xml;
	}
	this.save = function(callback, do_reload){
		var ajax = new AQUAX();
		ajax.method = AQUAX.POST;
		ajax.url = '../servlets/SrvGeneral';
		ajax.callback_method = callback;
		ajax.addParam('reload', do_reload);
		ajax.addParam('Transport', this);
		ajax.send();
	}
}

function TransportProperty(_key, _value){
	this.key = _key;
	this.value = new Encoder(_value);
}

function TransportObject(_key, _value){
	this.key = _key;
	this.value = _value;
}

Transport.parseObject = function(_t){
	if(!_t.toXML){
		var t = new Transport(_t._class);
		for(var i=0;i<_t.properties.length;i++){
			t.setProperty(_t.properties[i].key, _t.properties[i].DECIMALEncodedValue);
		}
		for(var i=0;i<_t.objects.length;i++){
			t.setObject(_t.objects[i].key, _t.objects[i].value);
		}
		return t;
	}else{
		return _t;	
	}
}

Transport.parseList = function(list){
	var _list = new Array();
	for(var i=0;i<list.length;i++){
		_list[i] = Transport.parseObject(list[i]);	
	}
	return _list;
}


//************** ENCODER 
//*************************************************************************

function Encoder(s){
	var original_value = s;
	original_value = decode();
	var dec_encoded_value = null;
	var html_encoded_value = null;
    this.getDecodedValue = function(){
		return original_value;
	}
	this.decimal = function(){
		if(dec_encoded_value == null){
			dec_encoded_value = encode(Encoder.Types.DEC);
		}
		return dec_encoded_value;
	}
	this.html = function(){
		if(html_encoded_value == null){
			html_encoded_value = encode(Encoder.Types.HTML);
		}
		return html_encoded_value;
	}
	this.decoded = function(){
		return decode();
	}
	function encode(type){
		if(original_value.length > 0){
			if(type == Encoder.Types.DEC){
				var encoded = "";
				for(var i=0;i<original_value.length;i++){
					encoded += original_value.charCodeAt(i) + ",";
				}
				return "DEC:ENCODED:" + encoded.substring(0, encoded.length - 1);	
			}else if(type == Encoder.Types.HTML){
				var encoded = "";
				for(var i=0;i<original_value.length;i++){
					if(original_value.charCodeAt(i) == 10){
						encoded += "<br />";
					}else{
						encoded += "&#" + original_value.charCodeAt(i) + ";";
					}
				}
				return encoded;
			}
		}else{
			return "";	
		}
	}
	function decode(){
		if(original_value.indexOf("ENCODED") == -1){
			return original_value;	
		}else{
			var codes = original_value.replace("DEC:ENCODED:", "");
			codes = codes.split(",");
			var decoded = "";
			for(var i=0;i<codes.length;i++){
				decoded += String.fromCharCode(codes[i]);
			}
			return decoded;	
		}
	}
	this.isEmpty = function(){
		if(original_value.length > 100)return false;
		var codes = this.decimal().replace('DEC:ENCODED:', '');
		codes = codes.split(",");
		if(codes.length == 0)return true;
		for(var i=0;i<codes.length;i++){
			if(codes[i] != 160 && codes[i] != '' && codes[i] != 32){
				return false;	
			}
		}
		return true;	
	}
}

Encoder.Types = function(){}
Encoder.Types.DEC = 1;
Encoder.Types.HTML = 2;
Encoder.Types.DECODED = 3;


//************** Drop Down Menu 
//*************************************************************************

function DropDownMenu(_id, _width, _title, _cell_cssOn, _cell_cssOff){
	this.DOM = null;
	this.id = _id;
	this.title = _title;
	this.width = _width;
	this.menuItems = new ItemCollection(this);
	this.cell_cssOn = _cell_cssOn;
	this.cell_cssOff = _cell_cssOff;
	this.show = function(top,left){
		if(this.DOM == null){
			var table = document.createElement("table");
			table.id = "ultrod_DDM";
			table.style.width = this.width + "px";
			table.cellPadding = "0px";
			table.cellSpacing = "0px";
			table.border = 0;
			var row = null;
			var cell = null;
			if(this.title != null){
				row = table.insertRow(-1);
				cell = row.insertCell(-1);
				cell.innerHTML = "&nbsp;" + this.title;
				row.id = "header_DDM"
			}
			for(var i=0;i<this.menuItems.size();i++){
				var item = this.menuItems.at(i);
				row = table.insertRow(-1);	
				cell = row.insertCell(-1);
				DDM_addLinkEvents(cell, item, this);
				row.className = "row_DDM";
				cell.className = this.cell_cssOff;
				var link = document.createElement("div");
				cell.id = 'link_DDM' + i;
				link.className = "link_DDM";
				cell.style.verticalAlign = "middle";
				cell.valign = "middel";
				link.href = 'javascript:void(0)';
				cell.appendChild(link);
				link.style.width = this.width;
				link.innerHTML = '<div><table cellspacing="0" cellpadding="0" border="0" class="table_link_DDM">'+
								    '<tr>'+
									'	<td rowspan="2"><img id="img_DDM'+i+'" src="'+item.iconoff+'" border="0" /></td>'+
									'	<td class="cell_text_DDM">'+item.text+'</td>'+
									'</tr>'+
									'<tr>'+
									'	<td class="cell_help_DDM">'+item.help+'</td>'+
									'</tr>'+
								 '</table></div>';
			}
			this.DOM = table;
		}
		var owner = document.createElement("div");
		owner.style.position = 'absolute';
		owner.style.left = left + "px";
		owner.style.top = top + "px";
		owner.appendChild(this.DOM);
		owner.id = this.id;
		owner.className = "faded_DDM";
		DDM_addEvents(owner);
		if(document.getElementById(this.id)){
			this.hide();						   
		}
		document.getElementsByTagName("body")[0].appendChild(owner);
		if(navigator.userAgent.indexOf('MSIE') != -1){
			owner.focus();
		}else{
			document.getElementsByTagName("body")[0].blur();
		}
	}
	this.hide = function(){
		if(document.getElementById(this.id)){
			document.getElementsByTagName("body")[0].removeChild(document.getElementById(this.id));
		}
	}
}

function DDM_addLinkEvents(cell, item, dmm){
	cell.onmouseover = function(){ 
		cell.className = ddm.cell_cssOn; 
		_(cell.id.replace('link_DDM', 'img_DDM')).src = item.iconon;
	}
	cell.onmouseout = function(){ 
		cell.className = ddm.cell_cssOff; 
		_(cell.id.replace('link_DDM', 'img_DDM')).src = item.iconoff;
	}
	cell.onclick = function(){ document.location.href = item.action; } 
}

function DDM_addEvents(owner){
	owner.onmouseover = function(){
		hide_menu = false;	
	}
	owner.onmouseout = function(){
		var id = owner.id.substring(4,owner.id.length);
		hideMenu(id);
	}
}

function ItemCollection(_owner){
	this.owner = _owner;
	items = new Array();
	this.add = function(text, action, help, iconon, iconoff){
		var item = new Item(text, action, help, iconon, iconoff);
		items[items.length] = item;
		this.owner.DOM = null;
	}
	this.at = function(index){
		try{
			return items[index];	
		}catch(E){
			alert("Index out of bounds");
		}
	}
	this.size = function(){
		return items.length;	
	}
}

function Item(_text, _action, _help, _iconon, _iconoff){
	this.text = _text;
	this.action = _action;
	this.help = _help;
	this.iconon = _iconon;
	this.iconoff = _iconoff;
}


// VALIDADOR

var formValidator_dialog;

function FormValidator(_form){
	this.form = _form;	
	this.message = 'Hay errores en los datos introducidos';
	this.showDialog = true;
	this.validate = function(){
		AQUA_VAL_getFields(this.form);
		var wrong_fields = new Array();
		for(var i=0;i<AQUA_VAL_fields.length;i++){
			var f = AQUA_VAL_fields[i];
			var validation_rules = f.getAttribute('validate').split(',');
			for(var c=0;c<validation_rules.length;c++){
				var vr = validation_rules[c];
				var label = f.getAttribute('label_' + vr.replace('[','').replace(']', ''));
				if(label){
					label = label.split(',');
				}else{
					label = new Array('label_' + f.id);	
				}
				FormValidator.hasErrors = false;
				var vg = f.getAttribute('vgroup');
				if(!vg){ vg = f.id;}
				FormValidator.hasErrors = wrong_fields[vg + '_' + vr] != null;
				var e = false;
				switch(vr){
					case 'text':
						e = FormValidator.showError(label, isEmpty(f.value));
						break;
					case 'list':
						var e = FormValidator.showError(label, f.selectedIndex == 0);						
						break;
					case 'radio':
						var radios = _(f.name, 'name');
						var checked = false;
						for(var d=0;d<radios.length;d++){
							checked = checked || radios[d].checked;
						}
						e =  FormValidator.showError(label, !checked);
						break;
					case 'checkbox':
						var checks = _(f.name, 'name');
						var checked = false;
						for(var d=0;d<checks.length;d++){
							checked = checked || checks[d].checked;
						}
						e =  FormValidator.showError(label, !checked);
						break;
					case 'email':
						if(f.value.length>0){
							e = FormValidator.showError(label, !isValidMail(f.value));
						}
						break;
				    case 'pass':
						if(f.value.length>0){
							e = FormValidator.showError(label, !isSecureFormat(f.value));
						}
						break;
					case 'number':
						if(f.value.length>0){
							e = FormValidator.showError(label, !isNumber(f.value));
						}
						break;
					case 'confirm':
						e = FormValidator.showError(label, f.value != _(f.getAttribute('related')).value);
						break;
					case 'url':
						if(f.value.length>0){
							e = FormValidator.showError(label, !isValidURL(f.value));
						}
						break;
					case 'username':
						if(f.value.length>0){
							e = FormValidator.showError(label, !isUsername(f.value));
						}
						break;
					default:
						var method = vr.substring(vr.indexOf('[')+1, vr.lastIndexOf(']'));
						e = eval(method + "()");
						FormValidator.showError(label, e)
						break;
				}
				if(e){
					wrong_fields[vg + '_' + vr] = new FieldError(f, vr);
				}
			}
		}
		var html = '<ul class="plain-list">';
		var index = 0;
		for(var c in wrong_fields){
			var error_field = wrong_fields[c];
			if(error_field.field){
				html += '<li>'+error_field.field.getAttribute('msg_' + error_field.rule)+'</li>';
				index++;
			}
		}
		if(index > 0 && this.showDialog){
			formValidator_dialog = new Dialog();
			formValidator_dialog.image = 'dialog/error.png';
			formValidator_dialog.title = this.message;
			formValidator_dialog.html = html;
			formValidator_dialog.addAction('Aceptar', 'formValidator_dialog.hide()', 'dialog/back.png');
			formValidator_dialog.render();
			return wrong_fields;
		}else if(index == 0){
			return null;	
		}else{
			return wrong_fields;	
		}
	}
}

function FieldError(field, rule){
	this.field = field;
	this.rule = rule;
}

FormValidator.hasErrors = false;
FormValidator.errorColor = 'RED';
FormValidator.validColor = '#666666';
FormValidator.showError = function(_labels, iserror){
	if(iserror || FormValidator.hasErrors){
		for(var i=0;i<_labels.length;i++){
			var _label = _labels[i];
			if(_label){
				if(_label.indexOf('[hide]') != -1){
					var label = _(_label.substring(0, _label.indexOf('[')));
					label.style.color = FormValidator.errorColor;
					label.style.display = 'block';
				}else{
					var label = _(_label);
					label.style.color = FormValidator.errorColor;
				}
			}
		}
	}else{
		for(var i=0;i<_labels.length;i++){
			var _label = _labels[i];
			if(_label){
				if(_label.indexOf('[hide]') != -1){
					var label = _(_label.substring(0, _label.indexOf('[')));
					label.style.color = FormValidator.validColor;
					label.style.display = 'none';
				}else{
					var label = _(_label);
					label.style.color = FormValidator.validColor;
				}
			}
		}
	}
	return iserror;
}

var AQUA_VAL_fields;
function AQUA_VAL_getFields(form)
{
  AQUA_VAL_fields = new Array();
  var domElement = form;
  AQUA_VAL_getFields_rec(domElement, 1);
}

function AQUA_VAL_getFields_rec(currentElement, depth)
{
  if (currentElement)
  {
    var j;
	if(currentElement.getAttribute){
		var validate = currentElement.getAttribute('validate');
		if(validate){
			AQUA_VAL_fields[AQUA_VAL_fields.length] = currentElement;
		}
		var i=0;
		var currentElementChild=currentElement.childNodes[i];
		while (currentElementChild)
		{
		  AQUA_VAL_getFields_rec(currentElementChild, depth+1);
		  i++;
		  currentElementChild=currentElement.childNodes[i];
		}
	}
  }
}

//************** UTILITIES 
//*************************************************************************

function isNumber(cadena){
	ExpresionRegular=/^\d+$/;
	return ExpresionRegular.test(cadena);
}

function isDecimal(cadena){
	if(isEmpty(cadena))return false;
	ExpresionRegular=/^\$?[0-9]*(\.[0-9]{0,2})?$/;
	return ExpresionRegular.test(cadena);
}

function isUsername(value){
	var ck_username = /^[A-Za-z0-9.]{4,15}$/;
	return ck_username.test(value);
}

function getPositionLeft(This){
	var el = This;var pL = 0;
	while(el){pL+=el.offsetLeft;el=el.offsetParent;}
	return pL
}
function getPositionTop(This){
	var el = This;var pT = 0;
	while(el){pT+=el.offsetTop;el=el.offsetParent;}
	return pT
}

function _(text, type){
	if(type == 'tag'){
		return document.getElementsByTagName(text);
	}else if(type == 'name'){
		return document.getElementsByName(text);
	}else{
		return document.getElementById(text);
	}
}

function isEmpty(cadena){ 		                                  
	var blanco = " \n\t" + String.fromCharCode(13); 		                                     
	var i;                         
	var es_vacio;                
	for(i = 0, es_vacio = true; (i < cadena.length) && es_vacio; i++) 
	  es_vacio = blanco.indexOf(cadena.charAt(i)) != - 1;
	return(es_vacio);
}

function isValidURL(cadena){
	var v = new RegExp();
    v.compile("^[A-Za-z]+://[A-Za-z0-9-_]+\\.[A-Za-z0-9-_%&\?\/.=]+$");
    return v.test(cadena);
}

var textareas_stop = new Array();
function ismaxlength(obj, event){
	var contador = 'contador_' + obj.id;
	var maxlength = parseInt(obj.getAttribute('lengthMax'));
	if(obj.value.length>maxlength){
		obj.value = obj.value.substring(0, maxlength);
	}
	if(_(contador)){
		if(!textareas_stop[obj.id]){
			textareas_stop[obj.id] = true;
			window.setTimeout('doCount(\''+obj.id+'\',\''+contador+'\')', 1000);
		}
		
	}
}

function doCount(idobj, contador){
	var obj = _(idobj);
	var element = document.getElementById(contador);
	var num = parseInt(obj.getAttribute("length"));
	num = num - obj.value.length;
	if(element)
	element.innerHTML = num;
	textareas_stop[idobj] = false;
}

function isNumberKey(evt){
	 var charCode = (evt.which) ? evt.which : evt.keyCode
	 if (charCode > 31 && (charCode < 48 || charCode > 57)){
		return false;
	 }else{
	 	return true;
	 }
}

function isEnterKey(evt){
	 var charCode = (evt.which) ? evt.which : evt.keyCode
	 return charCode == 13 && !evt.shiftKey;
}

var alert_element;
function _ALERT(_element, text){
	alert_element = _element;
	if(text != null && text != 'undefined'){
		alert_element.innerHTML = text;	
	}
	__ALERT(4, true);
}


function __ALERT(i, v){
	if(v){
		alert_element.style.visibility = 'visible';
	}else{
		alert_element.style.visibility = 'hidden';
	}
	if(i>0){
		window.setTimeout('__ALERT('+(i-1)+', '+!v+')', 50);
	}
}



function isValidAttach(file, extArray) {
	allowSubmit = false;
	if (!file) return false;
	while (file.indexOf("\\") != -1){
		file = file.slice(file.indexOf("\\") + 1);
		}
		ext = file.slice(file.lastIndexOf(".")).toLowerCase();
		for (var i = 0; i < extArray.length; i++) {
			if (extArray[i] == ext) { allowSubmit = true; break; }
		}
	
	return allowSubmit;
}

function isMoneyKey(evt, txt){	
	 var key = (evt.which) ? evt.which : evt.keyCode
	 keychar = String.fromCharCode(key);

	if ((key==null) || (key==0) || (key==8) || (key==9) || (key==13) || (key==27)){
		return true;
	}else if ((("0123456789").indexOf(keychar) > -1)){
	   return true;
	}else if (keychar == "." && txt.value.indexOf('.') == -1){
	   return true;
	}else{
	   return false;
	}
}

function checkMoney(c){
	var text = new String(c.value);
	if(isEmpty(text) || text == '.'){
		c.value = '';
		return;
	}
	if(text.charAt(text.length-1) == '.'){
		c.value = text.replace('.','');
	}else if(text.charAt(0) == '.'){
		c.value = text.replace('.','0.');
	}
	var first = new String(c.value).charAt(0);
	while(first == 0){
		if(c.value.length > 1){
			if(c.value.charAt(1) == '.'){
				break;	
			}else{
				c.value = c.value.substring(1, text.length);
				first = new String(c.value).charAt(0);
			}
		}else{
			break;
		}	
	}
	var val = c.value;
	if(val.indexOf('.') == -1){
		 c.value = val + ('.00'); 
		 return;
	}
	if(val.indexOf('.') == (val.length-1)){
		c.value = val + '00'; 
		return;
	}
	if(val.indexOf('.') == (val.length-2)){
		c.value = val + '0'; 
		return;
	}
}

function ShowTip(e){
	if(e.target){
		Tip(e.target.innerHTML);	
	}else{
		Tip(window.event.srcElement.innerHTML);
	}	
}

function setFocus(id){
	_(id).focus();
	if(_(id).select){
		_(id).select();
	}
}

function setActiveStyleSheet(id, name) {
  var i, a;
  for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
    if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("id")  && a.getAttribute("name")) {
	  if(a.getAttribute("name") == name){
		  a.disabled = true;
		  if(a.getAttribute("id") == id) a.disabled = false;
	  }
    }
  }
}

function getActiveStyleSheet() {
  var i, a;
  for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
    if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title") && !a.disabled) return a.getAttribute("title");
  }
  return null;
}

function getPageAttributes(){
	var xScroll, yScroll, windowWidth, windowHeight;
	if (window.innerHeight && window.scrollMaxY) {
		xScroll = document.scrollWidth;
		yScroll = (false ? parent.innerHeight : self.innerHeight) + (false ? parent.scrollMaxY : self.scrollMaxY);
	} else if (document.body.scrollHeight > document.body.offsetHeight){
		xScroll = document.body.scrollWidth;
		yScroll = document.body.scrollHeight;
	} else {
		xScroll = document.getElementsByTagName("html").item(0).offsetWidth;
		yScroll = document.getElementsByTagName("html").item(0).offsetHeight;
		xScroll = (xScroll < document.body.offsetWidth) ? document.body.offsetWidth : xScroll;
		yScroll = (yScroll < document.body.offsetHeight) ? document.body.offsetHeight : yScroll;
	}
	if (self.innerHeight) {
		windowWidth = (false) ? parent.innerWidth : self.innerWidth;
		windowHeight = (false) ? parent.innerHeight : self.innerHeight;
	} else if (document.documentElement && document.documentElement.clientHeight) {
		windowWidth = document.documentElement.clientWidth;
		windowHeight = document.documentElement.clientHeight;
	} else if (document.body) {
		windowWidth = document.getElementsByTagName("html").item(0).clientWidth;
		windowHeight = document.getElementsByTagName("html").item(0).clientHeight;
		windowWidth = (windowWidth == 0) ? document.body.clientWidth : windowWidth;
		windowHeight = (windowHeight == 0) ? document.body.clientHeight : windowHeight;
	}
	var pageHeight = (yScroll < windowHeight) ? windowHeight : yScroll;
	var pageWidth = (xScroll < windowWidth) ? windowWidth : xScroll;
	return new Array(pageWidth, pageHeight, windowWidth, windowHeight);
}

function getPageScroll() {
	if (self.pageYOffset) {
		return false ? parent.pageYOffset : self.pageYOffset;
	} else if (document.documentElement && document.documentElement.scrollTop){
		return document.documentElement.scrollTop;
	} else if (document.body) {
		return document.body.scrollTop;
	}
}

var aqua_loader_nextMethod;
var aqua_loader_element;
function loadContents(url, next_method, secciones, element){
	aqua_loader_nextMethod = next_method;
	aqua_loader_element = element;
	if(!secciones){
		secciones = 'CONTENT';	
	}
	if(!_('screen_block')){
		dialog = new Dialog();
		dialog.html = 'Cargando contenidos de informaci&oacute;n...<br /><br /><img src="dialog/ajax-loader.gif" />';
		dialog.actions.clear();
		dialog.render();
	}
	var ajax = new AQUAX();
	ajax.url = '../servlets/SrvGeneral';
	ajax.method = AQUAX.GET;
	ajax.callback_method = loadContents_cb;
	ajax.addParam('accion','loadContents');
	ajax.addParam('url',url);
	ajax.addParam('secciones',secciones);
	ajax.send();
}

function loadContents_cb(response){
	if(!aqua_loader_element){
		aqua_loader_element = _('content');	
	}
	aqua_loader_element.innerHTML = response.value;
	if(!aqua_loader_nextMethod){
		dialog.hide();	
	}else{
		aqua_loader_nextMethod();	
	}
}

function seleccionarRadio(r){
	_(r).checked = true;	
}

function CalendarConfig(){
	this.lang;
	this.databaseFormat;
	this.displayFormat;
}

function activarLink(id, index){
	var as = _(id).getElementsByTagName('a');
	for(var i=0;i<as.length;i++){
		as[i].style.fontWeight = 'normal';	
	}
	if(as[index]){
		as[index].style.fontWeight = 'bold';	
	}
}

function AQUA_toggleFlash(state) {
	var objects = document.getElementsByTagName("object");
	for (var i = 0; i < objects.length; i++) {
		objects[i].style.visibility = (state == "hide") ? 'hidden' : 'visible';
	}
	var embeds = document.getElementsByTagName("embed");
	for (var i = 0; i < embeds.length; i++) {
		embeds[i].style.visibility = (state == "hide") ? 'hidden' : 'visible';
	}
	if (this.isFrame) {
		for (var i = 0; i < parent.frames.length; i++) {
			try {
				objects = parent.frames[i].window.document.getElementsByTagName("object");
				for (var j = 0; j < objects.length; j++) {
					objects[j].style.visibility = (state == "hide") ? 'hidden' : 'visible';
				}
			} catch(e) { }
			try {
				embeds = parent.frames[i].window.document.getElementsByTagName("embed");
				for (var j = 0; j < embeds.length; j++) {
					embeds[j].style.visibility = (state == "hide") ? 'hidden' : 'visible';
				}
			} catch(e) { }
		}
	}
};

function startsWith(str1, str2)
{return (str1.match("^"+str2)==str2)}

function endsWith(str1, str2)
{return (str1.match(str2+"$")==str2)}

function trimFirst(txt){
	if(startsWith(txt, ' ')){
		txt = txt.substring(1,txt.length);
	}	
	return txt;
}

function getUrlParameter( name )
{
  name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
  var regexS = "[\\?&]"+name+"=([^&#]*)";
  var regex = new RegExp( regexS );
  var results = regex.exec( window.location.href );
  if( results == null )
    return "";
  else
    return results[1];
}

function disableButtons(id){
	var btns = _(id).getElementsByTagName('input');
	for(var i=0;i<btns.length;i++){
		if(btns[i].type == 'BUTTON' || btns[i].type == 'button'){
			btns[i].disabled = true;
			btns[i].className = 'disabledButton';
		}
	}
}

function enableButtons(id){
	var btns = _(id).getElementsByTagName('input');
	for(var i=0;i<btns.length;i++){
		if(btns[i].type == 'BUTTON' || btns[i].type == 'button'){
			btns[i].disabled = false;
			btns[i].className = 'btnStyle';
		}
	}
}

function _go(url){
	document.location.href = url;
}

function check(id){
	_(id).checked = !_(id).checked;	
}

function getSubstring(src, maxlength){
	if(src.length <= maxlength){
		return new Encoder(src).html();	
	}else{
		return new Encoder(src.substring(0,maxlength)).html();	
	}
}

function showHelp(txt){
	var help_text = txt.getAttribute('help_text');
	if(isEmpty(txt.value) || txt.value == help_text){
		txt.className = 'inactive-search';
		txt.value = help_text;
	}
}

function hideHelp(txt){
	var help_text = txt.getAttribute('help_text');
	txt.className = '';
	if(txt.value == help_text){
		txt.value = '';
	}
}

function isValidYT(cadena){
	return startsWith(cadena, 'http://www.youtube.com/watch') || startsWith(cadena, 'http://youtu.be/');
}
