package com.ejie.ab63.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.TimeZone;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ejie.ab63.clientesWS.ab79WebService.DatosEstablecimientoWS;
import com.ejie.ab63.clientesWS.ab79WebService.DatosValidarWS;
import com.ejie.ab63.clientesWS.ab79WebService.ObjetosValidarWS;
import com.ejie.ab63.exceptions.Ab63Exception;
import com.ejie.ab63.model.AgenciaData;
import com.ejie.ab63.model.Alojamiento;
import com.ejie.ab63.model.Aseo;
import com.ejie.ab63.model.AseoAlojamiento;
import com.ejie.ab63.model.Categoria;
import com.ejie.ab63.model.DireccionEstablecimiento;
import com.ejie.ab63.model.DispensaEstablecimiento;
import com.ejie.ab63.model.Especialidad;
import com.ejie.ab63.model.Establecimiento;
import com.ejie.ab63.model.EstablecimientoData;
import com.ejie.ab63.model.Grupo;
import com.ejie.ab63.model.Habitacion;
import com.ejie.ab63.model.HabitacionAlojamiento;
import com.ejie.ab63.model.HabitacionVivienda;
import com.ejie.ab63.model.Modalidad;
import com.ejie.ab63.model.OtrasDependenciasVivienda;
import com.ejie.ab63.model.Parcela;
import com.ejie.ab63.model.Recurso;
import com.ejie.ab63.model.SalonComedor;
import com.ejie.ab63.model.Suite;
import com.ejie.ab63.model.TercerosEstablecimiento;
import com.ejie.ab63.model.TipoAseo;
import com.ejie.ab63.model.TipoEstablecimiento;
import com.ejie.ab63.model.TipoFranquicia;
import com.ejie.ab63.model.TipoHabitacion;
import com.ejie.ab63.model.ZonaOcio;
import com.ejie.ab63.model.terceros.DatosTerceros;
import com.ejie.ab63.model.terceros.TiposTercero;

/**
 * 
 *  
 *
 */
public abstract class InspecionesServiceUtils {

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

	private static final String PACKAGE_MODEL_PATTERN = "com\\.ejie(\\.\\w*)*\\.model(\\.\\w+)*";

	private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";

	private static Map<Class<?>, String> modelClassCods = new HashMap<Class<?>, String>();
	static {
		modelClassCods.put(Establecimiento.class, "EST");
		modelClassCods.put(EstablecimientoData.class, "ESD");
		modelClassCods.put(AgenciaData.class, "AGD");
		modelClassCods.put(Habitacion.class, "HAB");
		modelClassCods.put(Suite.class, "SUI");
		modelClassCods.put(Aseo.class, "ASE");
		modelClassCods.put(SalonComedor.class, "SLC");
		modelClassCods.put(Parcela.class, "PAR");
		modelClassCods.put(DireccionEstablecimiento.class, "DRE");
		modelClassCods.put(Alojamiento.class, "ALE");
		modelClassCods.put(HabitacionVivienda.class, "HBV");
		modelClassCods.put(HabitacionAlojamiento.class, "HBA");
		modelClassCods.put(AseoAlojamiento.class, "ASA");
		modelClassCods.put(OtrasDependenciasVivienda.class, "ODV");
		modelClassCods.put(TipoAseo.class, "TPA");
		modelClassCods.put(TipoHabitacion.class, "TPH");
		modelClassCods.put(TipoFranquicia.class, "TFR");
		modelClassCods.put(Especialidad.class, "ESP");
		modelClassCods.put(Categoria.class, "CTE");
		modelClassCods.put(Grupo.class, "GPE");
		modelClassCods.put(Modalidad.class, "MDE");
		modelClassCods.put(ZonaOcio.class, "ZOE");
		// modelClassCods.put(TercerosEstablecimiento.class, "TER");
		// modelClassCods.put(DatosTerceros.class, "DTR");
		// modelClassCods.put(TipoEstablecimiento.class, "TPE");
		// modelClassCods.put(TiposTercero.class, "TPT");
	}

	private static Map<Class<?>, String> modelClassPK = new HashMap<Class<?>, String>();
	static {
		modelClassPK.put(Establecimiento.class, "idEstablecimiento");
		modelClassPK.put(EstablecimientoData.class, "idEstablecimiento");
		modelClassPK.put(AgenciaData.class, "idEstablecimiento");
		modelClassPK.put(Habitacion.class, "idHabitacion");
		modelClassPK.put(Suite.class, "idSuite");
		modelClassPK.put(Aseo.class, "idAseo");
		modelClassPK.put(SalonComedor.class, "idSalonComedor");
		modelClassPK.put(Parcela.class, "idParcela");
		modelClassPK.put(TercerosEstablecimiento.class, "idTercerosEstab");
		modelClassPK.put(TipoEstablecimiento.class, "idTipoEstablecimiento");
		modelClassPK.put(DatosTerceros.class, "idTercero");
		modelClassPK.put(TiposTercero.class, "idTipoTercero");
		modelClassPK.put(DireccionEstablecimiento.class, "idDireccionEstab");
		modelClassPK.put(Categoria.class, "idCategorias");
		modelClassPK.put(Especialidad.class, "idEspecialidad");
		modelClassPK.put(Modalidad.class, "idModalidad");
		modelClassPK.put(Grupo.class, "idGrupo");
		modelClassPK.put(Alojamiento.class, "idAlojamiento");
		modelClassPK.put(HabitacionVivienda.class, "idHabVivienda");
		modelClassPK.put(HabitacionAlojamiento.class, "idHabitacionAlo");
		modelClassPK.put(AseoAlojamiento.class, "idAseoAlo");
		modelClassPK.put(OtrasDependenciasVivienda.class, "idOtrasdepViviendas");
		modelClassPK.put(TipoAseo.class, "idTipoAseo");
		modelClassPK.put(TipoHabitacion.class, "idTipoHabitacion");
		modelClassPK.put(TipoFranquicia.class, "idFranquicia");
		modelClassPK.put(Recurso.class, "idRecurso");
		modelClassPK.put(DispensaEstablecimiento.class, "idDispensasEstab");
		modelClassPK.put(ZonaOcio.class, "idZonaOcio");
	}

	private static List<String> fieldsFilter = new ArrayList<String>();
	static {
		fieldsFilter.add("serialVersionUID");
		fieldsFilter.add("fechaRegistro");
		fieldsFilter.add("idEstablecimiento");
		fieldsFilter.add("usuarioRegistro");
		fieldsFilter.add("fechaUltmodificacion");
		fieldsFilter.add("usuarioUltmodificacion");
		fieldsFilter.add("descrNombre");
		fieldsFilter.add("visibleweb");
		fieldsFilter.add("urlweb");
		fieldsFilter.add("idDefectos");
		fieldsFilter.add("observaciones");
		fieldsFilter.add("fechaApertura");
		fieldsFilter.add("fechaInicierretemp");
		fieldsFilter.add("fechaFincierretemp");
		fieldsFilter.add("fechaVctoCierre");
		fieldsFilter.add("fechaUltNotificacion");
		fieldsFilter.add("fechaUltInspeccion");
		fieldsFilter.add("fechaProInspeccion");
		fieldsFilter.add("fechaUltActualizacion");
		fieldsFilter.add("fechaClausura");
		fieldsFilter.add("fechaUltReforma");
		fieldsFilter.add("eliminado");
		fieldsFilter.add("expedienteb29");
		fieldsFilter.add("idPortalS41");
		fieldsFilter.add("urlPortalS41");
		fieldsFilter.add("filterTiposAlojamiento");
		fieldsFilter.add("anyoApertura");
		fieldsFilter.add("nombrePersonaContacto");
		fieldsFilter.add("descAccesibilidad");
		fieldsFilter.add("anyoUltimaRenovTotal");
		fieldsFilter.add("filterTipos");
		fieldsFilter.add("fechaControlS41");
		fieldsFilter.add("numInstalacionAnterior");
		fieldsFilter.add("fechaInscripcion");
		fieldsFilter.add("numInstalacionWz");
		fieldsFilter.add("observaciones2");
		fieldsFilter.add("agrupacion");
		fieldsFilter.add("obsSegrespcivil");
		fieldsFilter.add("CIE");
		fieldsFilter.add("aperturaDesde");
		fieldsFilter.add("aperturaHasta");
		fieldsFilter.add("correoElectronico");
		fieldsFilter.add("telefono");
		fieldsFilter.add("idExpediente");
		fieldsFilter.add("tipoRegistro");
		fieldsFilter.add("idEstablecimientoPadre");
		fieldsFilter.add("identificadorSolicitud");
		fieldsFilter.add("autocompleteEstablecimiento");
		fieldsFilter.add("usoResidentes");
		fieldsFilter.add("usoTuristico");
		fieldsFilter.add("idInstalOfiPrincipal");
		fieldsFilter.add("idOrigenOfiPrincipal");
		fieldsFilter.add("idTipoCie");
		fieldsFilter.add("etiquetaCie");
		fieldsFilter.add("registroFianza");
		fieldsFilter.add("observFianza");
		fieldsFilter.add("observSrc");
		fieldsFilter.add("idPrimeraSucursal");
		fieldsFilter.add("numCie");
		fieldsFilter.add("notasMigracion");
		fieldsFilter.add("tipoBusqueda");
		fieldsFilter.add("ultimaInspeccionHasta");
		fieldsFilter.add("incluirSucursales");
		fieldsFilter.add("ultimaModificacionDesde");
		fieldsFilter.add("telefonoBusqueda");
		fieldsFilter.add("ultimaInspeccionDesde");
		fieldsFilter.add("modifEsencial");
		fieldsFilter.add("datosDirecciones");
		fieldsFilter.add("datosTerceros");
		fieldsFilter.add("mostrar");
		fieldsFilter.add("pais");
		fieldsFilter.add("ultimaModificacionHasta");
		fieldsFilter.add("fechaAntControl");
		fieldsFilter.add("numControl");
		fieldsFilter.add("alojamiento");
		fieldsFilter.add("tipoFranquicia");
		fieldsFilter.add("baja");
		fieldsFilter.add("correoElectronicoBusqueda");
		fieldsFilter.add("ESD.idDispensasEstab");
		fieldsFilter.add("EST.idEstablecimiento");
		fieldsFilter.add("EST.idRecurso");
		fieldsFilter.add("EST.idFranquicia");
	}

