/*
 * Creado el 22-mar-04
 *
 * 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.admon.logs;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.log4j.helpers.OptionConverter;

import es.ejie.frmk.Q70Factoria;
import es.ejie.frmk.control.excepciones.Q70FrameworkException;
import es.ejie.frmk.infraestructura.logs.base.Q70ConfiguracionLog;
import es.ejie.frmk.infraestructura.logs.base.Q70ConstantesLogs;
import es.ejie.frmk.infraestructura.traza.Q70TraceLevel;
import es.ejie.frmk.infraestructura.traza.Q70TrazaInterface;

/**
 * Clase empleada para la busqueda de líneas de Logs y Trazas en los diferentes ficheros existentes
 * tanto a nivel de servidor como de aplicación (accesos, conectores, transacciones, navegación,
 * incidencias y trazas).
 * <ul>
 * <li> Configuración de Log o Traza</li>
 * <li> Columnas visualizables (atributos genéricos)</li>
 * <li> Nombre de Log</li>
 * </ul>
 * @version 2.0 Fecha: 11-04-06
 */

public class Q70BuscadorFicheroLog  implements Q70Buscador
{
	Q70ConfiguracionLog configuracionLog = null;
	List listaColumnas = null;
	String logName = null;
	SimpleDateFormat df = new SimpleDateFormat(Q70ConstantesLogs.DATE_FORMAT);
	public Q70BuscadorFicheroLog(Q70ConfiguracionLog configuracionLog, String logName)
	{
		this.configuracionLog = configuracionLog;
		this.logName = logName;
	}
	public Q70BuscadorFicheroLog()
	{		
	}
	
	public void setConfiguracion(String logName,Q70ConfiguracionLog configuracionLog)
	{
		this.configuracionLog = configuracionLog;
		this.logName = logName;
	}
	
	public int getColumnPosition(String column)
	{
		//contiene la posicion en la que se encuentra el usuario dentro de la linea del fichero
		int posUsuario = 0;
		boolean encontrado = false;
		for (int i = 0; i < listaColumnas.size(); i++)
		{
			Q70Columna columna = (Q70Columna) listaColumnas.get(i);
			if (columna.getNombre().equals(column))
			{
				encontrado = true;
				break;
			}
			else
			{
				posUsuario += columna.getSize() + 1;
			}
		}
		if (encontrado)
		{
			return posUsuario + Q70ConstantesLogs.DATE_FORMAT.length() + 1;
		}
		else
		{
			return 0;
		}
	}
	
	public int getColumnSize(String column)
	{
		int sizeUsuario = 0;
		for (int i = 0; i < listaColumnas.size(); i++)
		{
			Q70Columna columna = (Q70Columna) listaColumnas.get(i);
			if (columna.getNombre().equals(column))
			{
				sizeUsuario = columna.getSize();
				break;
			}
		}
		return sizeUsuario;
	}
	
	private boolean compareLineQuery(
		String line,
		Integer position,
		Integer size,
		String value)
	{
		if (position.intValue() > 0)
		{
			return getValueInLine(line, position, size).equals(value);
		}
		return false;
	}
	
	/**
	 * Retorna un String con una cadena concreta obtenida en base a una posción y un tamaño
	 * @param position - posición a partir de la cual comenzará a montarse la cadena resultante.
	 * @param size - tamaño para obtener la cadena resultante
	 * @return String con la cadena resultante
	 */
	private String getValueInLine(String line, Integer position, Integer size) {
		if (line.length() > position.intValue() + size.intValue())
			return line.substring(position.intValue(), position.intValue() + size.intValue()).trim();
		else 
			return "";
	}
	
