package com.ejie.aa94a.utils;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StringUtils;

import com.ejie.aa94a.model.calculo.Estiba;
import com.ejie.aa94a.model.calculo.Mensaje;
import com.ejie.aa94a.model.config.Carga;
import com.ejie.aa94a.model.config.Configuracion;
import com.ejie.aa94a.model.config.Densidad;
import com.ejie.aa94a.model.config.Posicion;
import com.ejie.aa94a.model.config.Solucion;
import com.ejie.aa94a.model.config.TipoDistancia;
import com.ejie.aa94a.model.config.TipoSujecion;
import com.ejie.aa94a.model.config.Vehiculo;

/**
 * 
 * @author GFI-Norte
 * 
 */

public class UtilConfiguracion {

	private static final Logger logger = LoggerFactory
			.getLogger(UtilConfiguracion.class);

	private static final String SEPARADOR = ",";
	private static final String SEPARADOR_VALOR = ";";
	// properties
	private static final String VEHICULOS = "vehiculos.code";
	private static final String SUJECIONES = "sujeciones.code";
	private static final String DENSIDADES = "materiales.code";
	private static final String DISTANCIAS = "tiposDistancia.code";
	private static final String ESTIBAS = "estibas.code";
	private static final String MENSAJES = "mensajes.code";

	//

	private UtilConfiguracion() {
	}

	/**
	 * Inicializa la configuración del Sistema
	 */
	public static void inicializaConfiguracion() {
		UtilConfiguracion.logger.info("[inicializaConfiguracion - Inicio]");
		Configuracion.vehiculos = UtilConfiguracion.inicializaVehiculos();
		Configuracion.tiposSujecion = UtilConfiguracion
				.inicializaTiposSujecion();
		UtilConfiguracion.inicializaTiposDistancia();
		UtilConfiguracion.inicializaEstibas();
		UtilConfiguracion.inicializaDensidades();
		UtilConfiguracion.inicializaMensajes();
		UtilConfiguracion.inicializaRangosBobina();
		UtilConfiguracion.inicializaRangosFleje();
		Configuracion.initHashMap();
		UtilConfiguracion.inicializaSoluciones();
		UtilConfiguracion.logger.info("[inicializaConfiguracion - Fin]");
	}

	/**
	 * Obtiene la lista de vehiculos para su inicialización
	 * 
	 * @return List<Vehiculo>
	 */
	private static List<Vehiculo> inicializaVehiculos() {
		String str = null;
		// Vehículos
		List<Vehiculo> vehiculos = new ArrayList<Vehiculo>();
		Vehiculo veh = null;
		StringTokenizer strTokenizerVeh = new StringTokenizer(
				PropertiesUtil.getProperty(UtilConfiguracion.VEHICULOS),
				UtilConfiguracion.SEPARADOR);
		while (strTokenizerVeh.hasMoreTokens()) {
			str = strTokenizerVeh.nextToken();
			veh = new Vehiculo(Integer.valueOf(PropertiesUtil
					.getProperty("vehiculo.code." + str)),
					PropertiesUtil.getProperty("vehiculo.descEs." + str),
					PropertiesUtil.getProperty("vehiculo.descEu." + str),
					PropertiesUtil.getProperty("vehiculo.imagenEs." + str),
					PropertiesUtil.getProperty("vehiculo.imagenEu." + str));
			vehiculos.add(veh);
		}
		return vehiculos;
	}

	/**
	 * Inicializa la lista de Tipos de Sujeción
	 * 
	 * @return List<TipoSujecion>
	 */
	private static List<TipoSujecion> inicializaTiposSujecion() {
		String str = null;
		// Tipos de Sujeción
		List<TipoSujecion> tiposSujecion = new ArrayList<TipoSujecion>();
		TipoSujecion suj = null;
		StringTokenizer strTokenizerSuj = new StringTokenizer(
				PropertiesUtil.getProperty(UtilConfiguracion.SUJECIONES),
				UtilConfiguracion.SEPARADOR);
		while (strTokenizerSuj.hasMoreTokens()) {
			str = strTokenizerSuj.nextToken();
			suj = new TipoSujecion(Integer.valueOf(PropertiesUtil
					.getProperty("sujecion.code." + str)),
					PropertiesUtil.getProperty("sujecion.tipo." + str),
					PropertiesUtil.getProperty("sujecion.descEs." + str),
					PropertiesUtil.getProperty("sujecion.descEu." + str),
					PropertiesUtil.getProperty("sujecion.imagenEs." + str),
					PropertiesUtil.getProperty("sujecion.imagenEu." + str));
			tiposSujecion.add(suj);
		}
		return tiposSujecion;
	}