	private static Map<Class<?>, String> modelClassDesc = new HashMap<Class<?>, String>();
	static {
		modelClassDesc.put(Suite.class, "$SUI#.descNombre$");
		modelClassDesc.put(SalonComedor.class, "$SLC#.descNombre$");
		modelClassDesc.put(Parcela.class, "$PAR#.nombre$");
		modelClassDesc.put(Alojamiento.class, "$ALE#.descNombreAlojamiento$");
		modelClassDesc.put(HabitacionVivienda.class, "$HBV#.identHabitacion$");
		modelClassDesc.put(OtrasDependenciasVivienda.class, "$ODV#.denomDependencia$");
		modelClassDesc.put(Aseo.class, "$TPA#.descTipoEs$/$TPA#.descTipoEu$ $ASE#.ubicacion$");
		// Need another logic
		modelClassDesc.put(Habitacion.class, "$TPH#.descTipoEs$/$TPH#.descTipoEu$");
		modelClassDesc.put(HabitacionAlojamiento.class,
				"$TPH#.descTipoEs$ $TPA#.descTipoEs$/$TPH#.descTipoEu$ $TPA#.descTipoEu$ ($ALE#.descNombreAlojamiento$)");
		modelClassDesc.put(AseoAlojamiento.class, "$TPA#.descTipoEs$/$TPA#.descTipoEu$ ($ALE#.descNombreAlojamiento$)");
		modelClassDesc.put(ZonaOcio.class, "$ZOE#.descripcion$/$TPA#.descripcionEu$");
	}

	private static List<Class<?>> ignoreListClassModel = new ArrayList<Class<?>>();
	static {
		ignoreListClassModel.add(TipoAseo.class);
		ignoreListClassModel.add(TipoHabitacion.class);
		ignoreListClassModel.add(TipoFranquicia.class);
		ignoreListClassModel.add(Grupo.class);
		ignoreListClassModel.add(Modalidad.class);
		ignoreListClassModel.add(Categoria.class);
		ignoreListClassModel.add(Especialidad.class);
	}

	private static List<String> ignoreFieldsUpdateModel = new ArrayList<String>();
	static {
		ignoreFieldsUpdateModel.add("idTipoEstablecimiento");
		ignoreFieldsUpdateModel.add("idTipoAseo");
		ignoreFieldsUpdateModel.add("idTipoHabitacion");
		ignoreFieldsUpdateModel.add("idFranquicia");

	}

	private InspecionesServiceUtils() {
	}

	/**
	 * Desglosa un <Establecimiento> y lo cargar en un
	 * objeto<DatosEstablecimientoWS>
	 * 
	 * @param establecimiento
	 * @return
	 * @throws Exception
	 */
	public static DatosEstablecimientoWS descomponerEstablecimiento(Establecimiento establecimiento) throws Exception {
		logger.info("Inicio descomposicion del establecimeto: " + establecimiento.getIdentificadorEstablecimiento());
		HashMap<String, String> mapa = new HashMap<String, String>();
		DatosEstablecimientoWS datosEstablecimientoWS = new DatosEstablecimientoWS();
		datosEstablecimientoWS.setIdentEstablecimiento(String.valueOf(establecimiento.getIdEstablecimiento()));
		if (establecimiento.getTipoEstablecimiento() != null
				&& establecimiento.getTipoEstablecimiento().getIdTipoEstablecimiento() != null) {
			datosEstablecimientoWS
					.setTipoEstablecimiento(establecimiento.getTipoEstablecimiento().getIdTipoEstablecimiento());
		}
		if (establecimiento.getCategoria() != null && establecimiento.getCategoria().getIdCategorias() != null) {
			datosEstablecimientoWS.setCategoriaEstablecimiento(establecimiento.getCategoria().getIdCategorias());
		}
		if (establecimiento.getModalidad() != null && establecimiento.getModalidad().getIdModalidad() != null) {
			datosEstablecimientoWS.setModalidadEstablecimiento(establecimiento.getModalidad().getIdModalidad());
		}
		// Extract properties from Establecimiento elements
		ComplexNode rootEstablecimiento = extractClass(Establecimiento.class, establecimiento, 0, 2, false);
		rootEstablecimiento.map(mapa);
		logger.info("Datos sin repeticion: " + rootEstablecimiento.toString());
		// load list DatosValidar of datosEstablecimientoWS with
		// rootEstablecimiento, no list element
		List<DatosValidarWS> listDatosEstablecimiento = datosEstablecimientoWS.getDatosValidarWS();
		mapToListDatosValidar(mapa, listDatosEstablecimiento);
		// Extract List elements from establecimientoData attribute and
		// create labels for eac node
		EstablecimientoData data = establecimiento.getEstablecimientoData();
		ComplexNode listas = new ComplexNode();
		loadListNode(data, "listAlojamiento", 0, 4, listas, true);
		loadListNode(data, "listAseo", 0, 2, listas, false);
		loadListNode(data, "listHabitacion", 0, 2, listas, false);
		loadListNode(data, "listHabitacionVivienda", 0, 2, listas, false);
		loadListNode(data, "listOtrasDependenciasVivienda", 0, 2, listas, false);
		loadListNode(data, "listParcela", 0, 2, listas, false);
		loadListNode(data, "listSalonComedor", 0, 2, listas, false);
		loadListNode(data, "listSuite", 0, 2, listas, false);
		loadListNode(data, "listZonaOcio", 0, 2, listas, false);

		logger.info("Datos con repeticion: " + listas.toString());
		// listas.print();
		List<ObjetosValidarWS> objetosValidarWSs = datosEstablecimientoWS.getObjetosValidarWS();
		// for each list
		for (int i = 0; i < listas.getNodeList().size(); i++) {
			ComplexNode nodeListProperty = (ComplexNode) listas.getNodeList().get(i);
			// for each element of list
			for (int j = 0; j < nodeListProperty.getNodeList().size(); j++) {
				ObjetosValidarWS objetosValidarWS = new ObjetosValidarWS();
				Map<String, String> mapProperties = new HashMap<String, String>();
				// load map with values of nodes
				ComplexNode currentNode = (ComplexNode) nodeListProperty.getNodeList().get(j);
				currentNode.map(mapProperties, 0, 2);
				objetosValidarWS.setDescObjetoValidar(currentNode.getLabel());
				// find first element get id
				String firtsKey = mapProperties.keySet().iterator().next();
				String idObject = firtsKey.substring(0, firtsKey.indexOf('.'));
				// check list ignore class to send
				if (!ignoreListClassModel.contains(findClassFromCod(idObject.substring(0, 3)))) {
					objetosValidarWS.setIdObjetoValidar(idObject);
					// load list of DatosValidarWS of properties without id part
					mapToListDatosValidar(mapProperties, objetosValidarWS.getDatosValidarWS(), idObject + ".");
					objetosValidarWSs.add(objetosValidarWS);
				}
			}
		}
		showKeyTags(datosEstablecimientoWS);
		return datosEstablecimientoWS;
	}

