// JavaScript Document
function RetrieveObject(what) {
    var output = '';
    for (var i in what) {
        if (typeof what[i] == 'object') {
            output += RetrieveObject(what[i]);
        }
        else
            output += i + ' = ' + what[i] + '\n';
    }
    return output;
}


function myEval(val){
	return eval(val);
}


//////////////////////////////////
Prototype.FunctionFragment = '[a-zA-Z]+\\w+\\s*(\\([\\w\\s]*\\))?'; //detecta una función y sus argumentos
var Choquin = {
  Version: '1.0.0',
  require: function(libraryName) {
    // inserting via DOM fails in Safari 2.0, so brute force approach
    var script = '<script type="text/javascript" src="'+libraryName+'"></script>';
	//alert("ahí vamos:"+script);
	document.write(script);
  },
  load: function() {
    if((typeof Prototype=='undefined') || 
       (typeof Element == 'undefined') || 
       (typeof Element.Methods=='undefined') ||
       parseFloat(Prototype.Version.split(".")[0] + "." +
                  Prototype.Version.split(".")[1]) < 1.5)
       throw("choquin requires the Prototype JavaScript framework >= 1.5.0");
    $A(document.getElementsByTagName("script")).findAll( function(s) {
     //console.debug(s);
	 return (s.src && s.src.match(/myprototype\.js(\?.*)?$/))
    }).each( function(s) {
	  //console.debug(s);
	  var path = s.src.replace(/myprototype\.js(\?.*)?$/,'');
      var includes = s.src.match(/\?.*load=([a-z,]*)/);
      (includes ? includes[1] : 'myprototype_scrollable').split(',').each(
       function(include) { Choquin.require(path+include+'.js') });
    });
  }
}
Choquin.load();


// Extension to Ajax allowing for classes of requests of which only one (the latest) is ever active at a time
// - stops queues of now-redundant requests building up / allows you to supercede one request with another easily.

// just pass in onlyLatestOfClass: 'classname' in the options of the request


// Agregado para manejar evento Abort
Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete', 'Abort'];

Object.extend(Ajax.Request.prototype,{
  _onStateChange: Ajax.Request.prototype.onStateChange,
	onStateChange: function() {
		(this.options.onStateChange||Prototype.emptyFunction)(this.transport);
  	this._onStateChange();
	}

});


Object.extend(Ajax.Base.prototype,{
  _setOptions: Ajax.Base.prototype.setOptions,
	
	setOptions: function(options) {
    this._setOptions();
    Object.extend(this.options, {
			retries:10
		});
    Object.extend(this.options, options || {});
  },
	
	responseIsSuccess: function() {
    var status = this.getStatus();
		return status == undefined
        //|| status == 0
        || (status >= 200 && status < 300);
	 }

});


Ajax.currentRequests = {};

Ajax.Responders.register({
  onCreate: function(request) {
    //console.debug("Ajax.Responsders.onCreate:"+request.options.onlyLatestOfClass);
		if (request.options.onlyLatestOfClass && Ajax.currentRequests[request.options.onlyLatestOfClass]) {
            // if a request of this class is already in progress, attempt to abort it before launching this new request
           try { Ajax.currentRequests[request.options.onlyLatestOfClass].abort(); } catch(e) {}
        // keep note of this request object so we can cancel it if superceded
	   }
			//console.debug(request.options.onlyLatestOfClass);
			if(request.options.onlyLatestOfClass) Ajax.currentRequests[request.options.onlyLatestOfClass] = request;
  },
  onComplete: function(request) {
		//console.debug("onComplete: "+request.options.onlyLatestOfClass);
		if (request.options.onlyLatestOfClass) {
			// remove the request from our cache once completed so it can be garbage collected
			 Ajax.currentRequests[request.options.onlyLatestOfClass] = null;
     }
   }
});



///////////////////////////////////////////////////////////
///Ajax addon timeout
Object.extend(Ajax.Responders,{
	totalCount: 0,

	callInProgress: function(xmlhttp) {
		switch (xmlhttp.readyState) {
			/*
			0 = uninitialized
			1 = loading
			2 = loaded
			3 = interactive
			4 = complete
			*/
			
			case 1: case 2: case 3:
				return true;
				break;
			// Case 4 and 0
			default:
				return false;
				break;
		}
	},
	
	showFailureMessage: function(request) {
		console.debug(['uh oh, it looks like the network is down. Try again shortly',request]);
	},
	
	onNetworkdown: function(request){
		if (Ajax.Responders.callInProgress(request.transport)) {					
			request.transport.abort();
		}
		
		if(--request.options.retries >0) request['timeoutRequest'] = window.setTimeout(request.requestAgain.bind(request),5000 * Math.randRange(1,2,true));
		else{
			Ajax.Responders.showFailureMessage(request);
			(request.options['onTimeout']||request.options['onFailure']||Prototype.K)(request.transport, request.json);
		}
		Ajax.Responders.dispatch('onNetworkdown', this, this.transport);
	}
	
});

// Register global responders that will occur on all AJAX requests


Ajax.Responders.register({
	
	onCreate: function(request) {
		if(!request.uniqueId) request.uniqueId = ++Ajax.Responders.totalCount;
		request['timeoutId'] = window.setTimeout(
			function(){Ajax.Responders.onNetworkdown(request);},
			request.options.timeout||60000*2 // two minutes
		);
		console.debug(["setting timeout for "+request.uniqueId,request['timeoutId']]);
	},
	
	onComplete: function(request) {
		// Clear the timeout, the request completed ok
		window.clearTimeout(request['timeoutId']);
		window.clearTimeout(request['timeoutRequest']);
		console.debug(["clearing timeout for "+request.uniqueId,request['timeoutId']]);

	}
});

Ajax.Responders.register({
	onComplete: function(request) {
		//DETECCION DE ABORT
		setTimeout(function(){
			//console.debug([this,this.transport.readyState])
			if(this.transport.readyState==0) {
				//console.debug("esto es un abort, señores!");
				//esto es un abort señores!
				//this.onStateChange();
				//(this.options['onAbort']||Prototype.emptyFunction) (this.transport);
				//Ajax.Responders.dispatch('onAbort', this, this.transport);
			}
			else{
				if(this.transport.status==0 || this.transport.status==12007){
					//esto es un servidor caido señores!!!
					Ajax.Responders.onNetworkdown(request);
				}
			}
		}.bind(request),10);
	}
});
///////////////////////////////////////////////////////////


Object.extend(Ajax.Request.prototype,{
	getStatus: function(){
		//si el status no está, tiraba error
		try{return this.transport.status} catch(e){return -1}
	},
							
	respondToReadyState: function(readyState) {
    var event = Ajax.Request.Events[readyState];
    var transport = this.transport, json = this.evalJSON();
		//console.debug([event,readyState]);
		if (event == 'Complete') {
			
			//console.debug(['onComplete',this.responseIsSuccess(),readyState,this.getStatus()]);
			try {
        if(this.getStatus()>0){
					(this.options['on' + this.getStatus()]
        	 || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
        	 || Prototype.emptyFunction)(transport, json);
				}
				//else console.debug("ABORT")
			} catch (e) {
        this.dispatchException(e);
      }
      if ((this.header('Content-type') || '').match(/^text\/javascript/i))
        this.evalResponse();
    }

    try {
      (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
    } catch (e) {
      this.dispatchException(e);
    }finally{
		  Ajax.Responders.dispatch('on' + event, this, transport, json); ///esta es la diferencia con respecto al original
		}

    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
    if (event == 'Complete')
      this.transport.onreadystatechange = Prototype.emptyFunction;
  },


	abort : function(){
		 try {
				if (Ajax.Responders.callInProgress(this.transport)) {
					this.transport.abort();
					//Ajax.activeRequestCount--;
					this.transport.onreadystatechange = Prototype.emptyFunction;
				}
			 clearTimeout(this.timeoutId);
			 this.timeoutId = null;
			 //if(this.options.onAbort && typeof this.options.onAbort=='function') this.options.onAbort(this.transport);
			} catch(e) {}
			if(this.options.onlyLatestOfClass) Ajax.currentRequests[this.options.onlyLatestOfClass] = null;
	},
	

	requestAgain: function(){
		if(this.url) this.request(this.url);
	}
});





////////////////////////////////////////////////
/*
	Base, version 1.0.2
	Copyright 2006, Dean Edwards
	License: http://creativecommons.org/licenses/LGPL/2.1/
*/

var Base = function() {
	if (arguments.length) {
		if (this == window) { // cast an object to this class
			Base.prototype.extend.call(arguments[0], arguments.callee.prototype);
		} else {
			this.extend(arguments[0]);
		}
	}
};

Base.version = "1.0.2";

Base.prototype = {
	extend: function(source, value) {
		var extend = Base.prototype.extend;
		if (arguments.length == 2) {
			var ancestor = this[source];
			// overriding?
			if ((ancestor instanceof Function) && (value instanceof Function) &&
				ancestor.valueOf() != value.valueOf() && /\bbase\b/.test(value)) {
				var method = value;
			//	var _prototype = this.constructor.prototype;
			//	var fromPrototype = !Base._prototyping && _prototype[source] == ancestor;
				value = function() {
					var previous = this.base;
				//	this.base = fromPrototype ? _prototype[source] : ancestor;
					this.base = ancestor;
					var returnValue = method.apply(this, arguments);
					this.base = previous;
					return returnValue;
				};
				// point to the underlying method
				value.valueOf = function() {
					return method;
				};
				value.toString = function() {
					return String(method);
				};
			}
			return this[source] = value;
		} else if (source) {
			var _prototype = {toSource: null};
			// do the "toString" and other methods manually
			var _protected = ["toString", "valueOf"];
			// if we are prototyping then include the constructor
			if (Base._prototyping) _protected[2] = "constructor";
			for (var i = 0; (name = _protected[i]); i++) {
				if (source[name] != _prototype[name]) {
					extend.call(this, name, source[name]);
				}
			}
			// copy each of the source object's properties to this object
			for (var name in source) {
				if (!_prototype[name]) {
					extend.call(this, name, source[name]);
				}
			}
		}
		return this;
	},

	base: function() {
		// call this method from any other method to invoke that method's ancestor
	}
};

Base.extend = function(_instance, _static) {
	var extend = Base.prototype.extend;
	if (!_instance) _instance = {};
	// build the prototype
	Base._prototyping = true;
	var _prototype = new this;
	extend.call(_prototype, _instance);
	var constructor = _prototype.constructor;
	_prototype.constructor = this;
	delete Base._prototyping;
	// create the wrapper for the constructor function
	var klass = function() {
		var ret;
		var obj = this;
		if(obj == window) obj = {};
		if (!Base._prototyping) ret = constructor.apply(obj, arguments);
		obj.constructor = klass;
		return ret;  // de esta forma, la clase funciona tambien como una funcion
	};
	klass.prototype = _prototype;
	// build the class interface
	klass.extend = this.extend;
	klass.implement = this.implement;
	klass.toString = function() {
		return String(constructor);
	};
	extend.call(klass, _static);
	// single instance
	var object = constructor ? klass : _prototype;
	// class initialisation
	if (object.init instanceof Function) object.init();
	return object;
};

Base.implement = function(_interface) {
	if (_interface instanceof Function) _interface = _interface.prototype;
	this.prototype.extend(_interface);
};
//////////////////////////////////////////////////////////////

















Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  try{var fn = function() {
    return __method.apply(object, args.concat($A(arguments)));
  }}catch(e){throw(Object.extend(e,{description:e.description+'\nError binding function '+__method+' to '+object+' with arguments '+arguments}))}
	fn.__method = __method;
	return fn;
}



