var FECHA_ISO = 0;
var FECHA_USA = 1;
var FECHA_EUROPA = 2;

function Calendario(sId, fecha, iFormato){
	this.m_sId = sId;
	
	this.m_oDateNow = null;
	this.m_oDateSel = null;
	
	this.m_iMaxSeleccion = 0; //no se puede seleccionar ningun dia

	this.getIdForm = function(){return "form_"+this.m_sId;}
	this.getForm = function(){return document.getElementById(this.getIdForm());}
		
	/**
		establece el maximo numero de selecciones que se puede hacer sobre el calendario
	@param	int	iMax: maximo numero de selecciones sobre el calendario */
	this.setMaxSeleccion = 
	function(iMax){
		if (iMax==undefined)
			var iMax = 0;
			
		if (iMax<0)
			iMax = Number.MAX_VALUE;
	}

	/**
		Establece los valores de año, dia y mes en la instancia actual de calendario
	@param	mixed	fecha: numero de milesiomas de segundo desde el 1 de enero de 1970 
						o un objeto Date
						o una cadenda de caracteres con la fecha en formato iFormato
	@param	int		iFormato: formato de la fecha (FECHA_ISO, FECHA_USA o FECHA_EUROPA). FECHA_EUROPA por DEF ECTO
	@return	bool	true si todo ha ido bien y false en caso contrario
	@access	public */	
	this.setFechaActual = 
	function(fecha, iFormato){
		var d = Calendario.makeDate(fecha, iFormato);
		this.m_oDateNow = d;		

		var f = this.getForm();
		if (f)
			f.elements.timenow.value=d.getTime();
	}
	
	/**
		Establece los valores de año, dia y mes en la instancia actual de calendario
	@param	mixed	fecha: numero de milesiomas de segundo desde el 1 de enero de 1970 
						o un objeto Date
						o una cadenda de caracteres con la fecha en formato iFormato
	@param	int		iFormato: formato de la fecha (FECHA_ISO, FECHA_USA o FECHA_EUROPA). FECHA_EUROPA por DEF ECTO
	@return	bool	true si todo ha ido bien y false en caso contrario
	@access	public */
	this.setFecha = 
	function(fecha, iFormato){
		var d = Calendario.makeDate(fecha, iFormato);

		this.m_oDateSel = d;

		var f = this.getForm();
		if (f)
			f.elements.time.value=d.getTime();
	}
	
	/** 
		Dice si el año actual (m_oDateSel.getFullYear()) es bisiesto o no
	@return	bool
	@access	protected*/
	this.esBisiesto = 
	function(){
		return (this.m_oDateSel.getFullYear()%4==0);
	}
	
	/**
		Dado un mes, devuelve el numero de dias que tiene el mismo
	@param	int	iMes: numero 0-11 del mes 
	@return	int	Numero de dias del mes
	@access	protected*/
	this.numDiasMes = 
	function(iMes){
		if (iMes==undefined)
			var iMes = this.m_oDateSel.getMonth();
		switch(iMes){
		case 0: //enero
		case 2: //marzo
		case 4: //mayo
		case 6: //julio
		case 7: //agosto
		case 9: //octubre
		case 11: //diciembre
			return 31;
		case 1: if (this.esBisiesto()) return 29; else return 28; //febrero
		default:
			return 30;
		}
	}
		
	/**
		Obtiene el nombre del mes indicado
	@param	int	iMes: numero del mes (0-11). si no se especifica se toma el mes señalado del calendario
	@return	string	nombre del mes indicado
	@param protected
	*/
	this.nombreMes = 
	function(iMes){
		if (iMes == undefined)
			var iMes = this.m_oDateSel.getMonth();
	
		switch(iMes){
		case 0: return "Enero";
		case 1: return "Febrero";
		case 2: return "Marzo";
		case 3: return "Abril";
		case 4: return "Mayo";
		case 5: return "Junio";
		case 6: return "Julio";
		case 7: return "Agosto";
		case 8: return "Septiembre";
		case 9: return "Octubre";
		case 10: return "Noviembre";
		case 11: return "Diciembre";
		}
		return "";
	}
	
	/**
		Obtiene el nombre del mes indicado
	@param	int	iMes: numero del mes (0-11). si no se especifica se toma el mes señalado del calendario
	@return	string	nombre del mes indicado
	@param protected
	*/
	this.nombreDiaSemana = 
	function(iDia, iMes, iAno){
		if (iDia == undefined) var iDia = this.m_oDateSel.getDate();
		if (iMes == undefined) var iMes = this.m_oDateSel.getMonth();
		if (iAno == undefined) var iAno = this.m_iAno;
			
		switch(new Date(iAno, iMes, iDia).getDay()){
		case 0: return "Domingo";
		case 1: return "Lunes";
		case 2: return "Martes";
		case 3: return "Mi&eacute;rcoles";
		case 4: return "Jueves";
		case 5: return "Viernes";
		case 6: return "S&aacute;bado";
		}
		return "";
	}
		
	
	/**
		Dice si el primer dia del mes es lunes = 0, martes=1,...., domingo=1
	@return	int	(0..6)
	@access	protected*/
	this.primerDiaMes = 
	function(){
		var d = new Date(this.m_oDateSel.getFullYear(), this.m_oDateSel.getMonth(), 1);
		return (d.getDay()+6)%7; //0=lunes, 1=martes,... 6=domingo
	}
	
	
	/**
		Dice si el dia indicado se trata de un día festivo o no
	@param	int	iDia:  dia del mes
	@param	int	iMes: numero del mes (0-11)
	@param	int	iAno: año
	@return	bool	true si el dia es festivo y false en caso contrario
	@access	protected */
	this.esFestivo = 
	function(iDia, iMes){
		/*FESTIVOS NACIONALES:
		1 de enero: Año Nuevo
		6 de enero: Epifanía del Señor
		25 de marzo: Viernes Santo
		15 de agosto: Fiesta de la Asunción de la Virgen
		12 de octubre: Fiesta Nacional de España
		1 de noviembre: Todos los Santos
		6 de diciembre: Día de la Constitución
		8 de diciembre: Inmaculada Concepción
		*/
		if (iDia == undefined) var iDia = this.m_oDateSel.getDate();
		if (iMes == undefined) var iMes = this.m_oDateSel.getMonth();

		var d = new Date(this.m_oDateSel.getFullYear(), iMes, iDia);
		if (d.getDay()==0) //si es domingo
			return true;
		switch(iMes){
		case 0: //enero
			return (iDia==1 || iDia==6);
		case 2: //marzo
			return (iDia==25);
		case 7: //agosto
			return (iDia==15);
		case 9: //octubre
			return (iDia==12);
		case 10: //noviembre
			return (iDia==1);
		case 11: //diciembre
			return (iDia==6 || iDia==8);
		}//switch
		return false;
	}//esFestivo

	/**
	*/
	this.deshabilitar = 
	function(){
		this.habilitar(false);
	}
	
	/**
	*/
	this.habilitar = 
	function(bHabilitar){
		if (bHabilitar==undefined)
			var bHabilitar = true;
		
		var tiempo = 0;
		if (bHabilitar)
			tiempo = 50;
			
		var s = 'var e=null; var bHabilitar='+bHabilitar+';'
		+'e = document.getElementById("'+this.m_sId+'_anopre"); if (e) e.disabled = !bHabilitar;'
		+'e = document.getElementById("'+this.m_sId+'_mespre"); if (e) e.disabled = !bHabilitar;'
		+'e = document.getElementById("'+this.m_sId+'_actual"); if (e) e.disabled = !bHabilitar;'
		+'e = document.getElementById("'+this.m_sId+'_mespos"); if (e) e.disabled = !bHabilitar;'
		+'e = document.getElementById("'+this.m_sId+'_anopos"); if (e) e.disabled = !bHabilitar;'
		+'e = document.getElementById("'+this.m_sId+'_select"); if (e) e.disabled = !bHabilitar;';
	
		this.timeout = setTimeout(s, tiempo );
	}
	
	/**
		Muestra el calendario por la salida estandar del navegador o actualiza el navegador si ya existe en el documento
	@access	public*/
	this.mostrar = 
	function(){
		var capa = document.getElementById(this.m_sId+"_contenido");
		
		if (capa){
			//this.deshabilitar();
			capa.innerHTML = this.generarHTML();
			//this.habilitar();
		}else{
			document.writeln(this.generarHTMLFormulario());
			document.writeln('<table id="'+this.m_sId+'" class="calendario">');
			document.writeln('<tr>');
			document.writeln('<td class="controles">'+this.generarHTMLControles()+'</td>');
			document.writeln('</tr><tr>');
			document.writeln('<td id="'+this.m_sId+'_contenido" class="contenido" align="center">'+this.generarHTML()+'</td>');
			document.writeln('</tr></table>');
			document.writeln('</form>');
		}
		//cambiar formulario con los nuevos datos
		var formu = this.getForm();
		formu.elements.time.value = this.m_oDateSel.getTime();
		formu.elements.timenow.value = this.m_oDateNow.getTime();
		formu.elements.calendar_id.value = this.m_sId;
		formu.elements.selectmonth.selectedIndex = this.m_oDateSel.getMonth();
		var eAno = document.getElementById(this.m_sId+'_ano');
		eAno.innerHTML = this.m_oDateSel.getFullYear();
	}	
	
	/**
	@access	protected*/
	this.generarHTMLFormulario = 
	function (){
		var s = '';
		s+='<form id="form_'+this.m_sId+'">';
		s+='<input type="hidden" name="time" value="" />';
		s+='<input type="hidden" name="timenow" value="" />';
		s+='<input type="hidden" name="calendar_id" value="" />';
		s+='<select name="seleccion" multiple="multiple"></select>';
		return s;
	}

	/**
	@access	protected*/
	this.generarHTMLControles = 
	function (){
		var s = '';
		s+='<table width="100%"><tr>';		
		s+='<td align="left"><input type="button" name="preyear" class="button" value="&lt;&lt;" onclick="Calendario.cambiarAno(this.form, -1)" /></td>';
		s+='<td align="left"><input type="button" name="premonth" class="button" value="&lt;" onclick="Calendario.cambiarMes(this.form, -1)"  /></td>';
		s+='<td align="center"><input type="button" name="today" class="button" value="*" onclick="new Calendario(this.form.calendar_id.value, parseInt(this.form.timenow.value)).mostrar();" /></td>';
		s+='<td align="right"><input type="button" name="posmonth" class="button" value="&gt;" onclick="Calendario.cambiarMes(this.form, 1)"  /></td>';
		s+='<td align="right"><input type="button" name="posyear" class="button" value="&gt;&gt;" onclick="Calendario.cambiarAno(this.form, 1)"  /></td>';
		s+='</tr><tr>';
		s+='<td colspan="5"><table width="100%"><tr>';
		s+='<td><select name="selectmonth" onchange="Calendario.cambiarMes(this.form, this.value, true)"  >';
		for (var i = 0; i<12; i++){
			s+='<option';
			if (i == this.m_oDateSel.getMonth())
				s+=' selected="selected"';
			s+=' value="'+i+'">'+this.nombreMes(i)+'</option>';
		}
		s+='</select></td>';
		s+='<td align="right"><span id="'+this.m_sId+'_ano">'+this.m_oDateSel.getFullYear()+'</span></td></tr></table>';
		s+='</tr></table>';
		return s;
	}

	
	/**
		Devuelve el codigo HTML del calendario
	@return	string;
	@access	protected */
	this.generarHTML = 
	function(){
		var i,j,aux;
		var s = '';
		//s+=new Date(this.m_oDateSel.getFullYear(), this.m_oDateSel.getMonth(), this.m_oDateSel.getDate()).toString();
		
		//return s;
		s+='<table width="100%" border="0" cellpadding="0" cellspacing="0"><thead><tr>\n';
		
//		
//		s+='</tr><tr>';
		
		//cabecera dias
		s+='<th>L</th>\n';
		s+='<th>M</th>\n';
		s+='<th>X</th>\n';
		s+='<th>J</th>\n';
		s+='<th>V</th>\n';
		s+='<th>S</th>\n';
		s+='<th>D</th>\n';	
		s+='</tr></thead>\n';
		
		s+='<tbody>\n';
		//
		s+='<tr>\n';
		for(j=0; j<this.primerDiaMes(); j++)
			s+='<td>&nbsp;</td>\n';
		var dia;
		var d = this.m_oDateSel;
		for(i=j; i<this.numDiasMes()+j; i++){
			if ((i>6) && (i%7==0))
				s+='</tr><tr>\n';
			dia = ((i-j)+1);
			if (dia==this.m_oDateNow.getDate() && this.m_oDateSel.getMonth()==this.m_oDateNow.getMonth() && this.m_oDateSel.getFullYear()==this.m_oDateNow.getFullYear())
				aux = '<b>'+dia+'</b>';
			else
				aux = dia;

			if (this.esFestivo(dia)){
				aux = '<div style="color:red">'+aux+'</div>';
			}else{
				aux = '<div>'+aux+'</div>';
			}
			
			d.setDate(dia);
			aux = '<a href="#" onclick="if (this.className==\'seleccionado\') this.className=\'\'; else this.className=\'seleccionado\'; Calendario.seleccionarDia(\''+this.getIdForm()+'\', '+d.getTime()+')">'+aux+'</a>';
							
			s+='<td>'+aux+'</td>\n';
		}//for i
		i = this.numDiasMes()+j;
		while(i%7!=0){
			s+='<td>&nbsp;</td>\n';
			i++;
		}
		s+='</tr></tbody></table>\n';
		return s;
	}
	
	this.setFecha(fecha, iFormato);
	this.setFechaActual(fecha, iFormato);
	
	//alert(fecha);
}//Calendario