	/**
	 * Inicializa la lista de Densidades
	 */
	private static void inicializaDensidades() {
		String str = null;
		// Densidades
		List<Densidad> densidades = new ArrayList<Densidad>();
		Densidad dens = null;
		StringTokenizer strTokenizerVeh = new StringTokenizer(
				PropertiesUtil.getProperty(UtilConfiguracion.DENSIDADES),
				UtilConfiguracion.SEPARADOR);
		while (strTokenizerVeh.hasMoreTokens()) {
			str = strTokenizerVeh.nextToken();
			dens = new Densidad(Integer.valueOf(PropertiesUtil
					.getProperty("material.code." + str)),
					BigDecimal.valueOf(Double.valueOf(PropertiesUtil
							.getProperty("material.densidad." + str).replace(
									',', '.'))),
					PropertiesUtil.getProperty("material.descEs." + str),
					PropertiesUtil.getProperty("material.descEu." + str));
			densidades.add(dens);
		}
		Configuracion.densidades = densidades;
	}

	/**
	 * Inicializa la lista de Tipos de Distancia
	 */
	private static void inicializaTiposDistancia() {
		String str = null;
		// Tipos de Distancia
		List<TipoDistancia> tiposDistancia = new ArrayList<TipoDistancia>();
		TipoDistancia tipoDist = null;
		StringTokenizer strTokenizerVeh = new StringTokenizer(
				PropertiesUtil.getProperty(UtilConfiguracion.DISTANCIAS),
				UtilConfiguracion.SEPARADOR);
		while (strTokenizerVeh.hasMoreTokens()) {
			str = strTokenizerVeh.nextToken();
			tipoDist = new TipoDistancia(Integer.valueOf(PropertiesUtil
					.getProperty("tipoDistancia.code." + str)),
					PropertiesUtil.getProperty("tipoDistancia.descEs." + str),
					PropertiesUtil.getProperty("tipoDistancia.descEu." + str));
			tiposDistancia.add(tipoDist);
		}
		Configuracion.tiposDistancia = tiposDistancia;
	}

	/**
	 * Inicializa la lista de Estibas
	 */
	private static void inicializaEstibas() {
		String str = null;
		// Estibas
		List<Estiba> estibas = new ArrayList<Estiba>();
		Estiba est = null;
		StringTokenizer strTokenizerVeh = new StringTokenizer(
				PropertiesUtil.getProperty(UtilConfiguracion.ESTIBAS),
				UtilConfiguracion.SEPARADOR);
		while (strTokenizerVeh.hasMoreTokens()) {
			str = strTokenizerVeh.nextToken();
			est = new Estiba(Integer.valueOf(PropertiesUtil
					.getProperty("estiba.code." + str)),
					PropertiesUtil.getProperty("estiba.descEs." + str),
					PropertiesUtil.getProperty("estiba.descEu." + str),
					PropertiesUtil.getProperty("estiba.imagenEs." + str),
					PropertiesUtil.getProperty("estiba.imagenEu." + str));
			estibas.add(est);
		}
		Configuracion.estibas = estibas;
	}

	/**
	 * Inicializa la lista de Mensajes
	 */
	private static void inicializaMensajes() {
		String str = null;
		// Mensajes
		List<Mensaje> mensajes = new ArrayList<Mensaje>();
		Mensaje mens = null;
		StringTokenizer strTokenizerVeh = new StringTokenizer(
				PropertiesUtil.getProperty(UtilConfiguracion.MENSAJES),
				UtilConfiguracion.SEPARADOR);
		while (strTokenizerVeh.hasMoreTokens()) {
			str = strTokenizerVeh.nextToken();
			mens = new Mensaje(Integer.valueOf(PropertiesUtil
					.getProperty("mensaje.code." + str)),
					PropertiesUtil.getProperty("mensaje.descEs." + str),
					PropertiesUtil.getProperty("mensaje.descEu." + str));
			mensajes.add(mens);
		}
		Configuracion.mensajes = mensajes;
	}

