function calder(opts) {
	//Constructor
	
	//Checks if the first argument of the constructor is object if it is not failt to create calendar, and if it is sets  the object in the options variable
	if ($type(opts) == "object") {
		this.options = opts;
	} else {
		alert("(calder: No properties applied, calendar not created.)" );
		return
	}		

	//Checks the options variable for referer element if not fount failt to create calendar
	if (this.options.referer == undefined || $type(this.options.referer) != "element")  {
		alert("(calder: No referer element selected, calendat not created.)")
		return
	}
	
	//Array that hold the month and days captions
	this.sMonths = ["Ene","Feb","Mar","Abr","May","Jun","Jul","Ago","Sep","Oct","Nov","Dic"];
	this.sDays = ["Lun","Mar","Mie","Jue","Vie","Sab","Dom"];
	
	//checks the options for Class definitions to be applied to all the elements.
	if (this.options.className == undefined || this.options.className == "") {
		this.options.className = "calder";
	}
	
	//Calendar is positioned at top or at the bottom of the referer element
	if (this.options.position != "top") {
		this.options.position = "bottom";
	}

	//Private method for returning the classname.
	this.getClassName = function (sufix) {
		return this.options.className + "-" + sufix;
	}
	
	
	//Creates the calendar wrapper
	this.options.holder = new Element("div");
	$$("body").adopt(this.options.holder);

	this.hideCalendar = function() {
		this.options.holder.innerHTML = "";
		this.options.holder.setStyles({
			"position":"absolute",
			"top":"-9999px",
			"left":"-9999px"
		});
		this.options.visible = false;
	}
	this.hideCalendar();
	
	this.toggle = function() {
		if (!this.options.visible) {
			this.setvDate(this.sDate);
			this.buildCalendar();
		} else {
			this.hideCalendar();
		}
	}
	
	if ($type(this.options.handlers) == "array") {
		for (var i=0; i<this.options.handlers.length; i++) {
			if ( $type(this.options.handlers[i]) == "element" ) {
				this.options.handlers[i].onmouseup = this.toggle.bind(this);
				
			}
		}
	}	

	this.setRefererDate = function() {
		//this.options.referer.value = this.sDate.getFullYear() + "/" + (this.sDate.getMonth()+1) + "/" + this.sDate.getDate();
		this.options.referer.value = this.sDate.getDate() + "/" + (this.sDate.getMonth()+1) + "/" + this.sDate.getFullYear(); // EMR
	}
	
	this.setsDate = function(date) {
		if (date != undefined) {
			this.sDate = new Date(date);
		}
		if (this.sDate == "Invalid Date") {
			this.sDate = new Date();
			this.setRefererDate();
		}
	}
	// Poner el valor al cargar el calendario, pero no se puede quitar por lo que ...
	this.setsDate(this.options.referer.value);
	// ...una vez cargado con el valor inicial, ponemos el que queramos que sea inicial
	this.options.referer.value = "seleccione"; // EMR
	
	this.setvDate = function(dateObj) {
		this.vDate = new Date(dateObj);
		this.aDate = new Date(this.vDate);
		this.aDate.setDate(1);
		
		this.nmDate = new Date(this.vDate);
		this.nmDate.setMonth(this.nmDate.getMonth() + 1);
		
		this.pmDate = new Date(this.vDate);
		this.pmDate.setMonth(this.pmDate.getMonth() - 1);
	}
	
	this.catr = function(txt, func, args, tdclass) {
		var tds = new Element("td");
		var tma = new Element("a");
			tma.href = "javascript:;"
			tma.innerHTML = txt;
			tma.onmouseup = this[func].bind(this, args);
			if (tdclass != "") {
				tma.addClass(tdclass);
			}			
		tds.adopt(tma);
		return tds;
	}
	
	this.buildCalendar = function() {
		this.cDate = new Date(this.getFormated(new Date()));
		
		var wrapper = new Element("div");
			wrapper.addClass( this.getClassName("wrapper") );
			
		var table = new Element("table");
			table.addClass( this.getClassName("table") );
			table.setProperties({ cellspacing : 0, cellpadding: 2, border: 0 });
		
		//Create Menu
		var tr = new Element("tr");
			tr.addClass( this.getClassName("menu") );	
			tr.adopt( this.catr("<<", "previousYear") );
			tr.adopt( this.catr("<", "previousMonth") );
			
		var td = new Element("td");
			td.setProperty("colspan","3");		
			td.innerHTML = this.sMonths[this.aDate.getMonth()] + " / " + this.aDate.getFullYear();
			tr.adopt(td);
			
			tr.adopt( this.catr(">", "nextMonth") );
			tr.adopt( this.catr(">>", "nextYear") );									
			
		table.adopt(tr);
		
		//Create day titles	
		var tr = new Element("tr");
			tr.addClass( this.getClassName("dayLength") );
			
		for (var i = 0; i < 7; i++) {
			var td = new Element("td");
				td.innerHTML = this.sDays[i];
				tr.adopt(td);
		}
		table.adopt(tr);

		//Create dates cells
		while ( this.aDate.getDay() != 1) {
			this.aDate.setDate( this.aDate.getDate() -1);
		}
		
		while ( this.aDate.getDay() != 1 || this.aDate.getMonth() != this.nmDate.getMonth() ) {
			if (this.aDate.getDay() == 1) {
				var tr = new Element("tr");
					tr.addClass( this.getClassName("datesLength") )
			}
				this.options.cclass = "";
				if ( this.sDate.toString() == this.aDate.toString() ) {
					this.options.cclass += this.getClassName("selectedDay ");
				} 
				if ( this.vDate.getMonth() != this.aDate.getMonth() ) {
					this.options.cclass += this.getClassName("outDay ");
				} 
				if ( this.cDate.toString() == this.aDate.toString() ) {
					this.options.cclass += this.getClassName("today ");
				} 
				if ( this.aDate.getDay() == 0) {
					this.options.cclass += this.getClassName("weekEndSut ");				
				}
				if ( this.aDate.getDay() == 6) {
					this.options.cclass += this.getClassName("weekEndSun ");				
				}				
				tr.adopt( this.catr(this.aDate.getDate(), "pickDate", this.getFormated(this.aDate), this.options.cclass )  )
				
			if (this.aDate.getDay() == 0) {
				table.adopt(tr);
			}
			this.aDate.setDate(this.aDate.getDate() +1);
						
		}
		table.adopt(tr);

		wrapper.adopt(table);
		this.options.holder.innerHTML = "";
		this.options.holder.adopt(wrapper);
		this.holderPosition();
		this.options.visible = true;
	}
	
	this.holderPosition = function() {
		if (this.options.position == "top" && this.options.referer.getTop() - this.options.holder.getCoordinates().height >= 0) {
			this.options.holder.setStyles({
				"left": this.options.referer.getLeft() + "px" ,
				"top": this.options.referer.getTop() - this.options.holder.getCoordinates().height + "px"
			})
		} else {
			this.options.holder.setStyles({
				"left": this.options.referer.getLeft() + "px" ,
				"top": this.options.referer.getTop() + this.options.referer.getCoordinates().height + "px"
			})		
		}
	}
		
	this.nextYear = function() {
		this.vDate.setFullYear(this.vDate.getFullYear() + 1);
		this.setvDate(this.vDate);
		this.buildCalendar();
	}
	
	this.nextMonth = function() {
		this.vDate.setMonth(this.vDate.getMonth() + 1);
		this.setvDate(this.vDate);
		this.buildCalendar();
	}
	
	this.previousYear = function() {
		this.vDate.setFullYear(this.vDate.getFullYear() - 1);
		this.setvDate(this.vDate);
		this.buildCalendar();
	}
	
	this.previousMonth = function() {
		this.vDate.setMonth(this.vDate.getMonth() - 1);
		this.setvDate(this.vDate);
		this.buildCalendar();
	}			
	
	this.pickDate = function(arg) {
		this.setsDate(arg);
		this.setRefererDate();
		this.hideCalendar();
	}
	
	this.getFormated = function(arg) {
		return arg.getFullYear() + "/" + (arg.getMonth()+1) + "/" + arg.getDate();
	}
	
	this.refererChange = function() {
		this.setsDate(this.options.referer.value);
		this.setvDate(this.sDate);
		if (this.options.visible) {
			this.buildCalendar();
		}
		this.setRefererDate();
	}
	
	this.options.referer.onchange = this.refererChange.bind(this);
}