/**
	Crea un objeto date y lo devuelve a partir de los parametros pasados
*/
Calendario.makeDate = 
function(fecha, iFormato){
	var d = null;
	
	switch(typeof(fecha)){
	case "number": //numero de milesimas de segundo desde el 1 de enero de 1970
		d = new Date(fecha);
		break;
	case "object":
		if (!fecha.getFullYear)
			return false;
		d = fecha;
		break;
	case "string":
		switch(iFormato){
		case FECHA_ISO:
		case FECHA_EUROPA:
		case FECHA_USA:
		}
		break;
	default:
		d = new Date();
	}	
	return d;
}

/**
	cambia el año del calendario
	@param	object	formu: el objeto formulario del calendario en el documento
	@param	int	iMod: cuantos años se quiere atrasar o adelantar el calendario
	@param	bool	bAbsoluto: si se indica bAbsoluto=true entonces iMod se correspondera con el año que se desea poner (ej: 2006)
					falso por defecto.
*/
Calendario.cambiarAno = 
function(formu, iMod, bAbsoluto){
	if (bAbsoluto==undefined)
		var bAbsoluto = false;
	var d=new Date(parseInt(formu.elements.time.value));	
	
	var iAux;
	if 	(bAbsoluto)
		iAux = iMod;	
	else
		iAux = d.getFullYear()+iMod;
	
	d.setFullYear(iAux); 
	
	var hoy = parseInt(formu.elements.timenow.value);
	var cal = new Calendario(formu.calendar_id.value, d);
	cal.setFechaActual(hoy);
	cal.mostrar();
}