	/**
	 * Inicializa los Rangos para la bobina
	 */
	private static void inicializaRangosBobina() {
		Carga bobina = new Carga(Integer.valueOf(PropertiesUtil
				.getProperty("bobina.anchura.min")),
				Integer.valueOf(PropertiesUtil
						.getProperty("bobina.anchura.max")),
				BigDecimal.valueOf(Double.valueOf(PropertiesUtil
						.getProperty("bobina.peso.min"))),
				BigDecimal.valueOf(Double.valueOf(PropertiesUtil
						.getProperty("bobina.peso.max"))),
				Integer.valueOf(PropertiesUtil
						.getProperty("bobina.diametro.ext.min")),
				Integer.valueOf(PropertiesUtil
						.getProperty("bobina.diametro.ext.max")),
				Integer.valueOf(PropertiesUtil
						.getProperty("bobina.diametro.int.min")),
				Integer.valueOf(PropertiesUtil
						.getProperty("bobina.diametro.int.max")), null);
		Configuracion.bobina = bobina;
	}

	/**
	 * Inicializa los rangos para el fleje
	 */
	private static void inicializaRangosFleje() {
		Carga fleje = new Carga(
				Integer.valueOf(PropertiesUtil.getProperty("fleje.anchura.min")),
				Integer.valueOf(PropertiesUtil.getProperty("fleje.anchura.max")),
				BigDecimal.valueOf(Double.valueOf(PropertiesUtil
						.getProperty("fleje.peso.min"))), BigDecimal
						.valueOf(Double.valueOf(PropertiesUtil
								.getProperty("fleje.peso.max"))), Integer
						.valueOf(PropertiesUtil
								.getProperty("fleje.diametro.ext.min")),
				Integer.valueOf(PropertiesUtil
						.getProperty("fleje.diametro.ext.max")), Integer
						.valueOf(PropertiesUtil
								.getProperty("fleje.diametro.int.min")),
				Integer.valueOf(PropertiesUtil
						.getProperty("fleje.diametro.int.max")), BigDecimal
						.valueOf(Double.valueOf(PropertiesUtil.getProperty(
								"fleje.rel.anchura.diametro.ext").replace(',',
								'.'))));

		Configuracion.fleje = fleje;
	}

	/**
	 * Obtiene el nombre del parámetro
	 * 
	 * @param situacion
	 * @param nombre
	 * @param numBobinas
	 * @return String
	 */
	private static String obtenerParam(int situacion, String nombre,
			int numBobinas) {
		StringBuffer stb = new StringBuffer();
		final String SEP_BARRA = "_";
		final String SEP_PUNTO = ".";
		stb.append(numBobinas).append(SEP_BARRA).append(nombre)
				.append(SEP_PUNTO).append(situacion);
		return stb.toString();
	}

	/**
	 * Obtiene el identificador en función de la posición.
	 * 
	 * @param pos
	 * @return String
	 */
	public static String getIdentificador(int pos) {
		final String IDENTIFICADORES = "ABCDEFGHIJKLMNÑOPQRSTUVWXYZ";
		return IDENTIFICADORES.substring(pos, pos + 1);
	}

	/**
	 * Realiza un split del campo por el separador
	 * 
	 * @param campo
	 * @param separador
	 * @return String []
	 */
	private static String[] split(String campo, String separador) {
		String[] resultado = null;
		if (campo != null && separador != null) {
			resultado = campo.split(separador);
		}
		return resultado;
	}

	/**
	 * 
	 * @param propiedad
	 *            String
	 * @param propertiesFactoryBean
	 *            PropertiesFactoryBean
	 * @return String
	 */
	private static String getValor(String propiedad,
			PropertiesFactoryBean propertiesFactoryBean) {
		String resultado = "";
		if (propiedad != null && propertiesFactoryBean != null) {
			try {
				resultado = propertiesFactoryBean.getObject().getProperty(
						propiedad);
				if (resultado == null) {
					resultado = "";
				}
			} catch (IOException ioex) {

			}
		}
		return resultado;
	}