Number.prototype.inspect = function(){return this;};
String.prototype.inspect = function() {return "'"+this+"'";}

Object.inspect=function(object){
  try {
    if (object == undefined) return 'undefined';
    if (object == null) return 'null';
    if(object.inspect) return object.inspect();
	var ret="{";
	var arr=[];
	for (var i in object) if(typeof ret[i]!="function") arr.push ("'"+i+"':"+Object.inspect(object[i]));	
	ret+=arr+"}";
	return ret;
  } catch (e) {
    if (e instanceof RangeError) return '...';
    throw e;
  }
}



Object.extend(Object,{
	null2Empty:function(val){
		if(val==null || val==undefined) return "";
		return String(val);
	},
	
	isNull:function(val){
		return val==null || val==undefined || String(val)=="";
	},
	
	toLowerCase:function(val){
		if(!val) return val;
		if(typeof val.toLowerCase=="function") return val.toLowerCase();
		return val;
	},

	toUpperCase:function(val){
		if(!val) return val;
		if(typeof val.toUpperCase=="function") return val.toUpperCase();
		return val;
	},

	stringToDate:function(val){
		//intenta convertir el objeto a un Date, y si no es posible, lo deja como está
		//sólo convierte cadenas, no números
		var date = new Date(val);
		if(!isNaN(date.getYear())) return date;
		return val;
	},

	formatDate: function(val,format){
		if(val && val.format) return val.format(format);		
		return "";
	},

	archiveProperty: function(obj,propname,copy){
		if(!obj) return;
		var oldProperty = obj[propname];
		//if(copy) oldProperty = Object.extend({},oldProperty);
		obj["__________"+propname] = oldProperty;
		if(!copy) try{delete obj[propname];}catch(e){};
	},
	
	backupProperty: function(obj,propname){
		this.archiveProperty(obj,propname,true);
	},
	
	restoreProperty: function(obj,propname){
		if(!obj) return;
		if(obj["__________"+propname]){
			obj[propname] = obj["__________"+propname];
			delete obj["__________"+propname];
		}
		return obj[propname];
	},
	
	archivedProperty: function(obj,propname){
		if(!obj) return;
		return obj["__________"+propname];
	},
	
	removeProperties: function(obj,properties){
		if(!properties) return;
		if(typeof properties=="string") properties = [properties];
		properties.each(function(property){
			delete obj[property];
		});
		return obj;
	},
	
	hasMember: function(obj,val){
		//devuelve si este objeto tiene la propiedad o método con nombre val en su prototype
		return obj.constructor.prototype[val]!=undefined;
	},
	
	hasProperty: function(obj,key){
		return (obj && key in obj);
		//return $H(obj).keys().include(key);
	},
	
	getLongMethods: function(obj){
		for (var i in obj) {
			if (String(i).length>2 && typeof obj[i]=="function") console.debug([i,obj[i]]);
		}
	}


});


Choquin.Enumerable = {};

Object.extend(Choquin.Enumerable,{
	sortBy: function(iterator,desc) {
    var val_1 = desc? 1:-1;
		var val_2 = desc? -1:1;
		return this.collect(function(value, index) {
      return {value: value, criteria: iterator(value, index)};
    }).sort(function(left, right) {
      var a = left.criteria, b = right.criteria;
      return a < b ? val_1 : a > b ? val_2 : 0;
    }).pluck('value');
  },
	
	pluck: function(property) {
    var results = [];
    this.each(function(value, index) {
      var result;
			try{result = eval("value."+property);}catch(e){}
			results.push(result);
    });
    return results;
  },

	
	intersect:function (otherEnumerable){
		return this.select(function(obj){
			return otherEnumerable.include(obj);
		});
	},
	
	grepPartition: function (pattern,iteratorTrue,iteratorFalse,property){
		//pattern puede ser un string, un regExp, o un iterator (funcion)
		var trues = [], falses = [];	
		
		if(typeof pattern == "function") {
			this.each(function(value,index){
				if (pattern (value,index))
					trues.push((iteratorTrue || Prototype.K)(value, index));
				else falses.push((iteratorFalse || Prototype.K)(value, index));
			});
			return [trues,falses];
		}
		
		if(! (pattern instanceof RegExp)) pattern = String(pattern);
		if(typeof pattern == "string") pattern = pattern.findToRegExp();

		this.each(function(value,index){
			var stringValue = String(value).toString();
			if(property) {
				try{stringValue = String(eval("value."+property));}catch(e){}
			}
			if (pattern.test(stringValue))
				trues.push((iteratorTrue || Prototype.K)(value, index));
			else falses.push((iteratorFalse || Prototype.K)(value, index));
		});
		return [trues,falses];
	}
	
});

Object.extend(Enumerable,Choquin.Enumerable);
Object.extend(Array.prototype,Choquin.Enumerable);


function $() {
	//esta modificacion devuelve un array de elementos, si es que hay varios con el mismo "name"
 var elements = new Array();
  for (var i = 0; i < arguments.length; i++) {
    var element = arguments[i];
    if (typeof element == 'string'){
			var _element = element;
			element = document.getElementsByName(_element);
			if(element && element.length<=1){
				element = document.getElementById(_element)||element[0];
			}
		}
    if (arguments.length == 1){
    	//alert("aca:"+arguments[0]+" : "+element);
			return Element.extend(element);
		}
    elements.push(Element.extend(element));
  }
	return elements;
}

function $Name(element){
	if(typeof element=='string')
		return document.getElementsByName(element);
	else return element;
};


Choquin.Element = {};
Choquin.Element.Methods = {};

Choquin.Element.Methods._getStyle = Element.Methods.getStyle;