	/**
	 * Retorna una lista con todas las líneas de logs y trazas que atiendan  a los criterios de selección
	 * especificados. Estas entradas de logs o trazas se extraerán de los diferentes ficheros existentes tanto
	 * a nivel de servidor como de aplicaciones (accesos, navegación, transacciones, conectores, incidencias y
	 * trazas). 
	 * @param consultaLog - clase que contiene la información que será tenida en cuenta para conformar las líneas
	 * de log y trazas. Son los criterios de selección que se utilizarán para conformar la lista con aquellos que
	 * los cumplan. 
	 * @return List lista con los elementos de tipo Q70ApunteLog con los datos de cada entrada de log o traza
	 */
	public List ExecuteQuery(Q70Filtros consultaLog) throws Q70FrameworkException
	{
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		
		int contAccesos = 0;
		int contNavegacion = 0;
		int contTransacciones = 0;
		int contConectores = 0;
		int contIncidencias = 0;
		int contTraza = 0;
		int numRegistrosLog = consultaLog.getRegistrosLog();
		
		String fichero = OptionConverter.substVars(configuracionLog.getProperty(Q70ConstantesLogs.FICHERO), null);
		String columnasGenericas =
			configuracionLog.getProperty(Q70ConstantesLogs.ATRIBUTOS_GENERICOS);
		List listaResultados = new ArrayList();

		String formattedLog = getFormattedColumn(logName,Q70ConstantesLogs.LOG_NAME_SIZE) ;
		
		//Calcular el lugar en el que hay que buscar el usuario en el fichero;
		Q70ColumnParser cp = new Q70ColumnParser(columnasGenericas);
		listaColumnas = cp.parseColumns();	
		
		List fieldPositions=new ArrayList(listaColumnas.size());
		List fieldSizes=new ArrayList(listaColumnas.size());
		for (int i=0;i<consultaLog.getSize();i++)
		{
		 fieldPositions.add(new Integer (getColumnPosition(consultaLog.getCondition(i).getField())));
		 fieldSizes.add(new Integer(getColumnSize(consultaLog.getCondition(i).getField())));
		}
		
		List fieldColsPositions=new ArrayList(listaColumnas.size());
		List fieldColsSizes=new ArrayList(listaColumnas.size());
		for (int i=0;i<consultaLog.getSizeColumnasVisualizables();i++)	{
			fieldColsPositions.add(new Integer (getColumnPosition(consultaLog.getColumnaVisualizable(i))));
			fieldColsSizes.add(new Integer(getColumnSize(consultaLog.getColumnaVisualizable(i))));
		}
		
		List fieldConfigPositions=new ArrayList(listaColumnas.size());
		List fieldConfigSizes=new ArrayList(listaColumnas.size());
		for (int i=0;i<listaColumnas.size();i++)
		{
			Q70Columna columna = (Q70Columna)listaColumnas.get(i);
			fieldConfigPositions.add(new Integer (getColumnPosition(columna.getNombre())));
			fieldConfigSizes.add(new Integer(getColumnSize(columna.getNombre())));
		}
		
		//leer el fichero linea a linea y verificar las condiciones de la consulta.
		try
		{
			BufferedReader in = new BufferedReader(new FileReader(fichero));
			while (true)
			{
				//recorrer las lineas del fichero
				String line = in.readLine();
				if (line == null)
				{
					break;
				}
				//tratar cada linea del fichero
				if (line.length() > 22)
				{
					String fecha = line.substring(0, 23);
					Date date = getDate(fecha);
					if (date != null)
					{
						//comprobar si está entre la fecha de inicio y la fecha del final
						if (date.compareTo(consultaLog.getDateFrom()) >= 0
							&& date.compareTo(consultaLog.getDateTo()) <= 0)
						{ 
							//evaluar las condiciones
							boolean resultado=true;
							for (int i=0; i<consultaLog.getSize();i++)
							{
								resultado =compareLineQuery(line,(Integer)fieldPositions.get(i),(Integer)fieldSizes.get(i),consultaLog.getCondition(i).getValue());
								if (resultado==false)
									break; 
							}
							//si el resultado es true
							if (resultado)
							{
								if (logName.equals(Q70ConstantesLogs.LOG_ACCESOS)) {
									contAccesos ++;
								} else if (logName.equals(Q70ConstantesLogs.LOG_NAVEGACION)) {
									contNavegacion ++;
								} else if (logName.equals(Q70ConstantesLogs.LOG_CONECTORES)) {
									contConectores ++;
								} else if (logName.equals(Q70ConstantesLogs.LOG_TRANSACCIONES)) {
									contTransacciones ++;
								} else if (logName.equals(Q70ConstantesLogs.LOG_INCIDENCIAS)) {
									contIncidencias ++;
								} else if (logName.equals(Q70ConstantesLogs.TRAZA)) {
									contTraza ++;
								}
								
								Q70ApunteLog apunteLog = new Q70ApunteLog();
								apunteLog.setLog(formattedLog);
								apunteLog.setFecha(df.format(date));
								
								StringBuffer lineParcial =new StringBuffer("");
								
								try {
									String datosEspecificos = obtenerDatosEspecificos(line, fieldConfigPositions, fieldConfigSizes); 
									for (int j= 0; j < consultaLog.getSizeColumnasVisualizables(); j++){
										if (Integer.parseInt(fieldColsSizes.get(j).toString()) >0) {
											lineParcial.append((line.substring(((Integer)fieldColsPositions.get(j)).intValue(),((Integer)fieldColsPositions.get(j)).intValue()+((Integer)fieldColsSizes.get(j)).intValue())).trim()+" ");
										}
									}
									lineParcial.append(datosEspecificos);
								} catch (Exception e){
									if (traza.isTraceActive()){
										lineParcial = new StringBuffer("");
										traza.trace(Q70ConstantesLogs.ID_COMPONENTE, Q70TraceLevel.WARN, "Se ha intentado acceder a Logs y Trazas generados con configuraciones antiguas");
									}
								}
								
								if (!lineParcial.toString().equals("")) {
									apunteLog.setLinea(lineParcial.toString());
									apunteLog.setDetalle(lineParcial.toString());
								}else {
									apunteLog.setLinea(line.substring(Q70ConstantesLogs.DATE_FORMAT.length(),line.length()));
									apunteLog.setDetalle(line);
								}
								
								if (((logName.equals(Q70ConstantesLogs.LOG_ACCESOS)) && (contAccesos <= numRegistrosLog)) ||
									((logName.equals(Q70ConstantesLogs.LOG_CONECTORES)) && (contConectores <= numRegistrosLog)) ||
									((logName.equals(Q70ConstantesLogs.LOG_INCIDENCIAS)) && (contIncidencias <= numRegistrosLog)) ||
									((logName.equals(Q70ConstantesLogs.TRAZA)) && (contTraza <= numRegistrosLog)) ||
									((logName.equals(Q70ConstantesLogs.LOG_TRANSACCIONES)) && (contTransacciones <= numRegistrosLog)) ||
									((logName.equals(Q70ConstantesLogs.LOG_NAVEGACION)) && (contNavegacion <= numRegistrosLog))) {
									//añadimos las líneas de fichero 
											listaResultados.add(apunteLog);
								}
							}
						}
					}
					
				}
			}
		}
		catch (IOException e)
		{
			if (traza.isTraceActive()){
				traza.trace(Q70ConstantesLogs.ID_COMPONENTE, Q70TraceLevel.ERROR, "Se ha producido un error en la recuperación de Logs y Trazas de fichero");
			}
			throw new Q70FrameworkException(Q70ConstantesLogs.ID_COMPONENTE,this.getClass().toString(),"ExecuteQuery","Se ha producido un error en el método ExecuteQuery.",e);
		}
		return listaResultados;
	}
	