	private static void showKeyTags(DatosEstablecimientoWS datosEstablecimientoWS) {
		for (Iterator<DatosValidarWS> iterator = datosEstablecimientoWS.getDatosValidarWS().iterator(); iterator
				.hasNext();) {
			DatosValidarWS datosValidarWS = iterator.next();
			System.out.println(
					datosValidarWS.getIdentificadorDatoEstablecimiento() + " = " + datosValidarWS.getValorValidar());
		}

		for (Iterator<ObjetosValidarWS> iterator = datosEstablecimientoWS.getObjetosValidarWS().iterator(); iterator
				.hasNext();) {
			ObjetosValidarWS objetosValidarWS = iterator.next();
			for (Iterator<DatosValidarWS> iterator2 = objetosValidarWS.getDatosValidarWS().iterator(); iterator2
					.hasNext();) {
				DatosValidarWS datosValidarWS2 = iterator2.next();
				System.out.println(datosValidarWS2.getIdentificadorDatoEstablecimiento() + " = "
						+ datosValidarWS2.getValorValidar());
			}

		}

	}

	protected static void loadListNode(EstablecimientoData data, String fieldProperty, int deep, int limit,
			ComplexNode listas, boolean searchInside) throws Exception {
		Field field = data.getClass().getDeclaredField(fieldProperty);
		field.setAccessible(true);
		ComplexNode listNode = extractCollectionClass(field, field.get(data), deep, limit);
		if (listNode != null) {
			createLabelsElementsNode(listNode, inferGenericClass(field));
			if (searchInside) {
				List<ComplexNode> innerElements = extractInnerModelClassComplexNode(listNode, 0, 2);
				List<ComplexNode> groupedElements = groupInnerModelClassComplexNode(innerElements);
				for (Iterator<ComplexNode> iterator = groupedElements.iterator(); iterator.hasNext();) {
					ComplexNode complexNode = iterator.next();
					listas.add(complexNode);
				}
			} else {
				listas.add(listNode);
			}
		}
	}

	private static List<ComplexNode> groupInnerModelClassComplexNode(List<ComplexNode> innerElements) {
		List<ComplexNode> nodes = new ArrayList<ComplexNode>();
		HashMap<String, ComplexNode> nodeMapByCod = new HashMap<String, ComplexNode>();
		for (Iterator<ComplexNode> iterator = innerElements.iterator(); iterator.hasNext();) {
			ComplexNode innerComplexNode = iterator.next();
			HashMap<String, String> map = new HashMap<String, String>();
			innerComplexNode.map(map, 0, 2);
			String firtsKey = map.keySet().iterator().next();
			String idObject = firtsKey.substring(0, 3);
			if (!nodeMapByCod.containsKey(idObject)) {
				nodeMapByCod.put(idObject, new ComplexNode());
			}
			nodeMapByCod.get(idObject).add(innerComplexNode);
		}
		Iterator<Entry<String, ComplexNode>> it = nodeMapByCod.entrySet().iterator();
		while (it.hasNext()) {
			Entry<String, ComplexNode> codeKey = it.next();
			nodes.add(codeKey.getValue());
		}
		return nodes;
	}

	private static List<ComplexNode> extractInnerModelClassComplexNode(ComplexNode listNode, int deep, int limit) {
		List<ComplexNode> list = new ArrayList<ComplexNode>();
		if (deep > limit) {
			return list;
		}
		List<Node> listComplexNodes = listNode.getNodeList();
		for (Iterator<Node> iterator = listComplexNodes.iterator(); iterator.hasNext();) {
			Node node = iterator.next();
			if (Node.NODE_TYPE_COMPLEX.equals(node.getNodeType())) {
				if (((ComplexNode) node).getLabel() != null)
					list.add((ComplexNode) node);
				list.addAll(extractInnerModelClassComplexNode((ComplexNode) node, deep + 1, limit));
			}
		}

		return list;
	}

	private static void createLabelsElementsNode(ComplexNode nodes, Class<?> clazz) throws Exception {
		for (int i = 0; i < nodes.getNodeList().size(); i++) {
			Node node = nodes.getNodeList().get(i);
			if (Node.NODE_TYPE_SIMPLE.equals(node.getNodeType())) {
				continue;
			}
			ComplexNode currentNode = (ComplexNode) node;
			String templateDescClass = modelClassDesc.get(clazz);
			templateDescClass = preparedDescriptionNode(node, nodes, templateDescClass);
			currentNode.setLabel(templateDescClass);
			if (currentNode.getNodeList().isEmpty()) {
				continue;
			}
			List<Node> listNodes = currentNode.getNodeList();
			for (Iterator<Node> iterator = listNodes.iterator(); iterator.hasNext();) {
				Node subNode = iterator.next();
				if (Node.NODE_TYPE_COMPLEX.equals(subNode.getNodeType())) {
					createLabelsElementsNode((ComplexNode) subNode, currentNode);
				}
			}
		}
	}

	private static void createLabelsElementsNode(ComplexNode nodes, ComplexNode parent) throws Exception {
		for (int i = 0; i < nodes.getNodeList().size(); i++) {
			Node node = nodes.getNodeList().get(i);
			if (Node.NODE_TYPE_SIMPLE.equals(node.getNodeType())) {
				continue;
			}
			ComplexNode currentNode = (ComplexNode) node;
			List<Node> listCurr = currentNode.getNodeList();
			String codeClass = findCodeClassFromNode(listCurr);
			Class<?> clazzNode = findClassFromCod(codeClass);
			String templateDescClass = modelClassDesc.get(clazzNode);
			templateDescClass = preparedDescriptionNode(currentNode, parent, templateDescClass);
			currentNode.setLabel(templateDescClass);
		}
	}

	private static String findCodeClassFromNode(List<Node> listCurr) {
		String codeClass = "";
		for (Iterator<Node> iterator = listCurr.iterator(); iterator.hasNext() && "".equalsIgnoreCase(codeClass);) {
			Node subNode = iterator.next();
			if (Node.NODE_TYPE_SIMPLE.equals(subNode.getNodeType())) {
				SimpleNode simple = (SimpleNode) subNode;
				codeClass = simple.key.substring(0, simple.key.indexOf('.') - 1);
			}
		}
		return codeClass;
	}

	private static String preparedDescriptionNode(Node node, Node parent, String templateDescClass) {
		List<String> labels = findTemplateLabels(templateDescClass);
		Map<String, String> values = new HashMap<String, String>();
		for (String label : labels) {
			// find value on current node and childs
			SimpleNode nodeSearch = (SimpleNode) node.find(label, true);

			// if not found try on parent
			if (nodeSearch == null) {
				nodeSearch = (SimpleNode) parent.find(label, true);
			}
			values.put(label, nodeSearch != null ? nodeSearch.value : null);
		}
		for (int j = 0; j < labels.size(); j++) {
			String label = labels.get(j);
			String value = values.get(label);
			if (value == null) {
				value = "";
			}
			templateDescClass = templateDescClass.replace(label, value);
		}
		templateDescClass = templateDescClass.replace("$", "");
		return templateDescClass;
	}

	private static List<String> findTemplateLabels(String templateDescClass) {
		List<String> labels = new ArrayList<String>();
		while (templateDescClass.indexOf('$') > -1) {
			String label = templateDescClass.substring(templateDescClass.indexOf('$'),
					templateDescClass.indexOf('$', templateDescClass.indexOf('$') + 1) + 1);
			templateDescClass = templateDescClass.replace(label, "");
			labels.add(label.replace("$", ""));
		}
		return labels;
	}

	protected static Class<?> findClassFromCod(String key) {
		Iterator<Entry<Class<?>, String>> it = modelClassCods.entrySet().iterator();
		while (it.hasNext()) {
			Entry<Class<?>, String> entry = it.next();
			if (entry.getValue().equalsIgnoreCase(key)) {
				return entry.getKey();
			}
		}
		return null;
	}

	protected static void mapToListDatosValidar(Map<String, String> mapa, List<DatosValidarWS> listDatosValidar) {
		mapToListDatosValidar(mapa, listDatosValidar, "");
	}