Choquin.Element.Methods = {
  getElementsByClassName: function(element, className) {
		return document.getElementsByClassName(className,element);
	},

  getElementsBySelector: function() {
    var args = $A(arguments), element = args.shift();
    return args.map(function(expression) {
      return expression.strip().split(/s+/).inject([null], function(results, expr) {
        var selector = new Selector(expr);
        return results.map(selector.findElements.bind(selector, element)).flatten();
      });
    }).flatten();
  },
	
  visible: function(element) {
   var ret = Element.getStyle(element,'display') != 'none';
	 return ret;
  },

  show: function(element) {
    for (var i = 0; i < arguments.length; i++) {
      var element = $(arguments[i]);
			element.style.display = '';
 			if (element.style.display!=Element.getStyle(element,"display")) element.style.display="block";
    }
		return element;
  },

	setVisibility:function(element){
		//recibe elm1,elm2...,elmn,visibility,elma,elm4b,elmc,....elmx,visibility
		var last = [];
		arr={"true":"show","false":"hide"};
		for (var i=0;i<arguments.length;i++){
			if(arguments[i].constructor==Boolean) {
				last.invoke(arr[arguments[i]]);
				//Element[arr[arguments[i]]].apply(null,last);
				last=[];
			}else last.push($(arguments[i]));
		}
		return element;
	}, 
	
	toggleVisibility: function(element){
    element = $(element);
    element.setStyle({visibility:[element.getStyle("visibility")=="hidden" ? 'visible' : 'hidden']});
    return element;
	},
	
	moveToFixed:function(element,position){
		var element = $(element);
		if(Element.getStyle(element,"display")=="absolute"){
			var ro = Position.realOffset(element);
			position[0]+=ro[0];
			position[1]+=ro[1];
		}
		Element.setStyle(element,{left:position[0]+"px",top:position[1]+"px"});
		return element;
	},
	
	
	update: function(element, html) {
		var _element = element;
		if(typeof element=='string'){
			var element = $Name(element);
			element = $A(element);
			var elById = document.getElementById(_element);
			if(elById) element.push(elById);
			element.compact();
			if(element.length==0) return;
		}
		else element = [element];
		if(!html) html='';
		
		element.each(function(el){
			if(el.innerHTML!=undefined){
				el.innerHTML = String(html).stripScripts();
				setTimeout(function() {String(html).evalScripts()}, 10);
			}
		});
		
		return element;
	},
	

	getDimensions: function(element,which) {
		element = $(element);
    if(!which) which = "offset";
		if (Element.getStyle(element, 'display') != 'none'){
			var Width = element[which+"Width"]||element.offsetWidth;
			var Height = element[which+"Height"]||element.offsetHeight;
	    return {width: Width, height: Height};
		}

    // All *Width and *Height properties give 0 on elements with display none,
    // so enable the element temporarily
    var els = element.style;
    var originalVisibility = els.visibility;
    var originalPosition = els.position;
    var originalDisplay = els.display;
		els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = 'block';
		
		var Width = element[which+"Width"]||element.offsetWidth;
		var Height = element[which+"Height"]||element.offsetHeight;
		
    els.display = 'none';
    els.position = originalPosition;
    els.visibility = originalVisibility;
		els.display = originalDisplay;
    return {width: Width, height: Height};
  },
	
	getClientDimensions: function(element){
		var offset = Element.getDimensions(element);
		var additional = Element.getAdditionalDimensions(element);
		return {width:offset.width-additional.width, height:offset.height-additional.height};
	},
	
	getVisualDimensions: function(element){
		var element = $(element);
		return {width:element.offsetWidth||0, height:element.offsetHeight||0};
	},
	
	getAdditionalDimensions: function(element){
		element = $(element);
		var width = 0, height = 0;
		width+=parseFloat(element.getStyle("border-left-width"))||0;
		width+=parseFloat(element.getStyle("border-right-width"))||0;
		width+=parseFloat(element.getStyle("padding-left"))||0;
		width+=parseFloat(element.getStyle("padding-right"))||0;
		height+=parseFloat(element.getStyle("border-top-width"))||0;
		height+=parseFloat(element.getStyle("border-bottom-width"))||0;
		height+=parseFloat(element.getStyle("padding-top"))||0;
		height+=parseFloat(element.getStyle("padding-bottom"))||0;

		return {width:width,height:height};
	},


	swapNodes: function (nodeA, nodeB) {
		var nodeA = $(nodeA);
		var nodeB = $(nodeB);
		var nextSibling = nodeA.nextSibling;
		var parentNode = nodeA.parentNode;
		nodeB.parentNode.replaceChild(nodeA, nodeB);
		nodeA.parentNode.insertBefore(nodeB, nodeA.nextSibling);  
	},
		
	sortBy: function(element,iterator,desc){
		element = $(element);
		var childNodes = $A(element.childNodes);
		if(!childNodes) return;
		childNodes = childNodes.sortBy(iterator,desc);
		
		childNodes = childNodes.collect(function(node){
			return element.removeChild(node);
		});
		
		childNodes.each(function(e){
			if(e.nodeType!=3) element.appendChild(e);
		});
		
		return element;
	},
	
	insertAfter: function(element,node,referenceNode){
		element.insertBefore(node, referenceNode.nextSibling);
	},
	
	insertChild: function(element,node){
		var firstChild = element.childNodes[0];
		if(firstChild) element.insertBefore(node,firstChild);
		else element.appendChild(node);
	},
	
	clear: function(element){
		element.innerHTML = "";
		return element;
	},
	
	filter: function(element,textoOrRegExpIterator,property){
		if(textoOrRegExpIterator) element.__filtered = {element:element,textoOrRegExpIterator:textoOrRegExpIterator,property:property};		
		if(!element.__filtered) return;
		
		var iteratorTrue = function(element){
			if($(element).setStyle) $(element).setStyle({display:""});
		};
		var iteratorFalse = function(element){
			if($(element).setStyle) $(element).setStyle({display:"none"});
		};
		
		return $A($(element).childNodes).grepPartition(element.__filtered.textoOrRegExpIterator,
		iteratorTrue,iteratorFalse,element.__filtered.property);	
	},

	appendFilteredChild: function(element,child){
		var element = $(element), child = $(child);
		if(element.filterFunction) {
			child.setStyle({display: element.filterFunction(child)?"":"none"});
		}
		(element._230984209appendChild || element.appendChild) (child);
	},
	
	applyFilter: function(element,filterFunction){
		var element = $(element);
		if(element.appendChild != element.appendFilteredChild) {
			element._230984209appendChild = element.appendChild;
			element.appendChild = element.appendFilteredChild;
		}
		element.filterFunction = filterFunction;
		element.filter(filterFunction);
	},

	scrollToElement: function(element,childNode){
		var element = $(element), childNode = $(childNode);
		var relativeOffset = Position.relativeOffset(childNode);
		element.scrollLeft = relativeOffset[0];
		element.scrollTop = relativeOffset[1];
		return element;
	},
	
	flatWidth: function(element){
		var element = $(element);
		var ret = 0;
		$A(element.childNodes).each(function(node){
			var value = $(node).offsetWidth;
			if(value) ret+=value;
		})
		return ret;
	},
	
	flatten: function(element){
		var element = $(element);
		if(!element) return;
		var ret = 0;
		$A(element.childNodes).each(function(node){
			if(node.nodeType!=3) {
				$(node).setStyle({display:'inline',float:'left'});
				var value = $(node).offsetWidth;
				if(value) ret +=value;
			}
		});
		element.setStyle({width:ret+'px'});
		return element;
	}

	
};

Object.extend(Element, Choquin.Element.Methods);
Element.addMethods(Choquin.Element.Methods);



/////////////////////////////////////////////////////////////


Form.Element.getValue= function(element) {
	///sobreescribí esta función para que soporte varios elementos con el mismo name
	element = $(element);
	var ret= [];
	if(!element) return ret;
	if(element.options || !element.length) element=[element];
	for(var i=0;i<element.length;i++){
		var method = element[i].tagName.toLowerCase();
		var parameter = Form.Element.Serializers[method](element[i]);
		if (parameter){
			if(parameter[1].push)	ret = ret.concat(parameter[1]);
			else ret.push(parameter[1]);
		}
	}
	return ret;
}

$F = Form.Element.getValue;


Form.Element.setValue=function(element,value) {
	var old = element;
	element = $(element);
	//alert(element+" "+old+" "+element.tagName);
	if(!element) return;
	if(!element || element.options || !element.length) element=[element];

	for(var i=0;i<element.length;i++){
		var method = element[i].tagName.toLowerCase();
		switch(method){
			case 'input':
				switch(element[i].type.toLowerCase()){
					case 'submit':
					case 'hidden':
					case 'password':
					case 'text':
						element[i].value=value||"";
					break;
					
					case 'checkbox':
					case 'radio':
						var val=value;
						if(typeof val=="boolean") element[i].checked = val;
						else{
							if(!val || !val.any) val=$A(String(value));
							element[i].checked = val.any(function(node){return node==element[i].value});
						}
					break;
				}
			break;
			
			case 'textarea':
				element[i].value=value||"";	
			break;
			
			case 'select':
				var val=value;
				if(val==null || val==undefined) {
					if(element[i].type == 'select-one') {
						element[i].selectedIndex=0;
						continue;
					}
					else val=[];
				}
				if(!val.any) val=String(val).split(',');//val=$A(String(value));
				for(var i2=0;i2<element[i].options.length;i2++){
					var sel = !val.length?false:val.any(function(node){ return node==element[i].options[i2].value});
					element[i].options[i2].selected = sel;
				}
			break;
		}
	}
	if (element[0].onchange) element[0].onchange();
	//llamo a la onchange ya que estamos...
	
}


Form.Element.checkFileExtension=function(element,extensiones,botonParaHabilitar){
	//chequea que el control "element" tenga una de las entensiones dentro del string o array "extensiones"
	//si no se pasa extensiones, siempre devuelve true
	var control = $(element);
	if(!control) return false;
	var archivo = control.value;
	var ret=String(archivo).checkFileExtension(extensiones);
	if(botonParaHabilitar) $(botonParaHabilitar).disabled=!ret;
	return ret;
}