	/**
	 * Retorna un String con los atributos específicos de la línea de log o traza que se está tratando. Como esta información
	 * viene dada al final de cada línea, nos basamos para localizarla en la posición máxima que ocupan los atributos
	 * genéricos, ya que los datos específicos vendrán dados después del último atributo genérico.
	 * 
	 * @param line - String que contiene una línea o entrada de un log específico.
	 * @param fieldPositions - Lista que contiene las posiciones en las que comienza cada atributo genérico
	 * @param fieldSizes - Lista que contiene los tamaños de los atributos genéricos
	 * @return String con los atributos específicos de una línea de Log o Traza.
	 */
	private String obtenerDatosEspecificos (String line, List fieldPositions, List fieldSizes) {
		int max = 0;
		int size = 0;
		for (int i=0; i<fieldPositions.size(); i++) {
			if (((Integer)fieldPositions.get(i)).intValue() > max) {
				max = ((Integer)fieldPositions.get(i)).intValue();
				size = ((Integer)fieldSizes.get(i)).intValue();
			}
		}
		return line.substring(max+size);
	}
	
	private String addSpaces(int spacesNumber)
	{
		StringBuffer s = new StringBuffer();
		for (int i = 0; i < spacesNumber; i++)
		{
			s.append(" ");
		}
		return s.toString();
	}
	
	private String getFormattedColumn(String value, int size)
	{
		//si el valor es mayor que el maximo entonces truncar
		String ret = null;
		if (size == 0)
			return value;
		if (value == null)
			ret = addSpaces(size);
		else
		{
			int longitud = value.length();
			if (longitud > size)
				ret = value.substring(0, size);
			else
				if (longitud == size)
					ret = value;
				else
					ret = value + addSpaces(size - longitud);
		}
		return ret;
	}
	
	public Date getDate(String fecha)
	{
		Date date = null;
		try
		{
			date = df.parse(fecha);
		}
		catch (ParseException e)
		{
		}
		return date;
	}
}