	/**
	 * Obtiene las soluciones para el vehiculo y tipo de sujeción.
	 * 
	 * @param vehiculo
	 * @param tipoSujecion
	 * @return List<Solucion>
	 */
	private static List<Solucion> obtenerSoluciones(Vehiculo vehiculo,
			TipoSujecion tipoSujecion) {
		UtilConfiguracion.logger.info("[obtenerSoluciones - Inicio]");
		List<Solucion> soluciones = null;
		Solucion solucion = null;
		if (vehiculo != null && tipoSujecion != null) {
			StringBuffer stb = new StringBuffer("solucion.veh_")
					.append(vehiculo.getCodigo()).append(".suj_")
					.append(tipoSujecion.getCodigo());
			String nombreFichero = PropertiesUtil.getProperty(stb.toString());
			UtilConfiguracion.logger.info("nombreFichero: " + nombreFichero);
			// resources
			stb = new StringBuffer("solucion/").append(nombreFichero);
			// config
			// stb = new StringBuffer("aa94a/solucion/").append(nombreFichero);
			PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
			propertiesFactoryBean.setFileEncoding("UTF-8");
			propertiesFactoryBean.setLocation(new ClassPathResource(stb
					.toString()));
			soluciones = new ArrayList<Solucion>();
			// bobinas.permitidas=1,2,3,4
			final String BOBINAS_PERMITIDAS = "bobinas.permitidas";
			// situaciones.bobinas.permitidas=2,3,2,2
			final String SITUACIONES_BOBINAS_PERMITIDAS = "situaciones.bobinas.permitidas";
			try {
				propertiesFactoryBean.afterPropertiesSet();
				String VALOR_BOBINAS_PERMITIDAS = UtilConfiguracion.getValor(
						BOBINAS_PERMITIDAS, propertiesFactoryBean);
				String VALOR_SITUACIONES_BOBINAS_PERMITIDAS = UtilConfiguracion
						.getValor(SITUACIONES_BOBINAS_PERMITIDAS,
								propertiesFactoryBean);

				UtilConfiguracion.logger.info("VALOR_BOBINAS_PERMITIDAS: *"
						+ VALOR_BOBINAS_PERMITIDAS + "*");
				UtilConfiguracion.logger
						.info("VALOR_SITUACIONES_BOBINAS_PERMITIDAS: *"
								+ VALOR_SITUACIONES_BOBINAS_PERMITIDAS + "*");

				String[] valoresBobinasPermitidas = UtilConfiguracion.split(
						VALOR_BOBINAS_PERMITIDAS, UtilConfiguracion.SEPARADOR);
				String[] valoresSituacionesBobinasPermitidas = UtilConfiguracion
						.split(VALOR_SITUACIONES_BOBINAS_PERMITIDAS,
								UtilConfiguracion.SEPARADOR);

				// TODO: VALIDAR CONFIGURACION
				for (int i = 0; i < valoresBobinasPermitidas.length; i++) {
					Integer numBobinas = Integer
							.valueOf(valoresBobinasPermitidas[i]);
					Integer situaciones = Integer
							.valueOf(valoresSituacionesBobinasPermitidas[i]);
					for (int j = 1; j <= situaciones; j++) {
						solucion = new Solucion();
						solucion.setNumBobinas(numBobinas);
						solucion.setCodigo(String.valueOf(j));
						solucion.setGrafico(UtilConfiguracion.getValor(
								UtilConfiguracion.obtenerParam(j, "imagen",
										numBobinas), propertiesFactoryBean));
						// /////////////////////////////////////////////////////
						// TIPO DISTANCIA
						String tipoDistancia = UtilConfiguracion.getValor(
								UtilConfiguracion.obtenerParam(j,
										"tipoDistancia", numBobinas),
								propertiesFactoryBean);
						solucion.setTipoDistancia(Configuracion
								.getTipoDistancia(StringUtils
										.trimAllWhitespace(tipoDistancia)));
						// /////////////////////////////////////////////////////
						// ESTIBAS
						String[] estibasArray = UtilConfiguracion.split(
								UtilConfiguracion.getValor(
										UtilConfiguracion.obtenerParam(j,
												"estibas", numBobinas),
										propertiesFactoryBean),
								UtilConfiguracion.SEPARADOR);
						List<Estiba> estibas = null;
						if (estibasArray != null && estibasArray.length > 0
								&& estibasArray[0].length() > 0) {
							estibas = new ArrayList<Estiba>();
							for (int z = 0; z < estibasArray.length; z++) {
								estibas.add(Configuracion.getEstiba(StringUtils
										.trimAllWhitespace(estibasArray[z])));
							}
						}
						solucion.setEstibas(estibas);

						// //////////////////////////////////////////////////////
						// CONDICIONES
						String[] condicionesArray = UtilConfiguracion.split(
								UtilConfiguracion.getValor(UtilConfiguracion
										.obtenerParam(j, "condiciones",
												numBobinas),
										propertiesFactoryBean),
								UtilConfiguracion.SEPARADOR_VALOR);
						List<String> condiciones = null;
						if (condicionesArray != null
								&& condicionesArray.length > 0) {
							condiciones = new ArrayList<String>();
							for (int z = 0; z < condicionesArray.length; z++) {
								condiciones
										.add(StringUtils
												.trimAllWhitespace(condicionesArray[z]));
							}
						}
						solucion.setCondiciones(condiciones);
						// //////////////////////////////////////////////////////
						// POSICIONES
						String[] posicionesArray = UtilConfiguracion.split(
								UtilConfiguracion.getValor(UtilConfiguracion
										.obtenerParam(j, "posiciones",
												numBobinas),
										propertiesFactoryBean),
								UtilConfiguracion.SEPARADOR_VALOR);
						List<Posicion> posiciones = null;
						if (posicionesArray != null
								&& posicionesArray.length > 0) {
							posiciones = new ArrayList<Posicion>();
							for (int z = 0; z < posicionesArray.length; z++) {
								posiciones
										.add(new Posicion(
												UtilConfiguracion
														.getIdentificador(z),
												Integer.valueOf(StringUtils
														.trimAllWhitespace(posicionesArray[z]))));
							}
						}
						solucion.setPosiciones(posiciones);
						// AÑADIMOS SOLUCION
						soluciones.add(solucion);
					}
				}
			} catch (Exception e) {
				soluciones = null;
				UtilConfiguracion.logger
						.error("Error configurando el fichero: "
								+ nombreFichero);
			}
		}
		UtilConfiguracion.logger.info("[obtenerSoluciones - Fin]");
		return soluciones;
	}