Object.extend(Form.Element,{
	update:function(element,values){
		element = $(element);
    var method = element.tagName.toLowerCase();
    var parameter = Form.Element.Updaters[method](element,values);
	},
	
	setValueFromText:function(element,text){
		element = $(element);
		if(typeof text=="string") text =[text];
		var text = text.inject([],function(what,valor){
			what.push(String(valor).toLowerCase());
			return what;
		});
		var method = element.tagName.toLowerCase();
		switch(method){
			case 'select':
				for(var i = 0;i<element.options.length;i++){
					var option = element.options[i];
					option.selected = text.include(String(option.text).toLowerCase());
				}
			break;
		}
		if (element.onchange) setTimeout(function(){if(element && element.onchange && element.parentNode) element.onchange()},10);
	},
	
	getText:function(element){
		element = $(element);
		var method = element.tagName.toLowerCase();
		var ret = [];
		switch(method){
			case 'select':
				for(var i = 0;i<element.options.length;i++){
					var option = element.options[i];
					if(option.selected)  ret.push(option.text);
				}
			break;
		}
		return ret;	
	}
});

Form.Element.Updaters = {
	select: function(element,options){
		var element = $(element);
		var value = Form.Element.getValue(element);
		var lastopt = element.options.length ? element.options[element.options.length-1] : {};
		element.options.length= (element.options.length && element.options[0].value==0)?1:0;
		
		for(var i=0;i<options.length;i++){
		
			var ii=0;
			var nodo = document.createElement("option");
			var h = $H(options[i]);
			h.each(function(e){
				try{
					if(ii==0) nodo.value=e[1];
					if(ii==1) nodo.text=e[1];
					if(ii==2) nodo.title=e[1];
					if(ii==3) {
						nodo.data=e[1];
						//console.debug(e[1]);
					}
				}catch (e){};
		
				ii++;
				if(ii>3) throw $break;
					
			});
			
			try{element.add(nodo,null);}catch(e){element.add(nodo)}
		}
				
		if (lastopt.value==-1) try{element.add(lastopt,null);}catch(e){element.add(lastopt);}
		Form.Element.setValue(element,value);
	}
}


/////////////////////

Form.setValue=function(form,obj){
	var obj=$H(obj);
	obj.each(
		function(elm){
			Form.Element.setValue(elm[0],elm[1]);
		}
	);
}

Form.getValue=function(form){
	var obj={};
	var elements = this.getElements(form);
	elements.each(function(elm){obj[elm.name]=Form.Element.getValue(elm.name)});
	return obj;
}


Form.validate=function(form){
	try{
		var elements = this.getElements(form);
		var ret = true;
		var focused=false;
		elements.each(function(elm){
			var validation = elm.getAttribute("onvalidate")||elm.getAttribute("onValidate");
			if(validation){
				elm.error = !myEval.bind(elm)(validation);
				if (elm.error){
					if(elm.style._backgroundColor == undefined) elm.style._backgroundColor = elm.style.backgroundColor;
					if (!focused) {elm.focus();focused=true}
				}
				elm.style.backgroundColor=elm.error?Form.validate._backgroundColor:elm.style._backgroundColor;
				ret = ret && !elm.error;
			}
		});
		return ret; ////OJO! es return ret
	}catch(e){alert(e.message);return false};
}

Form.validate._backgroundColor = "#FFAA66";


//////////////////////


if(!window.Window) Window = {};

Object.extend(Window,{
	stop: function(ventana){
		if (!ventana) ventana = window;
		if (!document.all) ventana.stop(); else ventana.document.execCommand('Stop');
	},
	
	getWidth: function(){
		  var myWidth = 0;
			if( typeof( window.innerWidth ) == 'number' ) {
				//Non-IE
				myWidth = window.innerWidth;
			} else if( document.documentElement && ( document.documentElement.clientWidth) ) {
				//IE 6+ in 'standards compliant mode'
				myWidth = document.documentElement.clientWidth;
			} else if( document.body && ( document.body.clientWidth) ) {
				//IE 4 compatible
				myWidth = document.body.clientWidth;
			}
		return myWidth;
	},
	
	getHeight: function(){
		var myHeight = 0;
		if( typeof( window.innerWidth ) == 'number' ) {
			//Non-IE
			myHeight = window.innerHeight;
		} else if( document.documentElement && ( document.documentElement.clientHeight ) ) {
			//IE 6+ in 'standards compliant mode'
			myHeight = document.documentElement.clientHeight;
		} else if( document.body && ( document.body.clientHeight ) ) {
			//IE 4 compatible
			myHeight = document.body.clientHeight;
		}
		return myHeight;
	},
	
	getDimensions: function(){
		var width = this.getWidth();
		var height = this.getHeight();
		return {width:width,height:height};
	}		
});

////////////////////////////

if(!window.Menu) Menu = new Object();
Menu.open=function(element){
	var element = $(element);
	element.show();	
	if(element && element.Menu_Timer) clearTimeout(element.Menu_Timer);
	if(this.lastOpened && this.lastOpened!=element) {
		this.closeNow(this.lastOpened);
	}
	this.lastOpened = element;
}

Menu.closeNow=function(element){
	var element = $(element);
	if(element.__clipped) return;
	Element.hide(element);
	if(this.lastOpened = element) this.lastOpened = null;
}

Menu.close=function(element){
	var element = $(element);
	//console.debug(element.__clipped);
	if(element.__clipped) return;
	//setTimeout("Element.hide('"+element+"')",1000);
	element.Menu_Timer = setTimeout(function(){element.hide()},500);
}


Menu.show = Menu.open;
Menu.hide = Menu.close;

Menu.__open = Menu.open;
Menu.__close = Menu.close;
Menu.__closeNow = Menu.closeNow;


Object.extend(Menu,{
	create: function(element,options){
		var element = $(element);
		if(!element) throw(Error.create('No se encontró elemento al crear Menú'));
		var options = options||{};
		element.__menuOptions = {content:[],submenus:[],parentMenu:null};
		this.addSubmenu(options.parentMenu,element);
		
		Event.observe(element,'mouseover',function(event){
			Menu.open(element);
			Event.stop(event)
		}); 
		Event.observe(element,'mouseout',function(event){
			Menu.close(element);
			Event.stop(event)
		}); 
		
		options.content.each(function(content){
			Menu.addContent(element,content);
			Event.observe(content,'mouseover',function(event){Menu.open(element);Event.stop(event)}); 
			Event.observe(content,'mouseout',function(event){Menu.close(element);Event.stop(event)}); 
		});
		
		if("clip" in options) {
			options.clip = $(options.clip);
			Event.observe(options.clip,"click",function(){Menu.toggleClip(element)});
		}
		
		if(options.clipped) Menu.clip(element);
		//this.closeNow(element);

	},
	
	addContent: function(element,content){
		var element = $(element);
		var content = $(content);
		if(!element.__menuOptions) throw("No se puede agregar un contenido de menú a algo que no sea un Menú");
		content.hide();
		if(!element.__menuOptions.content.include(content)) element.__menuOptions.content.push(content);
	},
	
	addSubmenu: function (menu,submenu){
		var menu = $(menu),submenu = $(submenu);
		if(!menu || !submenu) return;
		if(!menu.__menuOptions) throw("No se puede agregar un sumbenu a algo que no sea un Menú");
		if(!submenu.__menuOptions) throw("No se puede agregar como submenú algo que no sea un Menú a un Menú");
		//this.closeNow(submenu);
		if(!menu.__menuOptions.submenus.include(submenu)) menu.__menuOptions.submenus.push(submenu);
		submenu.__menuOptions.parentMenu = menu;
	},
	
	sameGroup: function(menu,submenu){
		var menu = $(menu), submenu = $(submenu);
		if(!menu || !submenu) return false;
		return (menu == submenu) || (this.parentMenus(submenu).include(menu)) || (this.parentMenus(menu).include(submenu));
	},
	
	rootMenu: function(menu){
		var menu = $(menu);
		if(!menu || !menu.__menuOptions) return;
		var found = menu;
		do{
			found = menu;
			menu = menu.__menuOptions.parentMenu;
		} while (menu);
		return found;
	},
	
	parentMenus: function(menu){
		var menu = $(menu);
		if(!menu || !menu.__menuOptions) return;
		var result = [];
		while(menu){
			result.push(menu);
			menu = menu.__menuOptions.parentMenu;
		}
		return result;
	},
	
	open: function(element){
		var element = $(element);
		if(!element.__menuOptions) return this.__open.apply(this,$A(arguments));
		
		if(element.__menuOptions.open) return;
		//console.debug("open "+element.id);
		element.__menuOptions.content.invoke("show");
		
		var menu = element;
		do{
			clearTimeout(menu.__menuOptions.closeTimeout);
			menu = menu.__menuOptions.parentMenu;
		}while (menu);
		
		element.__menuOptions.open = true;
		//cerrar otros menúes que no estén en este grupo
		if(!this.sameGroup(this.lastOpenedMenu, element)){
			this.closeNow(this.lastOpenedMenu);
		}
		
		this.lastOpenedMenu = element;
	},
	
	close: function(element,now){
		var element = $(element);
		if(!element) return;
		if(!element.__menuOptions) return this.__close.apply(this,$A(arguments));
		if(element.__menuOptions.open == false) return;
		
		//console.debug("close "+element.id);
		//console.debug(element.__clipped);
		if(element.__clipped) return;
		element.__menuOptions.open = false;
		clearTimeout(element.__menuOptions.closeTimeout);
		element.__menuOptions.closeTimeout = setTimeout(function(){Menu.closeNow(element)},500);
		//if(this.lastOpenedMenu == element) this.lastOpenedMenu = null;
	},
	
	closeNow: function(element){
		var element = $(element);
		if(!element) return;
		if(!element.__menuOptions) return this.__closeNow.apply(this,$A(arguments));		
		if(element.__clipped) return;
		element.__menuOptions.content.invoke("hide");
	},
		
	clip: function(element){
		var element = $(element);
		Menu.open(element);
		element.show();
		element.__clipped = true;
		element.addClassName('clipped');
	},
	
	unClip: function(element){
		var element = $(element);
		element.__clipped = false;
		element.removeClassName('clipped');
	},
	
	clipped: function(element){
		return $(element).__clipped;
	},
	
	toggleClip: function(element){
		var element = $(element);
		if(Menu.clipped(element)) Menu.unClip(element);
		else Menu.clip(element);
	}
});