	protected static void mapToListDatosValidar(Map<String, String> mapa, List<DatosValidarWS> listDatosValidar,
			String replace) {
		String typeClass = "";
		if (replace != null && !"".equals(replace)) {
			typeClass = replace.substring(0, 3).concat(".");
		}
		for (Iterator<String> iterator = mapa.keySet().iterator(); iterator.hasNext();) {
			String key = iterator.next();
			String sendKey = key.replace(replace, "");
			DatosValidarWS datosValidarWS = new DatosValidarWS();
			if (!fieldsFilter.contains(sendKey)) {

				datosValidarWS.setIdentificadorDatoEstablecimiento(typeClass + sendKey);
				datosValidarWS.setValorValidar(mapa.get(key));
				listDatosValidar.add(datosValidarWS);
			}
		}
	}

	public static Establecimiento actualizarEstablecimiento(
			com.ejie.ab63.service.serviciosWeb.model.DatosEstablecimientoWS data, Establecimiento base)
			throws Ab63Exception {
		logger.info("[actualizarEstablecimiento] - inicio");
		HashMap<String, String> mapa = new HashMap<String, String>();
		List<com.ejie.ab63.service.serviciosWeb.model.DatosValidarWS> listDatosValidarWS = data.getDatosValidarWS();
		for (int i = 0; i < listDatosValidarWS.size(); i++) {
			com.ejie.ab63.service.serviciosWeb.model.DatosValidarWS datosValidarWS = listDatosValidarWS.get(i);
			if (datosValidarWS != null && datosValidarWS.getIdentificadorDatoEstablecimiento() != null) {
				mapa.put(datosValidarWS.getIdentificadorDatoEstablecimiento(), datosValidarWS.getValorValidar());
			}
		}
		ComplexNode root = new ComplexNode();
		loadNodeListDatosValidarWS(mapa, root);
		loadNodeCollectionObjetosValidarWS(data, root);
		// root.print();
		logger.info("[actualizarEstablecimiento] - load data from call to nodes");

		for (int i = 0; i < root.getNodeList().size(); i++) {
			String methodToCall = "applyChangesOn";
			ComplexNode node = (ComplexNode) root.getNodeList().get(i);
			String idElement = node.getKeyGroup().substring(3);
			String codElement = node.getKeyGroup().substring(0, 3);
			Class<?> clazzElement = findClassFromCod(codElement);
			if ("".equals(idElement)) {
				idElement = String.valueOf(base.getIdEstablecimiento());
			}
			if (clazzElement == null) {
				methodToCall += "Fail";
			} else {

				methodToCall += clazzElement.getSimpleName();
			}

			Class<?>[] arguments = new Class[] { String.class, Establecimiento.class, ComplexNode.class };
			Method method;
			try {
				if (!ignoreListClassModel.contains(clazzElement)) {
					method = InspecionesServiceUtils.class.getDeclaredMethod(methodToCall, arguments);
					method.setAccessible(true);
					method.invoke(null, idElement, base, node);
				}
			} catch (SecurityException e) {
				applyChangesOnFail(idElement, base, node, e);
			} catch (NoSuchMethodException e) {
				applyChangesOnFail(idElement, base, node, e);
			} catch (IllegalArgumentException e) {
				applyChangesOnFail(idElement, base, node, e);
			} catch (IllegalAccessException e) {
				applyChangesOnFail(idElement, base, node, e);
			} catch (InvocationTargetException e) {
				applyChangesOnFail(idElement, base, node, e);
			}
		}

		logger.info("[actualizarEstablecimiento] - fin");
		return base;
	}

	protected static void applyChangesOnEstablecimiento(String idElement, Establecimiento base, ComplexNode node) {
		logger.info(String.format("EST ID: %sChanges: %d %n", idElement, node.getNodeList().size()));
		applyChangesOnElement(base, node, Establecimiento.class, modelClassCods.get(Establecimiento.class));
	}

	protected static void applyChangesOnEstablecimientoData(String idElement, Establecimiento base, ComplexNode node) {
		logger.info(String.format("ESD ID: %sChanges: %d %n", idElement, node.getNodeList().size()));
		applyChangesOnElement(base.getEstablecimientoData(), node, EstablecimientoData.class,
				modelClassCods.get(EstablecimientoData.class));
	}

	protected static void applyChangesOnAgenciaData(String idElement, Establecimiento base, ComplexNode node) {
		logger.info(String.format("AGD ID: %sChanges: %d %n", idElement, node.getNodeList().size()));
		applyChangesOnElement(base.getAgenciaData(), node, AgenciaData.class, modelClassCods.get(AgenciaData.class));
	}

	protected static void applyChangesOnFranquicia(String idElement, Establecimiento base, ComplexNode node) {
		logger.info(String.format("FRN ID: %sChanges: %d %n", idElement, node.getNodeList().size()));
		applyChangesOnElement(base.getAgenciaData(), node, AgenciaData.class, modelClassCods.get(AgenciaData.class));
	}

	protected static void applyChangesOnAlojamiento(String idElement, Establecimiento base, ComplexNode node)
			throws Exception {
		logger.info(String.format("ALE ID: %sChanges: %d %n", idElement, node.getNodeList().size()));
		applyChangeOnListElement(idElement, base.getEstablecimientoData().getListAlojamiento(), node,
				Alojamiento.class);
	}

	protected static void applyChangesOnAseoAlojamiento(String idElement, Establecimiento base, ComplexNode node)
			throws Exception {
		logger.info(String.format("ASA ID: %sChanges: %d %n", idElement, node.getNodeList().size()));
		List<Alojamiento> alojamientos = base.getEstablecimientoData().getListAlojamiento();
		for (Iterator<Alojamiento> iterator = alojamientos.iterator(); iterator.hasNext();) {
			Alojamiento alojamiento = iterator.next();
			applyChangeOnListElement(idElement, alojamiento.getListAseoAlojamiento(), node, AseoAlojamiento.class);
		}
	}

	protected static void applyChangesOnHabitacionAlojamiento(String idElement, Establecimiento base, ComplexNode node)
			throws Exception {
		logger.info(String.format("HBA ID: %sChanges: %d %n", idElement, node.getNodeList().size()));
		List<Alojamiento> alojamientos = base.getEstablecimientoData().getListAlojamiento();
		for (Iterator<Alojamiento> iterator = alojamientos.iterator(); iterator.hasNext();) {
			Alojamiento alojamiento = iterator.next();
			applyChangeOnListElement(idElement, alojamiento.getListHabitacionAlojamiento(), node,
					HabitacionAlojamiento.class);
		}
	}

	protected static void applyChangesOnAseo(String idElement, Establecimiento base, ComplexNode node)
			throws Exception {
		logger.info(String.format("ASE ID: %sChanges: %d %n", idElement, node.getNodeList().size()));
		applyChangeOnListElement(idElement, base.getEstablecimientoData().getListAseo(), node, Aseo.class);
	}

	protected static void applyChangesOnHabitacion(String idElement, Establecimiento base, ComplexNode node)
			throws Exception {
		logger.info(String.format("HAB ID: %sChanges: %d %n", idElement, node.getNodeList().size()));
		applyChangeOnListElement(idElement, base.getEstablecimientoData().getListHabitacion(), node, Habitacion.class);
	}

	protected static void applyChangesOnZonaOcio(String idElement, Establecimiento base, ComplexNode node)
			throws Exception {
		logger.info(String.format("ZOE ID: %sChanges: %d %n", idElement, node.getNodeList().size()));
		applyChangeOnListElement(idElement, base.getEstablecimientoData().getListZonaOcio(), node, ZonaOcio.class);
	}

	protected static void applyChangesOnHabitacionVivienda(String idElement, Establecimiento base, ComplexNode node)
			throws Exception {
		logger.info(String.format("HBV ID: %sChanges: %d %n", idElement, node.getNodeList().size()));
		applyChangeOnListElement(idElement, base.getEstablecimientoData().getListHabitacionVivienda(), node,
				HabitacionVivienda.class);
	}

	protected static void applyChangesOnOtrasDependenciasVivienda(String idElement, Establecimiento base,
			ComplexNode node) throws Exception {
		logger.info(String.format("ODV ID: %sChanges: %d %n", idElement, node.getNodeList().size()));
		applyChangeOnListElement(idElement, base.getEstablecimientoData().getListOtrasDependenciasVivienda(), node,
				OtrasDependenciasVivienda.class);
	}

	protected static void applyChangesOnParcela(String idElement, Establecimiento base, ComplexNode node)
			throws Exception {
		logger.info(String.format("PAR ID: %sChanges: %d %n", idElement, node.getNodeList().size()));
		applyChangeOnListElement(idElement, base.getEstablecimientoData().getListParcela(), node, Parcela.class);
	}