/**
	cambia el mes del calendario
	@param	object	formu: el objeto formulario del calendario en el documento
	@param	int	iMod: 1 si quiere atrasar o -1 para adelantar el calendario
	@param	bool	bAbsoluto: si se indica bAbsoluto=true entonces iMod se correspondera con el mes que se desea poner (0..11)
					falso por defecto.	
*/
Calendario.cambiarMes = 
function(formu, iMod, bAbsoluto){
	var d = null;
	
	d = new Date(parseInt(formu.elements.time.value));
	var iMes = d.getMonth();
	
	if 	(bAbsoluto){
		iMes = parseInt(iMod);
	}else{
		iMes += iMod;
	}//else

	d.setMonth(iMes,1);	

	var hoy = parseInt(formu.elements.timenow.value);
	var cal = new Calendario(formu.calendar_id.value, d);
	cal.setFechaActual(hoy);
	cal.mostrar();
}

/**
	@param	mixed	
*/
Calendario.seleccionarDia = 
function(sIdForm, fecha){
	var formu = document.getElementById(sIdForm);
	if (!formu) formu = document.forms[sIdForm];
	if (!formu){
		var calendar_id = document.getElementsByName('calendar_id')[0];
		if (calendar_id) formu = calendar_id.form;
	}
	if (!formu)
		return false;

	var d = Calendario.makeDate(fecha);
		
	var eSeleccion = formu.elements["seleccion"];
	
	var valor = d.getFullYear()+'-'+(d.getMonth()+1)+'-'+d.getDate();
	
	var iPos = -1; //posicion de la opcion que coincida con el valor de valor
	for (var i = 0; i<eSeleccion.options.length; i++){
		if (eSeleccion.options[i].value==valor){
			iPos = i;
			break;
		}
	}

	if (iPos<0){ //si no existia ya esta opcion, se añade la opcion
		var eOpcion = document.createElement("option");
		eOpcion.value = valor;
		eOpcion.text = valor;
		eOpcion.selected = true;
	
		if (document.all)
			eSeleccion.add(eOpcion,0);
		else
			eSeleccion.add(eOpcion,null);
	}else{ //si síq ue existía se elimina la opcion
		eSeleccion.remove(iPos);
	}
}