//////////////////////////////////




Object.extend(Array.prototype,{
	pushFirst:function(what){
		var oldArray = [].concat(this);
		var newArray = [what].concat(this);
		this.length = 0;
		Object.extend(this,newArray);
		return this;
	},
	
	pushArray:function(array){
		return this.push.apply(this,array);
	},
	
	sliceArray:function(array){
		return this.slice.apply(this,array);
	},
	
	equalTo: function(array){
		var equals = true;
		this.each(function(value,index){
			
		}.bind(this));
	}
	
});

Object.extend(String.prototype,{
	
	checkFileExtension:function(extensiones){
		//extensiones puede ser un array o un string
		var archivo = this;
		var ret=false;
		if(extensiones && typeof extensiones=="string") extensiones=new Array(extensiones);
		if(!extensiones) ret=true;
		else{
			var ext = archivo.ext();
			if(!ext) return false;
			ret = extensiones.any(function(extension){
				return extension.toLowerCase() == ext.toLowerCase();
			});
			//ret = ((extensiones.join(",").toLowerCase()+",").indexOf(archivo.ext().toLowerCase()+',')) >=0;
		}
		return ret;
	},

	ext : function(){
		var posicion = this.lastIndexOf(".");
		if(posicion==-1) return null;
		return (this.substr(posicion+1)).toLowerCase();
	},

	removeExt : function(){
		///devuelve el nombre del archivo sin la extension
		var posicion = this.lastIndexOf(".");
		if(posicion==-1) return this;
		return (this.substr(0,posicion)).toLowerCase();
	},

	path : function(){
		//devuelve el path de un archivo
		var pos = this.lastIndexOf("/");
		if(pos==-1) 
		var pos = this.lastIndexOf("\\");
		if(pos==-1) return this;
		return this.substr(0,pos+1);
	},

	filename : function(){
		//devuelve el nombre del archivo sin el path
		var pos = this.lastIndexOf("/");
		if(pos==-1) 
		var pos = this.lastIndexOf("\\");
		if(pos==-1) 
		return this;
		return this.substr(pos+1);
	},
	
	fixLastCharacter : function (character){
		//si character no es el ultimo caracter de este string, se lo agrega y devuelve el resultado sin modificar el string original
		if(this.substr(this.length-1,1)!=character) return this+character;
		else return this;
	}, 
	
	newFilename : function (){
		var re = /(.+)\((\d*)\)/ig;
		var arr = re.exec(this);
		var newFile;
		if(arr) 
			newFile = this.path()+arr[1].filename()+"("+Number(arr[2]).succ()+")"+ (this.ext()?"."+this.ext():"");
		else newFile = this.path()+this.filename().removeExt()+"(1)"+(this.ext()?"."+this.ext():"");
		return newFile;
	},

	
	trim : function(caracteres){
		//caracteres es el caracter o array de caracteres posibles que se descarta/n del principio y fin
		if (caracteres==null) caracteres = " ";
		var returnString = $A(this);
		if(typeof caracteres == "string") caracteres = [caracteres];
		for (var i = 0;i<caracteres.length;i++){
			var c = caracteres[i];
			while(returnString[0]==c && returnString.length>0) returnString.shift();
			while(returnString[returnString.length-1]==c && returnString.length>0) returnString.pop();
		}
		return returnString.join("");
	},
	
	fixQuotes : function (c){
		if(c==null) c = "'";
		var re = new RegExp(c,"g");
		var ret = this.replace(re,"\\"+c);
		return ret;
	},

	parseFloat: function(){
		//var ret = this.replace(/,/g,".");
		//return ret;
		return parseFloat(this);
	},
	
	parseInt:function(){
		var re = /\d+/ig;
		return re.exec(this);
	},
	
	minusFirst: function(str,fnBusqueda){
		var str = String(str);
		this.fnBusqueda = fnBusqueda;
		//WriteLn(this.fnBusqueda);
		if(!fnBusqueda) this.fnBusqueda = this.indexOf;
		
		var p = this.fnBusqueda(str);
		if(p==-1) return this;
		var parte1 = this.substr(0,p);
		var parte2 = this.substr(p+str.length,this.length);
		return parte1+parte2;
	},
	
	minusLast: function (str){
		return this.minusFirst(str,this.lastIndexOf);
	},
	
	repeat: function(times){
		var ret = "";
		for (var i=1;i<=times;i++) ret+=this;
		return ret;
	},
	
	toNull: function(){
		if(this=="") return null;
		return this;
	},
	
	p:function(){
		return "<p>"+this+"</p>";
	},
	
	functionBody:function(){
		return this.substr(13,this.length-14);
	},
	
	functionParameters:function(){
		var primParentesis = this.indexOf("(");
		var segParentesis  = this.indexOf(")");
		if(primParentesis == -1 || segParentesis == -1) return;
		return this.substring(primParentesis+1,segParentesis);
	},
	
	functionName:function(){
		var primParentesis = this.indexOf("(");
		var functionString = this.indexOf("function ");
		var comienzo = functionString!=-1?functionString.length:0;
		if(primParentesis==-1) primParentesis = this.length;
		return this.substring(comienzo,primParentesis);
	},
	
	findToRegExp:function(){
		var texto = this;
		texto = texto.trim(",");
		texto = texto.split(",").inject([],function(what,i){
			what.push("("+i.fixRegExp().sinTildesRegExp()+")");
			return what;
		}).join("|");
		texto = "(^|\\s)("+texto+")";
		var pattern = new RegExp(texto,"i");
		return pattern;
	},
	
	queryString:function(){
		var pos = this.indexOf("?");
		if(pos==-1) return "";
		return this.substr(pos+1,this.length);
	},
	
	url:function(){
		var pos = this.indexOf("?");
		if(pos==-1) return this;
		return this.substr(0,pos);
	},
	
	fixLength:function(length,char,atRight){
		if(!char) char=" ";
		var ret = this;
		if(this.length>length) {
			if(atRight) ret = this.substr(0,length);
			else ret = this.substr(this.length-length,length);
		}
		else{
			var fix = char.repeat(length-this.length);
			if(atRight) ret +=fix;
			else ret = fix+ret;
		}
		return ret;
	},
	
	italics:function(){
		return "<i>"+this+"</i>";
	},
	
	reemplazar: function(cadena,nuevacadena){
		var arr=this.split(cadena);
		return arr.join(nuevacadena);
	},
	
	fixRegExp: function(){
		var re = /\.|\*|\|\?\(|\)|\^|\$|\\|\[|\]|\+|\{|\}/ig;
		return this.replace(re,function(what){return "\\"+what});
	},

	sinTildesRegExp:function(){
		var sintildes = {"a":"á","e":"é","i":"í","o":"ó","u":"ú"};
		var contildes = {"á":"a","é":"e","í":"i","ó":"o","ú":"u"};
		var todo = Object.extend(Object.extend({},sintildes),contildes);
		var retext = [];
		for (var i in sintildes) retext.push("("+i+"|"+sintildes[i]+")");
		var re = new RegExp(retext.join("|"),"ig");
		return this.replace(re,function(what){return "["+what.toLowerCase()+"|"+todo[what.toLowerCase()]+"]"});
	},
	
	getURIcontent:function(){
		return this.minusFirst("url(").minusFirst("\"").minusLast("\"").minusLast(")");
	}
	
});




Object.extend(String.prototype,{
	isEmail:function (){
		var reMail=new RegExp("^[\\w\.=-]+@[\\w\\.-]+\\.[a-z]{2,4}$");
		return reMail.test(this);
	},
	
	isFloat:function(){
		var re = /^(-)?\d+([.,]\d+)?$/;
		return re.test(this);
	},

	isInteger:function(){
		var re = /^(-)?\d+$/;
		return re.test(this);
	},

	isComodin:function(){
		return this.indexOf("***")!=-1 || this.indexOf("$$$")!=-1;
	},
	
	isDate:function(){
		return this.match(/^\d{1,2}\/\d{1,2}\/\d{4}(\s\d{1,2}:\d{1,2}(:\d{1,2})?)?$/);
	}
	
});


Object.extend(String,{
	null2Empty : function (val){
		if(val==null||val==undefined) val= "";
		return String(val);
	},
	
	randomLetter:function(primerLetra,ultimaLetra){
		var codeA = (primerLetra||"a").charCodeAt(0);
		var codeZ = (ultimaLetra||"z").charCodeAt(0);
		return String.fromCharCode(codeA+Math.round(Math.random()*(codeZ-codeA)));
	},

	randomNumber:function(){
		return this.randomLetter("0","9");
	},

	randomString:function(cant){
		var ret;
		if(!cant)cant=1;
		var arr= new Array();
		var codeA="a".charCodeAt(0);
		var codeZ="z".charCodeAt(0);
		var code0="0".charCodeAt(0);
		var code9="9".charCodeAt(0);
		
		for (var i=codeA;i<=codeZ;i++) arr.push(String.fromCharCode(i));
		for (var i=code0;i<=code9;i++) arr.push(String.fromCharCode(i));
	
		ret="";
		for(var i=0;i<cant;i++) ret+=arr[Math.round(Math.random()*(arr.length-1))];
		return ret;
	},
	
	fixLength:function(obj,quantity,char,atRight){
		return String(obj).fixLength(quantity,char,atRight);
	}
});