	protected static void applyChangesOnSalonComedor(String idElement, Establecimiento base, ComplexNode node)
			throws Exception {
		logger.info(String.format("SLC ID: %sChanges: %d %n", idElement, node.getNodeList().size()));
		applyChangeOnListElement(idElement, base.getEstablecimientoData().getListSalonComedor(), node,
				SalonComedor.class);
	}

	protected static void applyChangesOnSuite(String idElement, Establecimiento base, ComplexNode node)
			throws Exception {
		logger.info(String.format("SUI ID: %sChanges: %d %n", idElement, node.getNodeList().size()));
		applyChangeOnListElement(idElement, base.getEstablecimientoData().getListSuite(), node, Suite.class);
	}

	protected static void applyChangeOnListElement(String idElement, List<?> base, ComplexNode node, Class<?> clazz)
			throws Exception {
		for (Iterator<?> iterator = base.iterator(); iterator.hasNext();) {
			Object element = iterator.next();
			Field pk = clazz.getDeclaredField(modelClassPK.get(clazz));
			pk.setAccessible(true);
			if (pk.get(element) != null) {
				if ((pk.getType() == Integer.class && pk.get(element).equals(Integer.parseInt(idElement)))
						|| (pk.getType() == Long.class && pk.get(element).equals(Long.parseLong(idElement))
								|| (pk.getType() == String.class && pk.get(element).equals(idElement)))) {
					applyChangesOnElement(element, node, clazz, modelClassCods.get(clazz));
				}
			}
		}
	}

	protected static void applyChangesOnElement(Object base, ComplexNode node, Class<?> clazz, String code) {
		SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
		for (int i = 0; i < node.getNodeList().size(); i++) {
			SimpleNode property = (SimpleNode) node.getNodeList().get(i);
			try {
				String propertyName = property.key.replace(code + ".", "");
				if (!ignoreFieldsUpdateModel.contains(propertyName)) {
					logger.info(String.format("%-60s update... ", property.key));
					Field field = clazz.getDeclaredField(propertyName);
					field.setAccessible(true);
					if (property.value == null || "".equals(property.value.trim())) {
						field.set(base, null);
					} else if (field.getType() == Integer.class) {
						field.set(base, Integer.parseInt(property.value));
					} else if (field.getType() == Long.class) {
						field.set(base, Long.parseLong(property.value));
					} else if (field.getType() == BigDecimal.class) {
						field.set(base, BigDecimal.valueOf(Double.valueOf(property.value)));
					} else if (field.getType() == Date.class) {
						field.set(base, df.parse(property.value));
					} else {
						Object value = field.getType().cast(property.value);
						field.set(base, value);
					}
					logger.info(" Ready!");
				}
			} catch (Exception e) {
				logger.error(String.format("ERROR! %s %s", property, e.getMessage()));
			}
		}
	}

	protected static void applyChangesOnFail(String idElement, Establecimiento base, ComplexNode node)
			throws Ab63Exception {
		throw new Ab63Exception("error.updateEstablecimiento",
				"Ha ocurrido un error al procesar la peticion de actualizacion del establecimiento.",
				"EU_Ha ocurrido un error al procesar la peticion de actualizacion del establecimiento.");
	}

	protected static void applyChangesOnFail(String idElement, Establecimiento base, ComplexNode node,
			Exception exception) throws Ab63Exception {
		logger.error("Error apply changes on base establecimiento: ", exception);
		throw new Ab63Exception("error.updateEstablecimiento",
				"Ha ocurrido un error al procesar la peticion de actualizacion del establecimiento.",
				"EU_Ha ocurrido un error al procesar la peticion de actualizacion del establecimiento.");
	}

	protected static void loadNodeCollectionObjetosValidarWS(
			com.ejie.ab63.service.serviciosWeb.model.DatosEstablecimientoWS data, ComplexNode root) {
		List<com.ejie.ab63.service.serviciosWeb.model.ObjetosValidarWS> objetosValidarWSs = data.getObjetosValidarWS();
		for (com.ejie.ab63.service.serviciosWeb.model.ObjetosValidarWS objetosValidarWS : objetosValidarWSs) {
			List<com.ejie.ab63.service.serviciosWeb.model.DatosValidarWS> listDatosValidarWSObjecto = objetosValidarWS
					.getDatosValidarWS();
			HashMap<String, String> mapa = new HashMap<String, String>();
			if (objetosValidarWS.getIdObjetosValidarWS() != null
					&& !"".equals(objetosValidarWS.getIdObjetosValidarWS())) {
				for (int j = 0; j < listDatosValidarWSObjecto.size(); j++) {
					com.ejie.ab63.service.serviciosWeb.model.DatosValidarWS datosValidarWS = listDatosValidarWSObjecto
							.get(j);
					if (datosValidarWS != null && datosValidarWS.getIdentificadorDatoEstablecimiento() != null) {
						mapa.put(datosValidarWS.getIdentificadorDatoEstablecimiento(),
								datosValidarWS.getValorValidar());
					}
				}
				ComplexNode node = new ComplexNode();
				node.setKeyGroup(objetosValidarWS.getIdObjetosValidarWS());
				loadNodeListDatosValidarWS(mapa, node);
				root.add(node);
			}
		}
	}

	protected static void loadNodeListDatosValidarWS(Map<String, String> mapaOrdenado, ComplexNode root) {
		Iterator<Entry<String, String>> iterator = mapaOrdenado.entrySet().iterator();
		while (iterator.hasNext()) {
			Entry<String, String> entry = iterator.next();
			String key = entry.getKey().substring(0, entry.getKey().indexOf('.'));

			ComplexNode node = (ComplexNode) root.find(root.getKeyGroup() == null ? key : root.getKeyGroup());
			if (node == null) {
				node = new ComplexNode(key);
				root.add(node);
			}
			node.add(new SimpleNode(entry.getKey(), entry.getValue()));
		}
	}

	private static ComplexNode extractClass(Class<?> clazz, Object instance, int deep, int limit, boolean addID)
			throws Exception {
		if (deep > limit) {
			return new ComplexNode();
		}
		if (modelClassPK.get(clazz) == null) {
			return new ComplexNode();
		}

		Field[] fields = clazz.getDeclaredFields();
		Queue<CollectionModelClass> listModelQueue = new LinkedBlockingQueue<CollectionModelClass>();
		Queue<FieldModelClass> fieldModelQueue = new LinkedBlockingQueue<FieldModelClass>();
		ComplexNode nodeClass = new ComplexNode();
		// retrieve id of object model
		// Proccess properties of class
		String idModel = "";
		if (addID) {
			idModel = findModelPkByClass(fields, clazz, instance);
		}
		for (int i = 0; i < fields.length; i++) {
			Field field = fields[i];
			// ignore id field and serial uid
			if (!field.getName().equals(modelClassPK.get(clazz)) && !fieldsFilter.contains(field.getName())) {
				field.setAccessible(true);
				String key = generateKey(clazz, idModel, field);
				Object value = field.get(instance);
				String typeField = field.getType().getName();
				// ignore null properties
				if (value == null) {
					if (isModelClass(typeField)) {
						String cod = modelClassCods.get(field.getType());
						if (cod == null || (deep + 1) == limit) {
							String idModelProperty = findModelPkByClass(field.getType().getDeclaredFields(),
									field.getType(), null);
							if (modelClassPK.get(field.getType()) != null) {
								String keyProperty = generateKey(clazz, idModel,
										field.getType().getDeclaredField(modelClassPK.get(field.getType())));
								nodeClass.add(new SimpleNode(keyProperty, idModelProperty));
							}
						}
					} else {
						nodeClass.add(new SimpleNode(key, null));
					}
					continue;
				}

				if (value instanceof Collection<?> && isModelClass(inferGenericClass(field).getName())) {
					// Collecion properties need another logic, queue for late
					listModelQueue.add(new CollectionModelClass(field, value));
				} else if (isModelClass(typeField)) {
					// Model properties need another logic, queue for late
					String cod = modelClassCods.get(field.getType());
					if (cod != null) {
						String idModelProperty = findModelPkByClass(value.getClass().getDeclaredFields(),
								value.getClass(), value);
						String keyProperty = generateKey(clazz, idModel,
								value.getClass().getDeclaredField(modelClassPK.get(value.getClass())));
						nodeClass.add(new SimpleNode(keyProperty, idModelProperty));
						fieldModelQueue.add(new FieldModelClass(value.getClass(), value));

					}
				} else if (value instanceof Date) {
					// Date properties format to show
					nodeClass.add(new SimpleNode(key, formatDate((Date) value)));
				} else {
					// Simple data add to stack properties node
					nodeClass.add(new SimpleNode(key, String.valueOf(value)));
				}
			}
		}

		// for each property call recursive to extract info to nodes
		for (Iterator<FieldModelClass> iterator = fieldModelQueue.iterator(); iterator.hasNext();) {
			FieldModelClass fieldModelClass = iterator.next();
			ComplexNode node = extractClass(fieldModelClass.getClazz(), fieldModelClass.getValue(), deep + 1, limit,
					addID);
			if (!node.getNodeList().isEmpty()) {
				nodeClass.add(node);
			}
		}

		// for each property call recursive to extract info to nodes
		for (Iterator<CollectionModelClass> iterator = listModelQueue.iterator(); iterator.hasNext();) {
			CollectionModelClass collectionModelClass = iterator.next();
			ComplexNode node = extractCollectionClass(collectionModelClass.getField(), collectionModelClass.getValue(),
					deep + 2, limit);
			if (!node.getNodeList().isEmpty()) {
				nodeClass.add(node);
			}
		}

		return nodeClass;
	}