	/**
	 * 
	 * @param listaTiposSujecion
	 * @return
	 */
	private static List<TipoSujecion> clonar(
			List<TipoSujecion> listaTiposSujecion) {
		List<TipoSujecion> listaTiposSujecionAux = new ArrayList<TipoSujecion>();
		if (listaTiposSujecion != null) {
			Iterator<TipoSujecion> itTipoSujecion = listaTiposSujecion
					.iterator();
			TipoSujecion tipoSujecion = null;
			while (itTipoSujecion.hasNext()) {
				try {
					tipoSujecion = (TipoSujecion) itTipoSujecion.next().clone();
				} catch (CloneNotSupportedException e) {
				}
				listaTiposSujecionAux.add(tipoSujecion);
			}

		}
		return listaTiposSujecionAux;

	}

	/**
	 * Inicializa la lista de soluciones configurada para la clase Configuracion
	 */
	private static void inicializaSoluciones() {
		UtilConfiguracion.logger.info("[inicializaSoluciones - Inicio]");
		List<Vehiculo> listaVehiculos = UtilConfiguracion.inicializaVehiculos();
		Iterator<Vehiculo> itVehiculos = listaVehiculos.iterator();
		Vehiculo vehiculo = null;
		TipoSujecion tipoSujecion = null;
		List<TipoSujecion> listaTiposSujecion = UtilConfiguracion
				.inicializaTiposSujecion();
		while (itVehiculos.hasNext()) {
			vehiculo = itVehiculos.next();
			List<TipoSujecion> listaTiposSujecionAux = UtilConfiguracion
					.clonar(listaTiposSujecion);
			Iterator<TipoSujecion> itTiposSujecion = listaTiposSujecionAux
					.iterator();
			while (itTiposSujecion.hasNext()) {
				tipoSujecion = itTiposSujecion.next();
				tipoSujecion.setSoluciones(UtilConfiguracion.obtenerSoluciones(
						vehiculo, tipoSujecion));
			}
			vehiculo.setTiposSujecion(listaTiposSujecionAux);
		}
		Configuracion.soluciones = listaVehiculos;
		UtilConfiguracion.logger.info("[inicializaSoluciones - Fin]");
	}

}