////////////////

Object.extend(Number.prototype,{
	decimals:function(val){
		var val2 = Math.pow(10,val);
		var ret = String(Math.round(this*val2)/val2);
		var posDot = String(ret).indexOf(".");
		var integer = String(parseInt(ret));
		var decimals = "";
		if (posDot==-1) decimals = "0".repeat(val);
		else decimals = ret.substr(posDot+1,ret.length);
		decimals+="0".repeat(val-decimals.length);		
		return integer+"."+decimals;
	},
	
	trimDecimals:function(val){
		var val2 = Math.pow(10,val);
		var ret = String(Math.round(this*val2)/val2);
		var posDot = String(ret).indexOf(".");
		var integer = String(parseInt(ret));
		var decimals = posDot!=-1?ret.substr(posDot+1,ret.length):null;
		return integer+(decimals?"."+decimals:"");
	},
	
	currency:	function (symbol) {
		 if(symbol==null) symbol="$";
		 if(!decimals) decimals = Number.currencyDecimals;
		 //-- Returns passed number as string in $xxx,xxx.xx format.
		 var number = String(this).decimals(decimals);
		 var decimales = number.substr(number.indexOf("."));
		 var dNum = number.substr(0,number.indexOf("."));
		 var dStr = dNum;
		 var dLen;
		 if (dNum>=1000) {
				dLen=dStr.length;
				dStr=parseInt(""+(dNum/1000))+","+dStr.substring(dLen-3,dLen);
		 }
	
		 //-- Adds comma in millions place.
		 if (dNum>=1000000) {
				dLen=dStr.length;
				dStr=parseInt(""+(dNum/1000000))+","+dStr.substring(dLen-7,dLen);
		 }

		 return symbol+" "+dStr+decimales;

	},
	
	odd:function (){
		return (Math.pow(-1,this)<0);
	},
	
	even:function(){
		return !this.odd();
	},
	
	sign:function(){
		return this==0?0:this>0?1:-1;
	},
	
	pixels: function(){
		return this+"px"; 
	}
	
});

Object.extend(Number,{
	currencyDecimals: 2
});
/////////////



/**********************/

Object.extend(document,{
	createElementHTML : function(tag,innerHTML){
		//recibe o un string en tag, o un objeto con: tag (string) , innerHTML (string) , style (objeto)
		if(typeof tag!="object"){
			var _tag = tag;
			var tag = {};
			tag.tag = _tag;
			tag.innerHTML = innerHTML;
		}
		var el = document.createElement(tag.tag);
		if(tag.innerHTML!=null) el.innerHTML = tag.innerHTML;
		if(tag.style) Element.setStyle(el,tag.style);
		if(tag.className) el.className = tag.className;
		return el;
	},
	
	getElementsByAttribute:function(attr_name,attr_value,childs){
		var ret = new Array();
		if(!childs)childs=this.documentElement.childNodes;
		for(var i=0;i<childs.length;i++){
			var node = childs[i];
			if (node.getAttribute &&  node.getAttribute(attr_name)==attr_value) {
				ret.push(node);
			}
			if(node.hasChildNodes())	ret = ret.concat(this.getElementsByAttribute(attr_name,attr_value,node.childNodes));
		}
		return ret; //no puede devolver null, por el concat
	},
	
	getElementsByAttribute : function(attrName, value, parentElement) {
		var children = ($(parentElement) || document.body).getElementsByTagName('*');
		return $A(children).inject([], function(elements, child) {
			if (child.getAttribute && child.getAttribute(attrName)==value){
				elements.push(child);
			}
			return elements;
		});
	}

});

$Attr = document.getElementsByAttribute;

////////////////////////////////
Object.extend(Date,{
 	arrDayNames : ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],
	dayName:function(number){
		return this.arrDayNames[number];
	}
});

Object.extend(Date.prototype,{
	format: function (formato){
		if (!formato) {
			formato="dd/mm/yyyy";
			//if (Application("language")=="en") formato="mm/dd/yyyy";
			//else formato = "dd/mm/yyyy";
		}
		
		var fec = this;
		var yyyy = fec.getFullYear();
		var dd = String.fixLength(fec.getDate(),2,"0");
		var mm = String.fixLength(fec.getMonth()+1,2,"0");
		var hh = String.fixLength(fec.getHours(),2,"0");
		var nn = String.fixLength(fec.getMinutes(),2,"0");
		var ss = String.fixLength(fec.getSeconds(),2,"0");
		var ds = Date.dayName(fec.getDay());
		
		ret = formato;
		
		var re = /ddss/ig;
		ret = ret.replace(re,ds);
		var re = /dd/ig;
		ret = ret.replace(re,dd);
		var re = /mm/ig;
		ret = ret.replace(re,mm);
		var re = /yyyy/ig;
		ret = ret.replace(re,yyyy);
		var re = /hh/ig;
		ret = ret.replace(re,hh);
		var re = /nn/ig;
		ret = ret.replace(re,nn);
		var re = /ss/ig;
		ret = ret.replace(re,ss);
		var re = /ds/ig;
		ret = ret.replace(re,ds.substr(0,2));
	
		return(ret);
	}
});


//////////////////////////////////////

Cronometro = Base.extend({
	constructor: function(){
		this.iniTime = new Date();
		this.lastTime = this.iniTime;
	},
	
	elapsed: function(){
		var d = new Date();
		var ret = d-this.lastTime;
		this.lastTime=d;
		return ret;
	},
	
	elapsedTotal: function(){
		var d = new Date();
		var ret = d-this.iniTime;
		this.lastTime=d;
		return ret;
	},
	
	wait: function(milisegundos){
		var date = new Date();
		var curDate = null;
		do { var curDate = new Date(); } 
		while(curDate-date < milisegundos);
	}
},
{
	time: function(callback){
		var crono = new Cronometro();
		callback();
		return crono.elapsed();
	}
});

/////////////////////////////////////////
//Amount permite sumar montos en diferentes monedas
var Amount=function(){
	this.bag = {};
}

Object.extend(Amount.prototype,{
	add:function(moneda,amount){
		switch(moneda.constructor){
		case Amount:
			var otherBag = moneda;
			for (var mone in otherBag.bag){
				if(!this.bag[mone]) this.bag[mone] = 0;
				this.bag[mone]+= otherBag.bag[mone];
			}
			return this;
			break;
		default:
			if(!this.bag[moneda]) this.bag[moneda] = 0;
			this.bag[moneda]+=Number(amount);
		}
	},
	
	minus:function(moneda,amount){
		switch(moneda.constructor){
		case Amount:
			var otherBag = moneda;
			for (var mone in otherBag.bag){
				if(!this.bag[mone]) this.bag[mone] = 0;
				this.bag[mone]-= otherBag.bag[mone];
			}
			return this;
			break;
		default:
			if(!this.bag[moneda]) this.bag[moneda] = 0;
			this.bag[moneda]-=Number(amount);
		}
	},
	
	get:function(moneda){
		if(!moneda) return this.bag;
		else return this.bag[moneda];
	},
	
	getCurrency:function(moneda){
		var ret="";
		if(!moneda) return $H(this.bag).collect(function(e){return e[1].currency(e[0])});
		return this.bag[moneda].currency(moneda);
	}
	
});



//////////////////////////////////////////////////////
//Event.Watcher permite saber en cualquier momento qué tecla estaba apretada dado que queda
//almacenado en Event.keyCode
Event.Watcher = Class.create();
Event.Watcher.prototype = {
  initialize: function() {
    Event.observe(document, 'keydown', this.onKeyPress.bindAsEventListener(this));
    Event.observe(document, 'keyup', this.onKeyUp.bindAsEventListener(this));
    //Event.observe(document, 'mousemove', this.onMouseMove.bindAsEventListener(this));
  },

  onKeyPress: function(event) {
		var code = event.keyCode;
    Event.keyCode = code;
		//Element.setStyle('culo',{'background-color':'#FF0000'});
    //if(code == Event.KEY_TAB) alert('Tab key was pressed');
  },
	
	onKeyUp:function(event){
		//Element.setStyle('culo',{'background-color':'transparent'});
		Event.keyCode = 0;
	}	
}

new Event.Watcher();

Object.extend(Event,{
	KEY_CONTROL: 17							
});

/////////////////////////////////////////////////////

Position._realOffset = Position.realOffset;
Position._cumulativeOffset = Position.cumulativeOffset;
Position._positionedOffset = Position.positionedOffset; 