	private static String findModelPkByClass(Field[] fields, Class<?> clazz, Object instance)
			throws IllegalAccessException {
		String idModel = modelClassPK.get(clazz);
		String value = "";
		if (idModel == null || "".equals(idModel) || instance == null) {
			return value;
		}
		for (int i = 0; i < fields.length && "".equals(value); i++) {
			Field field = fields[i];
			if (field != null && idModel.equalsIgnoreCase(field.getName())) {
				field.setAccessible(true);
				Object temp = field.get(instance);
				if (temp != null) {
					return temp.toString();
				}
			}
		}
		return value;
	}

	protected static String formatDate(Date fecha) {
		TimeZone tz = TimeZone.getTimeZone("UTC");
		DateFormat df = new SimpleDateFormat(DATE_FORMAT);
		df.setTimeZone(tz);
		return df.format(fecha);
	}

	protected static String generateKey(Class<?> clazz, String idElem, Field field) {
		String codTable = modelClassCods.get(clazz);
		if (codTable == null) {
			codTable = "";
		}
		String fielName = field.getName();

		return "{cod}{id}.{field}".replace("{cod}", codTable).replace("{id}", idElem).replace("{field}", fielName);
	}

	private static ComplexNode extractCollectionClass(Field field, Object value, int deep, int limit) throws Exception {
		if (deep > limit) {
			return new ComplexNode();
		}
		Collection<?> collection = (Collection<?>) value;
		Class<?> originalClass = inferGenericClass(field);

		ComplexNode rootCollection = new ComplexNode();
		for (Iterator<?> iterator = collection.iterator(); iterator.hasNext();) {
			Object object = iterator.next();
			ComplexNode node = extractClass(originalClass, object, deep, limit, true);
			rootCollection.add(node);
		}

		return rootCollection;
	}

	protected static boolean isModelClass(String typeField) {
		return Pattern.matches(PACKAGE_MODEL_PATTERN, typeField);
	}

	private static Class<?> inferGenericClass(Field field) {
		Type genericFieldType = field.getGenericType();
		if (genericFieldType instanceof ParameterizedType) {
			ParameterizedType aType = (ParameterizedType) genericFieldType;
			Type[] fieldArgTypes = aType.getActualTypeArguments();
			for (Type fieldArgType : fieldArgTypes) {
				return (Class<?>) fieldArgType;
			}
		}
		return null;
	}

	public static void main(String[] args) throws Exception {
		Establecimiento est = createEstablecimiento();
		est.setEstablecimientoData(createDataEstablcimiento());
		// Add agencia

		DatosEstablecimientoWS datosEstablecimientoWS = descomponerEstablecimiento(est);

		com.ejie.ab63.service.serviciosWeb.model.DatosEstablecimientoWS datos = new com.ejie.ab63.service.serviciosWeb.model.DatosEstablecimientoWS();
		parseDatosValidarWS(datosEstablecimientoWS.getDatosValidarWS(), datos.getDatosValidarWS());
		for (int i = 0; i < datosEstablecimientoWS.getObjetosValidarWS().size(); i++) {
			ObjetosValidarWS objetosValidarWS = datosEstablecimientoWS.getObjetosValidarWS().get(i);
			com.ejie.ab63.service.serviciosWeb.model.ObjetosValidarWS validarWS = new com.ejie.ab63.service.serviciosWeb.model.ObjetosValidarWS();
			validarWS.setIdObjetosValidarWS(objetosValidarWS.getIdObjetoValidar());
			parseDatosValidarWS(objetosValidarWS.getDatosValidarWS(), validarWS.getDatosValidarWS());
			datos.getObjetosValidarWS().add(validarWS);
		}
		actualizarEstablecimiento(datos, est);
	}

	protected static void parseDatosValidarWS(List<DatosValidarWS> datosEstablecimientoWS,
			List<com.ejie.ab63.service.serviciosWeb.model.DatosValidarWS> datos) {
		for (int i = 0; i < datosEstablecimientoWS.size(); i++) {
			DatosValidarWS datosValidar = datosEstablecimientoWS.get(i);
			com.ejie.ab63.service.serviciosWeb.model.DatosValidarWS datoNuevo = new com.ejie.ab63.service.serviciosWeb.model.DatosValidarWS();
			datoNuevo.setIdentificadorDatoEstablecimiento(datosValidar.getIdentificadorDatoEstablecimiento());
			datoNuevo.setValorValidar(datosValidar.getValorValidar());
			datos.add(datoNuevo);
		}
	}

	private static Establecimiento createEstablecimiento() {
		Establecimiento est = new Establecimiento();
		est.setAgrupacion("AAA");
		est.setAperturaDesde(new Date());
		est.setAperturaHasta(new Date());
		est.setAutocompleteEstablecimiento("AAA");
		est.setCIE("AAA");
		est.setCorreoElectronico("AAA");
		est.setDescrNombre("AAA");
		est.setEliminado("AAA");
		est.setExpedienteb29("AAA");
		est.setFechaApertura(new Date());
		est.setFechaBaja(new Date());
		est.setFechaClausura(new Date());
		est.setFechaControlS41(new Date());
		est.setFechaFincierretemp(new Date());
		est.setFechaInicierretemp(new Date());
		est.setFechaInscripcion(new Date());
		est.setFechaProInspeccion(new Date());
		est.setFechaRegistro(new Date());
		est.setFechaUltActualizacion(new Date());
		est.setFechaUltInspeccion(new Date());
		est.setFechaUltmodificacion(new Date());
		est.setFechaUltNotificacion(new Date());
		est.setFechaUltReforma(new Date());
		est.setFechaVctoCierre(new Date());
		est.setIdDefectos("AAA");
		est.setIdentificadorEstablecimiento("AAA");
		est.setIdentificadorSolicitud("AAA");
		est.setIdEstablecimiento(1);
		est.setIdEstablecimientoPadre("AAA");
		est.setIdExpediente("AAA");
		est.setIdPortalS41(1L);
		est.setNumInstalacionAnterior("AAA");
		est.setNumInstalacionWz("AAA");
		est.setNumUnidadesAlojamiento(1);
		est.setObservaciones("AAA");
		est.setObservaciones2("AAA");
		est.setObsSegrespcivil("AAA");
		est.setRefCatastral("AAA");
		est.setTelefono("AAA");
		est.setTemporada("AAA");
		est.setTipoRegistro("AAA");
		est.setUrlPortalS41("AAA");
		est.setUrlweb("AAA");
		est.setUsuarioRegistro("AAA");
		est.setUsuarioUltmodificacion("AAA");
		est.setVisibleweb("AAA");
		est.setEspecialidad(new Especialidad("1", "descCategoriaEs", null, "nomUsuario", 0, "descCategoriaEu", null,
				null, null, null, new TipoEstablecimiento(1 + "")));
		est.setCategoria(new Categoria("1", "descCategoriaEs", null, "nomUsuario", 0, "descCategoriaEu", null, null,
				null, null, new TipoEstablecimiento(1 + "")));
		est.setGrupo(new Grupo("1", "descGrupoEs", null, "nomUsuario", 0, "descGrupoEu", null, null, null, null,
				new TipoEstablecimiento(1 + "")));
		est.setModalidad(new Modalidad("1", "descModalidadEs", null, "nomUsuario", 0, "descModalidadEu", null, null,
				null, null, new TipoEstablecimiento(1 + "")));
		est.setFranquicia(new AgenciaData(1, 1, new TipoFranquicia((long) 1), 1, "idInstalOfiPrincipal",
				"idOrigenOfiPrincipal", "idTipoCie", "etiquetaCie", "registroFianza", "observFianza", "observSrc",
				"idPrimeraSucursal", "numCie", null, null, null, null));
		est.setPeriodoPuentes("1");
		est.setPeriodoVacaciones("0");
		est.setPeriodoVerano("0");
		est.setSinPeriodoPref("1");
		return est;
	}

