/*
 * Creado el 11-dic-03
 *
 * Para cambiar la plantilla para este archivo generado vaya a
 * Ventana&gt;Preferencias&gt;Java&gt;Generación de código&gt;Código y comentarios
 */
package es.ejie.frmk.infraestructura.tablas;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Vector;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.struts.Globals;
import org.apache.struts.util.RequestUtils;

import es.ejie.frmk.infraestructura.traza.Q70TraceLevel;
import es.ejie.frmk.infraestructura.traza.Q70Traza;
import es.ejie.frmk.presentacion.iu.taglib.base.Q70Constants;


/**
 * @author UFRM002
 *
 * Para cambiar la plantilla para este comentario de tipo generado vaya a
 * Ventana&gt;Preferencias&gt;Java&gt;Generación de código&gt;Código y comentarios
 */
public class Q70TablasCodigosTag extends TagSupport{

	//	------------------------------------------------------------------ Instance Variables 

	/**
	 * Constante que indica el componente al que pertenece dicha clase. Es
	 * necesario para el uso del log de trazas.
	 */
	protected static final String COMPONENTE = Q70Constants.COMPONENTE_CUSTOM_TAG;

	/**
	 * Instancia del log de trazas
	 */
	private static Q70Traza tr = Q70Traza.getSingleton();


	/**
	 * Clave de session que tiene el Locale para el idioma de los datos de resultado.
	 */
	protected String localeKey = Globals.LOCALE_KEY;

	/**
	 * Maps lowercase JSP scope names to their PageContext integer constant values. 
	 */
	private static Map scopes = new HashMap();
    
	/**
	 * Initialize the encode variable with the 1.4 method if available.  Also set up the
	 * scope map values.
	 */
	static {
		scopes.put("page", new Integer(PageContext.PAGE_SCOPE));
		scopes.put("request", new Integer(PageContext.REQUEST_SCOPE));
		scopes.put("session", new Integer(PageContext.SESSION_SCOPE));
		scopes.put("application", new Integer(PageContext.APPLICATION_SCOPE));
	}	
	
	
	//	------------------------------------------------------------------  Propiedades

	// Nombre del bean que se carga con los resultados 
	private String name = Q70Constants.TABLAS_BEAN;
	
	//Nombre completo de la clase java a la que pertenece el bean.
	private String type = null;	
	
	// Scope del bean que se carga con los resultados
	private String scope = null;	
	
	// Lista completa de opciones
	private String options = null;

	// Lista de opciones extra
	private String extraOptions = null;
	
	// Nombre de la tabla de la que se obtiene los datos
	private String table = null;
	
	// Nombre de la columna cuyos datos muestra el tag. 
	// Es la primera columna de la parte 'select' (o sujeto) de la consulta a lanzar.
	private String labelColumn = null;


	private String valueColumn = null;


	//Condiciones de la Consulta a lanzar contra el Gestor de Tablas y Codigos
	private String whereClause = null;	


	// -------------------------------------------------------------------  Metodos de acceso a propiedades

	public String getLocale() {
		return (this.localeKey);
	}

	public void setLocale(String locale) {
		this.localeKey = locale;
	}

	/**
	 * @return
	 */
	public String getName() {
		return name;
	}
	/**
	 * @param string
	 */
	public void setName(String name) {
		this.name = name;
	}
		
		
	public String getScope() {
		return (this.scope);
	}

	public void setScope(String scope) {
		this.scope = scope;
	}
		
		
	/**
	 * @return
	 */
	public String getOptions() {
		return this.options;
	}
	/**
	 * @param strings
	 */
	public void setOptions(String options) {
		this.options = options;
	}
		 
	/**
	 * @return
	 */
	public String getExtraOptions() {
		return extraOptions;
	}	
	/**
	 * @param strings
	 */
	public void setExtraOptions(String extraOptions) {
		this.extraOptions = extraOptions;
	}
	
	
	/**
	 * @return
	 */
	public String getTable() {
		return table;
	}
	/**
	 * @param string
	 */
	public void setTable(String string) {
		this.table = string;
	}

	/**
	 * @return
	 */
	public String getLabelColumn() {
		return labelColumn;
	}
	/**
	 * @param string
	 */
	public void setLabelColumn(String string) {
		this.labelColumn = string;
	}
	
	/**
	 * @return
	 */
	public String getValueColumn() {
		return valueColumn;
	}
	/**
	 * @param string
	 */
	public void setValueColumn(String string) {
		valueColumn = string;
	}	
	
	/**
	 * @return
	 */
	public String getWhereClause() {
		return whereClause;
	}	
	/**
	 * @param string
	 */
	public void setWhereClause(String whereClause) {
		this.whereClause = whereClause;
	}



	public String getType() {
		return (this.type);
	}

	public void setType(String type) {
		this.type = type;
	}






	//	------------------------------------------------------------------  Constructor

	/**	 Constructor */
	public Q70TablasCodigosTag(){ }



	//	------------------------------------------------------------------  Metodos Publicos

	/**
	  * Process the start of this tag.  The default implementation does nothing.
	  *
	  * @exception JspException if a JSP exception has occurred
	  */
	public int doStartTag() throws JspException 
	{
		if (tr.isTraceActive()) {		
			tr.trace(COMPONENTE, Q70TraceLevel.INFO, "Entrando en doStartTag de Q70TablasCodigosTag...");
		}

		// Obtener los resultados de la consulta realizada al Gestor de Tablas y Codigos	
		Object dataBean = getData();
	
		if (null != dataBean) {
			//Poner los resultados en el alcance (scope) adecuado 
			storeData(dataBean);
		} 		
		
		return SKIP_BODY;
		
	}


	 
	/** Release any acquired resources.*/
	public void release() {
		super.release();
	}	 