Object.extend(Position,{
	realOffset: function(element){return this._realOffset($(element))},	
	cumulativeOffset: function(element){return this._cumulativeOffset($(element))},	
	positionedOffset: function(element){return this._positionedOffset($(element))},	
	
	screenOffset: function(element){
		var element = $(element);
		var cumulativeOffset = this.cumulativeOffset
		(element);
		var realOffset = this.realOffset (element);
		var screenOffset = cumulativeOffset.inject([],function(what,el,indx){
			what.push(el-realOffset[indx]);
			return what;
		});
		return screenOffset;
	},
	
	relativeOffset: function(element) { 
		var ret = [element.offsetLeft,element.offsetTop];
		element = element.parentNode;
		ret[0] -= element.offsetLeft;
		ret[1] -= element.offsetTop;
		return ret;
	}	
});



//////////////////////////

Error.create=function(obj){
	var err = new Error(-2146823281);
	err.name = "TypeError";
	if(typeof obj=="string") obj = {message:obj};
	Object.extend(err,obj);
	if(!err.message) err.message = err.description;
	if(!err.description) err.description = err.message;
	return err;
}

//////////////////////////////////////////////////////////


var Table = Table||{};
Object.extend(Table,{
	addRow: function(table,row,comodin){
		var table = $(table);
		var row = $(row);
		var tBody = table.getElementsByTagName('tbody')[0];
		var newRow;
		if(row) {
			oldRow = row;
			var newRow = row.cloneNode(true);
			tBody.insertBefore(newRow,row);
		}
		else newRow = tBody.appendChild(tBody.firstChild.cloneNode(true));
		newRow.cloned = true;
		if (!table.rowNum) table.rowNum=0;
		
		table.rowNum++;
		newRow.id = table.id+"_row_"+table.rowNum;
		newRow.style.display="";
		if(comodin==null) comodin = "***";

		for(var i=0;i<newRow.cells.length;i++){
			newRow.cells[i].innerHTML = String(newRow.cells[i].innerHTML).reemplazar(comodin, table.rowNum);
		}
			
		if(!table.rowsAdded) table.rowsAdded=new Array();
		table.rowsAdded[table.rowNum]=newRow;
		return table.rowNum;
	},
	
	getRow:function(table,rowNumber){
		var table = $(table);
		if(!table.rowsAdded) return null;
		return table.rowsAdded[rowNumber];
	},
	
	delRow: function(table,rowNumber){
		var table = $(table);
		var oldRow = Table.getRow(table,rowNumber);
		if(!oldRow || !oldRow.cloned) return;
		table.deleteRow(oldRow.sectionRowIndex);
		delete table.rowsAdded[rowNumber];
		table.normalize();
	},
	
	delAllRows: function(table){
		var table = $(table);
		if(!table.rowsAdded) return;
		table.rowsAdded.each(function(row,index){
			if(!Object.isNull(row)) Table.delRow(table,index);
		});
		table.rowNum=0;
	},
		
	upRow: function (table,rowNumber){
		var table = $(table);
		var oldRow = Table.getRow(table,rowNumber);
		if(!oldRow || !oldRow.cloned) return;
		var newRow = oldRow.previousSibling;
		if(!newRow || !newRow.cloned) return;
		if(newRow){
			Element.swapNodes(oldRow,newRow);
			return true;
		}
		else return false;
	},
	
	downRow: function (table,rowNumber){
		var oldRow = Table.getRow(table,rowNumber);
		if(!oldRow || !oldRow.cloned) return;
		var newRow = oldRow.nextSibling;
		if(!newRow || !newRow.cloned) return;
		if (newRow){
			Element.swapNodes(newRow,oldRow);
			return true;
		}
		else return false;
	}


});




///////////////////////////////////////////////////////////
Prototype.Selection = Base.extend({	
	constructor:function(options){
		this.options = Object.extend({
			key:null
		},options||{});
		
		//this.options.key = null; //está para que no use key por ahora, porque parece ser más lento.. es RARO!!!
		
		this.content = [];
		if(this.options.key) this.content = new Dictionary();
	},
	
	add: function(value){
		if (this.include(value)) return;
		if(this.options.key) this.content.add (value[this.options.key] , value);
		else this.content.push(value);
		if(value.onselect && typeof value.onselect=="function") value.onselect(this);
	},
	
	remove:function(value,options){
		if(options){
			var found = this.get(options);
			found.each(function(obj){
				this.remove(obj);
			}.bind(this));
			this.length = this.content.length;
			return found;
		}
		if(this.include(value)){
			if(value.ondeselect && typeof value.ondeselect=="function") value.ondeselect(this);
			if(this.options.key) this.content.remove(value[this.options.key]);
			else this.content = this.content.without(value);
			return value;
		}
	},
	
	count: function(){
		if(this.options.key) return this.content.count();
		return this.content.length;
	},
	
	get: function(obj){
		if(!obj) return this.content.select(function(e){return true});
		
		var content = this.content;
		
		if(this.options.key in obj) {
			var what = obj[this.options.key];
			if(what instanceof Prototype.Selection.Multiple) what = what.array;
			if (what instanceof Array) 
				content = what.inject([],function(arr,value){if(content.include(value)) arr.push(content.item(value));return arr});
				//	content = what.collect(function(element){return content.item(element)}.bind(this));
			else {
				var what = this.content.item(what);
				content =  what?[what]:[];
			}
			delete obj[this.options.key];
		}
		if(obj.instanceOf){
			return content.select(function(e){
				return e instanceof obj.instanceOf;
			});
		}
				
		return content.select(function(e){
			var ret = true;
			for (var i in obj) {
				if(obj[i] instanceof RegExp)
					ret &= String(obj[i]).test(e[i]);
				else {
					if(obj[i] instanceof Prototype.Selection.Multiple)
						ret &= obj[i].array.include(e[i]);
					else ret &= e[i]==obj[i];
				}
			}
			return ret;
		});
	},
	
	getFirst:function(obj){
		var ret = this.get(obj);
		return ret[0];
	},
	
	include:function(object){
		if(this.options.key) return this.content.include(object[this.options.key]);
		return this.content.include(object);
	},
	
	clear:function(){
		var _this = this;
		this.content.each(function(obj){
			_this.remove(obj);
		});
		this.content.clear();
	},
	
	addNew:function(value){
		this.clear();
		this.add(value);
	},
	
	update:function(objUpdate){
		this.content.each(function(obj){
			Object.extend(obj,objUpdate);
		});
	},
	
	toString:function(){
		return "Prototype.Selection ("+this.count()+")";
	}
});

var Selection = Selection || {};
Object.extend(Selection, new Prototype.Selection());

Prototype.Selection.Multiple = Base.extend({
	constructor: function(what){
		this.array = what;
	}
});




//////////////////////////////////////////

Dictionary = Base.extend({
	constructor: function(){
		this.repository = {};
		this.length = 0;
	},
	
	_each: function(iterator){
		for(var i in this.repository) iterator(this.repository[i],i);
	}
});

Dictionary.implement(Enumerable);

Dictionary.implement({
	add: function (key,value){
		if(arguments.length==1) {
			value = key;
			key = this.count();
		}
		if(key==undefined) key = this.count();
		this.repository[key] = value;
		this.length++;
	},
	
	remove: function(key){
		this.repository[key] = null;
		delete this.repository[key];
		this.length--;
	},
	
	item: function(key){
		return this.repository[key];
	},
	
	items: function(){
		return $H(this.repository).values();
	},
	
	include: function(key){
		return key in this.repository;
	},
	
	count: function(){
		return this.length;
		var cant = 0;
		for (var i in this.repository) cant++;
		return cant;
	},
	
	clear: function(){
		delete this.repository;
		this.repository = null;
		this.repository = {};
	}

});


////////////////////////////////////////////////////////




EventDispatcher=Base.extend({
	constructor:function(){
		///esta clase permite despachar eventos y es compatible con Event.observe !!!
		//console.debug("constructor de EventDispatcher");
	},
	
	observe:function(object){
		var events = ["click","dblclick","mouseover","mouseout","mousedown","mouseup"];
		events.each(function(event){
			Event.observe(object,event,function(e){
				(this["on"+event]||Prototype.K)(e);
			}.bind(this))
		}.bind(this));
	},
	
	observers:function(){
		if(!this._observers) this._observers = new Prototype.Selection();
		return this._observers;
	},

	addEventListener:function(name, observer, useCapture){
		//alert("agregando un evento:"+name);
		var observer = {name:name,observer:observer,useCapture:useCapture};
		this.observers().add(observer);
		if(!this["on"+name]) {
			this["on"+name] = function(){
				this.triggerEvent.apply(this,[name].concat($A(arguments)))
			}.bind(this);
		}
		else{
			if(!this["on"+name].__createdByEventDispatcher){
				var oldFn = this["on"+name];
				this["on"+name]=function(){
					this.triggerEvent.apply(this,[name].concat($A(arguments)));
					oldFn.apply(this,$A(arguments));
				}.bind(this);
			}
		}
		this["on"+name].__createdByEventDispatcher=true;
	},
	
	removeEventListener:function(name, observer, useCapture){
		this.observers().remove(null,{name:name,observer:observer});
	},
	
	triggerEvent:function (name){
		var args = $A(arguments);
		//console.debug(args.length);
		args.shift();
		var observers = this.observers().get({name:name});
		observers.each(function(observer){
			observer.observer.apply(this,args);
		}.bind(this));
	}
});
////////////////////////////////////