	private static EstablecimientoData createDataEstablcimiento() {
		EstablecimientoData data = new EstablecimientoData(1);
		data.setBar(0);
		data.setComparteInstal(1);
		data.setComparteViviendas(1);
		data.setDerechoCocina(1);
		data.setEdificioCatalogado(1);
		data.setFechaAnoConstruccion(1920L);
		data.setFechaAnoRenovacion(1970L);
		data.setFechaRegistro(new Date());
		data.setFechaUltmodificacion(new Date());
		data.setIdEstablecimiento(1);
		data.setNumApartamentos(1L);
		data.setNumBanosGenerales(1L);
		data.setNumComedores(1L);
		data.setNumConjuntos(2L);
		data.setNumControl(1L);
		data.setNumEstudios(0L);
		data.setNumHabDoble(1L);
		data.setNumHabDobleCs(1L);
		data.setNumHabIndividuales(2L);
		data.setNumHabitaciones("");
		data.setNumHabMas4(1L);
		data.setNumHabMenos4(3L);
		data.setNumInstalComparte("1");
		data.setNumMaximoSupletorias(1L);
		data.setNumParcelasAf(1L);
		data.setNumParcelasAnf(1L);
		data.setNumParcelasSa(1L);
		data.setNumPlazas(8L);
		data.setNumResidentesPerm("");
		data.setNumSalones(2L);
		data.setNumSalonesComedor(2L);
		data.setNumSuites(1L);
		data.setNumSupAcampada(new BigDecimal(1));
		data.setNumTotParcelas(2L);
		data.setPiscina(1);
		data.setRequisitos("no");
		data.setRestaurante(1);
		data.setServicioComedor(1);
		// data.setSupRestoDepen(" ");
		data.setSupTotHabitac("");
		data.setUsuarioRegistro("");
		data.setUsuarioUltmodificacion("");
		data.setListAseo(setListAseoEstablecimiento());
		data.setListAlojamiento(setListAlojamientoEstablecimiento());
		data.setListHabitacion(setListHabitacionEstablecimiento());
		data.setListHabitacionVivienda(setListHabitacionViviendaEstablecimiento());
		data.setListParcela(setListParcelaEstablecimiento());
		data.setListSalonComedor(setListSalonComedorEstablecimiento());
		data.setListSuite(setListSuiteEstablecimiento());
		data.setListOtrasDependenciasVivienda(setListOtrasDependenciasViviendaEstablecimiento());
		data.setListZonaOcio(setListZonaOcio());

		return data;
	}

	private static List<ZonaOcio> setListZonaOcio() {
		List<ZonaOcio> list = new ArrayList<ZonaOcio>();
		for (int i = 1; i <= 2; i++) {
			ZonaOcio zonaOcio = new ZonaOcio(i);
			zonaOcio.setDescripcion("descripcion es");
			zonaOcio.setDescripcionEu("descripcion eu");
			zonaOcio.setNumSuperficie(new BigDecimal(2.33f));
			list.add(zonaOcio);
		}
		return list;
	}

	private static List<Aseo> setListAseoEstablecimiento() {
		List<Aseo> list = new ArrayList<Aseo>();
		for (int i = 1; i <= 2; i++) {
			Aseo aseo = new Aseo(i);
			aseo.setUbicacion("ubicacion");
			aseo.setNumUnidades(1L);
			aseo.setTipoAseo(new TipoAseo(i + "", "descTipoEs" + 1, new Date(), null, 0, null, null, null, null, null));
			// ADRI
			aseo.setCodigo(1);
			aseo.setNumSupTotal(new BigDecimal(i % 2));
			aseo.setTipoRegistro(1);
			aseo.setNumUnidadesAloj(1L);
			aseo.setDescTipoAseo("descTipoAseo");

			list.add(aseo);
		}
		return list;
	}

	private static List<Habitacion> setListHabitacionEstablecimiento() {
		List<Habitacion> list = new ArrayList<Habitacion>();
		for (int i = 1; i <= 2; i++) {
			Habitacion habitacion = new Habitacion(i);
			habitacion.setNumPlazas((i % 2L) + 1);
			habitacion.setNumUnidades(1L);
			habitacion.setTipoAseo(
					new TipoAseo(i + "", "descTipoEs" + 1, new Date(), null, 0, "descTipoEU", null, null, null, null));
			habitacion.setTipoHabitacion(new TipoHabitacion(i + "", "indivdobl", "descTipoEs", i % 2, i % 4L, null,
					null, 0, "descTipoEu", null, null, null, null));
			// ADRI
			habitacion.setDescTipoHab("descHabitacion");
			habitacion.setDescTipoAseo("descTipoAseo");
			habitacion.setTotalPlazas(1L);
			habitacion.setTipoRegistro(1);
			habitacion.setNumSupBanyoCompleto(new BigDecimal(i % 2));
			habitacion.setNumSupDuchaLavaboIno(new BigDecimal(i % 2));
			habitacion.setNumSupBanyoLavabo(new BigDecimal(i % 2));
			habitacion.setLavabo(1);
			habitacion.setNumHabitacion(1);
			habitacion.setNumSupTotal(new BigDecimal(i % 2));
			habitacion.setSalonPrivado(1);
			habitacion.setNumSupSalon(new BigDecimal(i % 2));
			habitacion.setTerraza(1);
			habitacion.setNumSupTerraza(new BigDecimal(i % 2));
			habitacion.setCamaSupletoria(1);
			habitacion.setAccesibilidad(1);
			habitacion.setOtrasCaracteristicas("otrasCaracteristicas");

			list.add(habitacion);
		}
		return list;
	}

	private static List<HabitacionVivienda> setListHabitacionViviendaEstablecimiento() {
		List<HabitacionVivienda> list = new ArrayList<HabitacionVivienda>();
		for (int i = 1; i <= 2; i++) {
			HabitacionVivienda habitacionVivienda = new HabitacionVivienda(i + "");
			habitacionVivienda.setAccesible(i % 2 + "");
			habitacionVivienda.setIdentHabitacion(i % 7 * i % 3 + "");
			habitacionVivienda.setIlumNatural(i % 2 + "");
			habitacionVivienda.setPlazasHab(i % 4 + "");
			habitacionVivienda.setUsoTuristico(i % 2 + "");
			habitacionVivienda.setVentilacionPatio(i % 2 + "");

			// ADRI
			habitacionVivienda.setSupDormitorio(new BigDecimal(i % 2));

			list.add(habitacionVivienda);
		}
		return list;
	}

	private static List<Alojamiento> setListAlojamientoEstablecimiento() {
		List<Alojamiento> list = new ArrayList<Alojamiento>();
		for (int i = 1; i <= 2; i++) {
			Alojamiento alojamiento = new Alojamiento(i);
			alojamiento.setCapacidad(i % 4 + "");
			alojamiento.setNumUnidades(1L);
			alojamiento.setDescNombreAlojamiento("descNombreAlojamiento[" + i % 4 + "]");
			alojamiento.setNumPlazasConvertibles(i % 4L);
			alojamiento.setNumPlazasDormitorio(i % 2L);
			alojamiento.setNumSupCocina(new BigDecimal(i % 2));
			alojamiento.setNumSupCocinaComedor(new BigDecimal(i % 2));
			alojamiento.setNumSupComedor(new BigDecimal(i % 2));
			alojamiento.setNumSupEstudio(new BigDecimal(i % 2));
			alojamiento.setNumSupSalon(new BigDecimal(i % 2));
			alojamiento.setNumSupSalonCocinaCom(new BigDecimal(i % 2));
			alojamiento.setNumSupSalonComedor(new BigDecimal(i % 2));
			alojamiento.setTipoAlojamiento("tipoAlojamiento[" + i % 4 + "]");
			alojamiento.setListHabitacionAlojamiento(setListHabitacionAlojamiento(alojamiento, i));
			alojamiento.setListAseoAlojamiento(setListAseoAlojamiento(alojamiento, i));

			// NUEVOS
			alojamiento.setDescTipoAlojamiento("descTipoAlojamiento");
			alojamiento.setTotalPlazas(1L);
			alojamiento.setTipoRegistro(1);
			alojamiento.setNumAlojamiento(1L);
			alojamiento.setNumSupTotal(new BigDecimal(i % 2));
			alojamiento.setCapacidadTotal(1L);
			alojamiento.setAccesibilidad(1);
			alojamiento.setOtrasCaracteristicas("otrasCaracteristicas");
			alojamiento.setDescAccesibilidad("descAccesibilidad");
			alojamiento.setAnyoApertura(BigInteger.valueOf(1));
			alojamiento.setAnyoUltimaRenovTotal(BigInteger.valueOf(1));
			alojamiento.setEspecialidad("especialidad");
			alojamiento.setNombrePersonaContacto("nombrePersonaContacto");

			list.add(alojamiento);
		}
		return list;
	}