	// -------------------------------------------------------------------  Metodos Privados
	
	/**
	 * Metodo que llama al Gestor de Tablas y Codigos para obtener los 
	 * resultados asociados a la llamada realizada.
	 * @return (Object): objeto nuevo cargado con los datos del Gestor de Tablas. 
	 */
	private Object getData() throws JspException 
	{
		// Obtener los datos del Gestor
		if (tr.isTraceActive()) {		
			tr.trace(COMPONENTE, Q70TraceLevel.INFO, "Comenzando a obtener los datos llamando al Gestor de tablas...");
		}		
	
		//Obtener la configuracion local del idioma	
		Locale locale = RequestUtils.retrieveUserLocale( pageContext, getLocale() );
		
		Vector cols = new Vector(2);
		cols.add(labelColumn);
		if (null!=valueColumn) 
			cols.add(valueColumn);

		if (tr.isTraceActive()) {		
			tr.trace(COMPONENTE, Q70TraceLevel.INFO, "Llamando al Gestor de tablas con los parametros:" + 
												  "-locale:" + locale.getLanguage() + 
												  "-table:" + this.table + 
												  "-whereClause:" + this.whereClause + 
												  "-cols:" + cols);
		}
		
		Collection data = null;
		try {
			data = (Collection) Q70GestorTablasCodigos.
								getSingleton().
								selectRecordsFromTable( this.table, 
														this.whereClause,
														locale.getLanguage(), 
														cols);
		} catch (Exception e) {
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "No ha sido posible obtener el resultado del Gestor de Tablas y Codigos.");
			}
			RequestUtils.saveException(pageContext, e);
			throw new JspException("No ha sido posible obtener el resultado del Gestor de Tablas y Codigos.", e);				
		}			


					
		Object dataBean = null;
		if (null!=data)
			dataBean = createAndFillDataBean((Collection) data);
									
		return dataBean;
	}


	/**
	 * Busca el bean en el alcance especificado.
	 * Si lo encuentra lo sobreescibe con el objeto	data.
	 * Si no, lo inserta en el contexto de pagina.
	 * @param (Object) data: bean con los resultados de la consulta
	 */
	private void storeData(Object data) throws JspException {	

		pageContext.setAttribute(this.name, data, getScope(this.scope));		

	}


	/**
	 * Convierte en nombre del alcance a su correspondiente constante PageContext.
	 * Si este nombre viene vacío, devuelve el contexto de página.
	 * @param (String) scopeName: puede tener los valores "page", "request", "session", o "application".
	 * @return (int): La constante que representa el alcance (ej. PageContext.REQUEST_SCOPE).
	 * @throws JspException si scopeName no es un nombre válido.
	 */
	private int getScope(String scopeName) throws JspException {
		int newScope = PageContext.PAGE_SCOPE;
		
		if (null!=scopeName && scopeName.length()>0) {
		
			Integer scope = (Integer) scopes.get(scopeName.toLowerCase());
	
			if (null == scope) {
				JspException e =
					new JspException("No existe un definicion de alcance(scope) de tipo '"+ scopeName +"' para las paginas jsp.");
				RequestUtils.saveException(pageContext, e);
				throw e;				
			}

			newScope = scope.intValue();
		}
		
		return newScope;
	}


	/** 
	 * Crea un objeto del tipo especificado en la propiedad type y lo llena con 
	 * una coleccion de datos.
	 * @param (Collection) data: datos a cargar en el nuevo objeto
	 * @return (Object): nuevo objeto del tipo indicado en el atributo "beanType". 
	 * @throws JspException
	 */
	private Object createAndFillDataBean(Collection data)throws JspException 
	{
		if (tr.isTraceActive()) {		
			tr.trace(COMPONENTE, Q70TraceLevel.INFO, "Comenzando a crear y llenar un Bean...");
		}	
		
		Object dataBean = null;
		try{				
				//dataBean = RequestUtils.applicationInstance(this.type);				
				if (null==pageContext.getAttribute(this.name, getScope(this.scope)))
					dataBean = RequestUtils.applicationInstance(this.type);	
				else
					dataBean = pageContext.getAttribute(this.name, getScope(this.scope));
					
				if (tr.isTraceActive()) {		
					tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "El tipo del parametro '" + this.options + "' es= " + PropertyUtils.getPropertyType(dataBean, this.options).toString());
				}	
	
							
				//Class[] args = new Class[] { Collection.class };
				Class[] args = new Class[] { PropertyUtils.getPropertyType(dataBean, this.options) };
				
				StringBuffer st=new StringBuffer("set");
				st.append(this.options.substring(0,1).toUpperCase());
				st.append(this.options.substring(1));	
										
				Method setter = dataBean.getClass().getMethod(st.toString(), args);	
				setter.invoke(dataBean, new Object[] {data} );
				
		}catch(Exception ex) {
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "No ha sido posible crear y llenar el bean");
			}
			RequestUtils.saveException(pageContext, ex);
			throw new JspException("No ha sido posible crear y llenar el bean.", ex);							
		}	
		
		return dataBean;	
	}


}