///TabGroup se encarga de mostrar y ocultar elementos que estén en el mismo grupo
TabGroup = EventDispatcher.extend({
	constructor: function(arrElements){
		this.displayed = 0;
		if(arrElements && arrElements instanceof Array){
			arrElements.each(function(element){
				this.add(element);
			}.bind(this));
			this.show();
		}
	},
	
	next:function(){
		this.displayed++;
		if(this.displayed>=this.content.length) this.displayed = 0;
		this.show();
	},

	previous:function(){
		this.displayed--;
		if(this.displayed<0) this.displayed = this.content.length-1;
		this.show();
	},
	
	show:function(which){
		this.get().invoke("hide");
		if(which) this.get().each(function(e,idx){if($(which)==e) this.displayed = idx}.bind(this));
		var element = this.get()[this.displayed];
		element.show();
	}
	
});

TabGroup.implement(new Prototype.Selection);

Object.extend(TabGroup.prototype,{
	_add: TabGroup.prototype.add,
	
	add: function(element){
		element = $(element);
		element.hide();
		this._add(element);
		//console.debug(element);
	}
})


////////////////////////////////////
//Este wrapper hace que el Builder devuelva un nodo con los métodos de Element

try{	
	Builder.__node = Builder.node;
	Builder.node = function(){
		return $(Builder.__node.apply(Builder,$A(arguments)));
	}
}catch(e){}


/////////////////////////////////


Object.extend(Math,{
	randRange:function(ini,fin,float){
		var range = fin-ini+1;
		return float?Math.random()*(range-1)+ini : Math.floor(Math.random()*range)+ini;
	}
});





/////CONSOLE///////////////////////////////////////////////////////////////
var console = console||{
	_output: function(what,options){
		var options = options || {};
		what.each(function(argument){
			var outputstring = String(argument).p();								 
			if(options.fontcolor) outputstring = outputstring.fontcolor(options.fontcolor);
			$('output').innerHTML += outputstring;
			$('output').scrollTop = 9000000;
		});
	},
	
	debug:function(){
		this._output($A(arguments));
	},
	
	error:function(){
		this._output($A(arguments),{fontcolor:"#FF0000"});
	},

	warning:function(){
		this._output($A(arguments),{fontcolor:"#AAAA00"});
	}
}
///////////////////////////////////////////////////////////////////////////





Element.Observer = Class.create();
Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  initialize: function(element, property, frequency, callback) {
		this.property = property;
		this.frequency = frequency;
    this.element   = $(element);
    this.callback  = callback;
    this.lastValue = this.getValue();

    /*if(element.watch) {
				element.watch(property,function(pro,oldval,newval){this.callback(this.element, newval)}.bind(this));
			console.debug(["watching "+property+" of ",this.element]);
		}
		else*/ this.registerCallback();
  },

	getValue: function() {
		var val = eval("this.element."+this.property);
		//console.debug(val);
    return val;
  }
});



///////////////////////////////////////////////
Choquin.Marquee = Base.extend({
	constructor: function(element, options){
		this.element = $(element);
		var height = this.element.offsetHeight;
		var width = this.element.offsetWidth;
		//console.debug(this.element.offsetHeight);
		this.options = {
			velocity: 8,
			force: false,
			timer: 100
		};
		Object.extend(this.options,options);
		
		if (! (this.container = $(this.element.id+"_marquee")) ) {
			this.container = Builder.node("div");
			this.container.id = this.element.id+"_marquee";
			this.element.parentNode.insertBefore(this.container,this.element);
		}
		
		this.container.setStyle({overflow:'auto'});
		
		this.container.appendChild(this.element);
		this.element.setStyle({width:'auto',position:'absolute',whiteSpace:'nowrap'});
		//if (!this.container.getStyle('height')) this.container.setStyle({height:height+'px'});
		//if (!this.container.getStyle('width')) this.container.setStyle({width:width+'px'});
		this.container.onclick = this.start.bind(this);
		this.container.onmouseover = this.pause.bind(this);
		this.container.onmouseout = this.resume.bind(this);

		new Element.Observer(this.element,"innerHTML",.5,this.element.flatten.bind(this.element));

		this.start();
	},
	
	start: function(){
		this.pos = -this.container.offsetWidth;
		clearInterval(this.interval);
		this.interval = setInterval(this.update.bind(this),this.options.timer);
	},
	
	pause: function(){
		clearInterval(this.interval);
		this.interval = null;
	},
	
	resume: function(){
		this.pause();
		this.interval = setInterval (this.update.bind(this),this.options.timer);
		this.lastTime = new Date();
	},
	
	update: function(){
		var vel = this.options.velocity * (new Date() - this.lastTime) / this.options.timer;
		this.pos+=vel;
		var width = this.getWidth();
		if(width<=this.container.offsetWidth) this.pos = 0;
		if(this.pos>width) this.start();
		var right = this.pos+this.container.offsetWidth+'px';
		var left = this.pos+'px';
		//right = '20px';
		//left = '0px';
		this.element.setStyle({clip:'rect(0px '+right+' auto '+left+')'});
		this.element.setStyle({marginLeft:-this.pos+'px'});
		this.lastTime = new Date();
		//console.debug(this.element.getStyle('clip'));
	},
	
	getWidth: function(){
		return parseFloat(this.element.offsetWidth);
	}
});



////////////////////////////////////////////////////////
//extensión para las clases de GoogleMaps

if(window.GLatLng){
	Object.extend(GLatLng.prototype,{
		toArray: function(){
			return [this.lat(),this.lng()];
		},
		toJSONString: function(){return "["+this.toArray()+"]";}
	});
	
	Object.extend(GLatLngBounds.prototype,{
		toArray: function(){
			return this.getNorthEast().toArray().concat(this.getSouthWest().toArray());
		},
		
		toJSONString: function(){
			return "["+this.toArray()+"]";
		}
	});
	
	
	
	function K_CrossControl(image,size)
		{
			this.size=size?size:new GSize(20,20);
			this.image=image?image:"http://www.step1.cn/map/cross.gif";
			this.div=document.createElement("div");
			this.img=document.createElement("img");
			this.div.appendChild(this.img);
			this.div.style.position="absolute";
			this.img.style.position="absolute";
		}
		K_CrossControl.prototype=new GControl(true,false);
		K_CrossControl.prototype.initialize=function(map)
		{
			if(this.img.src!=this.image)
			{
				this.img.src=this.image;
			}
			this.img.width=this.size.width;
			this.img.height=this.size.height;
			this.map=map;
			this.resetSize();
			map.getContainer().appendChild(this.div);
			GEvent.bind(map,"resize",this,this.resetSize());
			return this.div;
		}
		K_CrossControl.prototype.resetSize=function()
		{
			var size=this.map.getSize();
			this.img.style.left=(size.width/2-this.size.width/2)+"px";
			this.img.style.top=(size.height/2-this.size.height/2)+"px";
		}
		K_CrossControl.prototype.getDefaultPosition=function()
		{
			return new GControlPosition(G_ANCHOR_TOP_LEFT,new GSize(0,0));
		}
	
}



////////////////////////////////
//flash fix for IE:
/*function FlashFix(){
	theObjects = document.getElementsByTagName("object"); 
	for (var i = 0; i < theObjects.length; i++) { 
		if(!theObjects[i].outerHTML) return;
		theObjects[i].outerHTML = theObjects[i].outerHTML; 
	}
}*/


/*
<div class="flash"  style="width:200px;height:100px" isflash="true" background-color="#336699" src="/albums/db/portadas/alf.swf" version="7" wmode="transparent" flashvars="a=1&b=2">[...]</div>
*/

function Div2Flash(flash){
	if(typeof SWFObject=="undefined") {
		console.debug("No se encuentra registrado SWFObject");
		return;
	}

	var flash=$(flash);
	if(!flash.id) flash.id = "flashcontent_"+String.randomString(20);

	var width = flash.getAttribute("width")||flash.style.width;
	var height = flash.getAttribute("height")||flash.style.height;
	var bgColor = flash.getAttribute("background-color");
	var version = flash.getAttribute("version")||"8";
	var src= flash.getAttribute("src");
	var wmode = flash.getAttribute("wmode");
	var quality = flash.getAttribute("quality")||"high";
	var flashvars = flash.getAttribute("flashvars")||"";
	flashvars = flashvars.split("&");
	//alert(src+"\n"+flash.id+"\n"+width+"\n"+height+"\n"+version+"\n"+bgColor);
	
	var so = new SWFObject(src, flash.id, width, height, version, bgColor);

	
	if(wmode) so.addParam("wmode", wmode);
	if(quality) so.addParam("quality", quality);
	
	for(var ii=0;ii<flashvars.length;ii++){
		var variable = flashvars[ii].split("=");
		so.addVariable(String(variable[0]), String(variable[1]));
	}
	//so.setAttribute('redirectUrl', 'http://www.adobe.com/go/getflashplayer');

	//so.addVariable("variable2", "value2");
	so.write(flash.id);
	
	flash.id="div_"+flash.id;
	flash.setAttribute("isflash","false");
	flash.setAttribute("className","");

}

function FlashFix(){
	if(!document.getElementsByAttribute || typeof SWFObject=="undefined") return;
	//alert("antes del stack overflow");
	var flashs = document.getElementsByAttribute("isflash","true");

	for(var i=0;i<flashs.length;i++){
		var flash = flashs[i];
		Div2Flash(flash);
	}
	
	//alert("despúes del stack overflow");

}


//Event.observe(window, 'load', function(){FlashFix()}, false);