	private static List<HabitacionAlojamiento> setListHabitacionAlojamiento(Alojamiento alojamiento, Integer n) {
		List<HabitacionAlojamiento> list = new ArrayList<HabitacionAlojamiento>();
		for (int i = 1; i <= 2; i++) {
			HabitacionAlojamiento habitacionAlojamiento = new HabitacionAlojamiento(i + n);
			habitacionAlojamiento.setNumUnidades(10L);
			habitacionAlojamiento.setNumPlazas(2L);
			habitacionAlojamiento.setTipoHabitacion(
					new TipoHabitacion("TipoHabitacion[" + i % 4 + "]", i % 2 + "", "descTipoHEs[" + i + "]", 0,
							(i % 3) + 0L, null, null, 0, "descTipoHEu[" + i + "]", null, null, null, null));
			habitacionAlojamiento.setTipoAseo(new TipoAseo("TipoAseo[" + i % 4 + "]", "descTipoAEs[" + i + "]", null,
					null, 0, "descTipoAEu[" + i + "]", null, null, null, null));
			habitacionAlojamiento.setAlojamiento(alojamiento);

			// NUEVOS
			habitacionAlojamiento.setTipoRegistro(1);
			habitacionAlojamiento.setDescTipoHab("DescTipoHab");
			habitacionAlojamiento.setDescTipoAseo("DescTipoAseo");
			habitacionAlojamiento.setNumSupBanyoCompleto(new BigDecimal(i % 2));
			habitacionAlojamiento.setNumSupDuchaLavaboIno(new BigDecimal(i % 2));
			habitacionAlojamiento.setNumSupBanyoLavabo(new BigDecimal(i % 2));
			habitacionAlojamiento.setLavabo(1);
			habitacionAlojamiento.setNumHabitacion(1);
			habitacionAlojamiento.setNumSupTotal(new BigDecimal(i % 2));
			habitacionAlojamiento.setSalonPrivado(1);
			habitacionAlojamiento.setNumSupSalon(new BigDecimal(i % 2));
			habitacionAlojamiento.setTerraza(1);
			habitacionAlojamiento.setNumSupTerraza(new BigDecimal(i % 2));
			habitacionAlojamiento.setCamaSupletoria(1);
			habitacionAlojamiento.setAccesibilidad(1);
			habitacionAlojamiento.setOtrasCaracteristicas("OtrasCaracteristicas");
			habitacionAlojamiento.setNumHabIndividuales(BigInteger.valueOf(1));
			habitacionAlojamiento.setNumHabDobles(BigInteger.valueOf(1));
			habitacionAlojamiento.setNumHabSalon(BigInteger.valueOf(1));
			habitacionAlojamiento.setNumHabSuite(BigInteger.valueOf(1));
			habitacionAlojamiento.setNumHabHasta4Plazas(BigInteger.valueOf(1));
			habitacionAlojamiento.setNumHabMas4Plazas(BigInteger.valueOf(1));

			list.add(habitacionAlojamiento);
		}
		return list;
	}

	private static List<AseoAlojamiento> setListAseoAlojamiento(Alojamiento alojamiento, Integer n) {
		List<AseoAlojamiento> list = new ArrayList<AseoAlojamiento>();
		for (int i = 1; i <= 2; i++) {
			AseoAlojamiento aseoAlojamiento = new AseoAlojamiento(i + n);
			aseoAlojamiento.setNumSuperficie(new BigDecimal(25));
			aseoAlojamiento.setTipoAseo(new TipoAseo("TipoAseo[" + i % 4 + "]", "descTipoAEs[" + i + "]", null, null, 0,
					"descTipoAEu[" + i + "]", null, null, null, null));
			aseoAlojamiento.setAlojamiento(alojamiento);

			// NUEVOS
			aseoAlojamiento.setDescTipoAseo("DescTipoAseo");
			aseoAlojamiento.setNumAseoAlojamiento(1L);

			list.add(aseoAlojamiento);
		}
		return list;
	}

	private static List<OtrasDependenciasVivienda> setListOtrasDependenciasViviendaEstablecimiento() {
		List<OtrasDependenciasVivienda> list = new ArrayList<OtrasDependenciasVivienda>();
		for (int i = 1; i <= 2; i++) {
			OtrasDependenciasVivienda otrasDependenciasVivienda = new OtrasDependenciasVivienda(i + "");
			otrasDependenciasVivienda.setAccesible(i % 2 + "");
			// otrasDependenciasVivienda.setDenomDependencia("denomDependencia");
			otrasDependenciasVivienda.setEsCuartoBano(i % 2 + "");
			// otrasDependenciasVivienda.setSupDependencia(i % 2 + "");
			list.add(otrasDependenciasVivienda);
		}
		return list;
	}

	private static List<Parcela> setListParcelaEstablecimiento() {
		List<Parcela> list = new ArrayList<Parcela>();

		for (int i = 1; i <= 2; i++) {
			Parcela parcela = new Parcela(i + 0L);
			parcela.setNumPlazas((i % 4L) + 1);
			parcela.setNumUnidades(1L);
			parcela.setAgua("Agua");
			parcela.setAlbergueFijo(i % 2);
			parcela.setDesague("Desague");
			parcela.setElectricidad("Electricidad");
			parcela.setNombre("nombre");
			parcela.setNumSuperficie(new BigDecimal(i * 9));
			parcela.setNumPlazasTipo(i % 2);

			// NUEVOS
			parcela.setNumPlazasTipo(1);
			parcela.setTipoRegistro(1);
			parcela.setNumParcela(1L);
			parcela.setAccesibilidad(1);
			parcela.setOtrasCaracteristicas("OtrasCaracteristicas");
			parcela.setDescAccesibilidad("DescAccesibilidad");

			list.add(parcela);
		}
		return list;
	}

	private static List<SalonComedor> setListSalonComedorEstablecimiento() {
		List<SalonComedor> list = new ArrayList<SalonComedor>();

		for (int i = 1; i <= 2; i++) {
			SalonComedor salonComedor = new SalonComedor(i);
			salonComedor.setDescNombre("descNombre");
			salonComedor.setHabilitado(i % 2 + "");
			salonComedor.setIdTipo(i % 3 + "");
			salonComedor.setNumSuperficie(new BigDecimal(i % 7));

			// NUEVOS
			salonComedor.setDescTipo("DescTipo");

			list.add(salonComedor);
		}
		return list;
	}

	private static List<Suite> setListSuiteEstablecimiento() {
		List<Suite> list = new ArrayList<Suite>();
		for (int i = 1; i <= 2; i++) {
			Suite suite = new Suite(i + 0L);
			suite.setNumPlazas((i % 4L) + 1);
			suite.setNumUnidades(1L);
			suite.setDescNombre("descNombre");
			suite.setNumHabDoble(i % 3L);
			suite.setNumHabIndividuales(i % 3L);
			suite.setNumPlazasTipo(i % 3);
			suite.setNumSalones(i % 3L);

			// NUEVOS
			suite.setTotalPlazas(1L);
			suite.setTipoRegistro(1);
			suite.setNumSuite(1L);
			suite.setNumSupTotal(new BigDecimal(i % 2));
			suite.setSalonPrivado(1);
			suite.setNumSupSalon(new BigDecimal(i % 2));
			suite.setTerraza(1);
			suite.setNumSupTerraza(new BigDecimal(i % 2));
			suite.setAccesibilidad(1);
			suite.setOtrasCaracteristicas("OtrasCaracteristicas");

			list.add(suite);
		}
		return list;
	}

}

class CollectionModelClass {
	private Field field;
	private Object value;

	public CollectionModelClass(Field field, Object value) {
		this.field = field;
		this.value = value;
	}

	public Field getField() {
		return field;
	}

	public Object getValue() {
		return value;
	}

}

class FieldModelClass {
	private Class<?> clazz;
	private Object value;

	public FieldModelClass(Class<?> clazz, Object value) {
		this.clazz = clazz;
		this.value = value;
	}

	public Class<?> getClazz() {
		return clazz;
	}

	public Object getValue() {
		return value;
	}

}
