package com.ejie.ab04b.util;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.ejie.ab04b.constantes.Constantes;
import com.ejie.ab04b.constantes.ConstantesPlateaTramitacion;
import com.ejie.ab04b.exception.AB04BParseException;
import com.ejie.ab04b.model.DatosAviso;
import com.ejie.ab04b.model.DatosLocalizacion;
import com.ejie.ab04b.model.DatosNotificacion;
import com.ejie.ab04b.model.pps.PPSReturnInfo;
import com.ejie.ab04b.parse.MessageParser;
import com.ejie.ab04b.parse.MessageUnparser;
import com.ejie.ctfm.xml.Addressee;
import com.ejie.ctfm.xml.Channel;
import com.ejie.ctfm.xml.ContextSubmission;
import com.ejie.ctfm.xml.ContextSubmission.DataControl;
import com.ejie.ctfm.xml.Notice;
import com.ejie.ctfm.xml.Notices;
import com.ejie.foldermanagement.xml.ContextRegistry;
import com.ejie.foldermanagement.xml.Property;
import com.ejie.foldermanagement.xml.RequestReturn;
import com.ejie.platea.generic.xml.ChannelInfo;
import com.ejie.platea.generic.xml.DepartmentName;
import com.ejie.platea.generic.xml.EntityName;
import com.ejie.platea.generic.xml.ManagingUnitName;
import com.ejie.platea.generic.xml.PostalAddress;
import com.ejie.platea.generic.xml.ProcedureName;
import com.ejie.sc.xml.ConsultationContext;

/**
 * @author GFI-NORTE
 * 
 */
public final class PPSUtils {

	private static final String TAG_STORED_APPLICATION_INFO_FOLDERID = "folderID";

	private static PPSUtils instance = null;

	private static final Logger LOGGER = LoggerFactory
			.getLogger(PPSUtils.class);

	/**
	 * Constructor privado.
	 */
	private PPSUtils() {

	}

	/**
	 * Gets the single instance of PPSUtils.
	 * 
	 *  PPSUtils
	 *
	 * @return single instance of PPSUtils
	 */
	public static PPSUtils getInstance() {
		if (PPSUtils.instance == null) {
			PPSUtils.instance = new PPSUtils();
		}
		return PPSUtils.instance;
	}

	/**
	 * Crea el apartado con la informacion del procedimiento del XML del
	 * ContextSubmission.
	 * 
	 *  ctxSubmission
	 *            ContextSubmission
	 *  infoProcedure
	 *            ConsultationContext que representa el XML que devuelve el
	 *            metodo getSoftConsultatioContext del WS de FDCDP
	 * 
	 * 
	 *            return : ContextSubmission con la informacion del
	 *            procedimiento rellena
	 *
	 * @param ctxSubmission the ctx submission
	 * @param infoProcedure the info procedure
	 */
	public void addContextSubmissionFromInfoProcedure(
			ContextSubmission ctxSubmission, ConsultationContext infoProcedure) {

		ctxSubmission.setDeliveryKey(Constantes.VACIO); // se crea aunque vacio

		// IDs
		ctxSubmission.setDepartmentID(infoProcedure.getDepartmentId());
		ctxSubmission.setEntityID(infoProcedure.getEntityID());
		ctxSubmission.setFamilyID(infoProcedure.getFamilyId());
		ctxSubmission.setManagingUnitID(infoProcedure.getOrganInfo()
				.getManagingUnitId());
		ctxSubmission.setProcedureID(infoProcedure.getProcedureId());

		// Names traducidos del objeto SC al folderManagement
		if (null != infoProcedure.getDepartmentName()) {
			DepartmentName departmentName = new DepartmentName();
			departmentName.setDescription(infoProcedure.getDepartmentName()
					.getDescription());
			ctxSubmission.setDepartmentName(departmentName);
		}

		if (null != infoProcedure.getOrganInfo()
				&& null != infoProcedure.getOrganInfo().getManagingUnitName()) {
			ManagingUnitName managingUnitName = new ManagingUnitName();
			managingUnitName.setDescription(infoProcedure.getOrganInfo()
					.getManagingUnitName().getDescription());
			ctxSubmission.setManagingUnitName(managingUnitName);
		}

		if (null != infoProcedure.getProcedureName()) {
			ProcedureName procedureName = new ProcedureName();
			procedureName.setDescription(infoProcedure.getProcedureName()
					.getDescription());
			ctxSubmission.setProcedureName(procedureName);
		}

		if (null != infoProcedure.getEntityName()) {
			EntityName entityName = new EntityName();
			entityName.setDescription(infoProcedure.getEntityName()
					.getDescription());
			ctxSubmission.setEntityName(entityName);
		}

	}

	/**
	 * Construir platea description.
	 * 
	 *  descEs
	 *            String
	 *  descEu
	 *            String
	 *  DescriptionType
	 *
	 * @param descEs the desc es
	 * @param descEu the desc eu
	 * @return the com.ejie.platea.generic.xml. description
	 */
	public com.ejie.platea.generic.xml.Description construirPlateaDescription(
			String descEs, String descEu) {

		com.ejie.platea.generic.xml.Description description = new com.ejie.platea.generic.xml.Description();
		description.getLanguage().add(
				this.construirPlateaLanguage(Constantes.ES, descEs));
		description.getLanguage().add(
				this.construirPlateaLanguage(Constantes.EU, descEu));
		return description;
	}

	/**
	 * Construir platea language.
	 * 
	 *  locale
	 *            String
	 *  value
	 *            String
	 *  Language
	 *
	 * @param locale the locale
	 * @param value the value
	 * @return the com.ejie.platea.generic.xml. language
	 */
	public com.ejie.platea.generic.xml.Language construirPlateaLanguage(
			String locale, String value) {

		com.ejie.platea.generic.xml.Language language = new com.ejie.platea.generic.xml.Language();
		language.setLocale(locale);
		language.setValue(value);
		return language;
	}

	/**
	 * Construir platea provincia.
	 * 
	 *  descEs
	 *            String
	 *  descEu
	 *            String
	 *  Provincia
	 *
	 * @param descEs the desc es
	 * @param descEu the desc eu
	 * @return the com.ejie.platea.generic.xml. provincia
	 */
	public com.ejie.platea.generic.xml.Provincia construirPlateaProvincia(
			String descEs, String descEu) {

		com.ejie.platea.generic.xml.Provincia provincia = new com.ejie.platea.generic.xml.Provincia();
		provincia.getLanguage().add(
				this.construirPlateaLanguage(Constantes.ES, descEs));
		provincia.getLanguage().add(
				this.construirPlateaLanguage(Constantes.EU, descEu));
		return provincia;
	}

	/**
	 * Construir channel.
	 * 
	 *  datosNotificacion
	 *            DatosNotificacion
	 *  Channel
	 *
	 * @param datosNotificacion the datos notificacion
	 * @return the channel
	 */
	public Channel construirChannel(DatosNotificacion datosNotificacion) {

		Channel channel = new Channel();
		ChannelInfo channelInfo = new ChannelInfo();

		if (datosNotificacion != null) {
			if (Constantes.CANAL_NOTIF_TELEMATICO.equals(datosNotificacion
					.getCanalnotif066())) {
				channel.setChannelType(ConstantesPlateaTramitacion.CS_TIPO_NOTIF_ELECTRONICA);
				channelInfo.setElectronicAddress("");
			} else if (Constantes.CANAL_NOTIF_POSTAL.equals(datosNotificacion
					.getCanalnotif066())) {

				channel.setChannelType(ConstantesPlateaTramitacion.CS_TIPO_NOTIF_POSTAL);
				PostalAddress postalAddress = new PostalAddress();

				postalAddress.setPais(Constantes.ID_PAIS_ESPANA);

				DatosLocalizacion datosLocalizacion = datosNotificacion
						.getDatosLocalizacion();
				if (datosLocalizacion != null) {

					postalAddress.setDireccion(datosLocalizacion.getCalle067());
					postalAddress.setLocalidad(datosLocalizacion.getLocalidad()
							.getDescripcion());
					postalAddress.setMunicipio(datosLocalizacion.getMunicipio()
							.getDescripcion());

					postalAddress.setProvincia(PPSUtils.getInstance()
							.construirPlateaProvincia(
									datosLocalizacion.getProvincia()
											.getDescripcion(),
									datosLocalizacion.getProvincia()
											.getDescripcion()));
					postalAddress.setPortal(datosLocalizacion.getPortal067());
					postalAddress.setEscalera(Constantes.VACIO);
					postalAddress.setPiso(datosLocalizacion.getPiso067());
					postalAddress.setLetra(datosLocalizacion.getPuerta067());
					postalAddress.setCp(datosLocalizacion.getCodpostal067());
				}

				channelInfo.setPostalAddress(postalAddress);
			}
		}
		channel.setChannelInfo(channelInfo);

		return channel;
	}

	/**
	 * Gets the notices applicant info.
	 * 
	 *  addresseeId
	 *            String
	 *  addresseeName
	 *            String
	 *  listaDatosAviso
	 *            List<DatosAviso>
	 *  Notices
	 *
	 * @param addresseeId the addressee id
	 * @param addresseeName the addressee name
	 * @param listaDatosAviso the lista datos aviso
	 * @return the notices applicant info
	 */
	public Notices getNoticesApplicantInfo(String addresseeId,
			String addresseeName, List<DatosAviso> listaDatosAviso) {

		Notices objNotices = new Notices();

		if (listaDatosAviso != null && !listaDatosAviso.isEmpty()) {
			Addressee objAd = new Addressee();
			objAd.setAddresseeID(addresseeId);
			objAd.setAddresseeName(addresseeName);

			for (DatosAviso datosAviso : listaDatosAviso) {
				Notice obj = new Notice();
				obj.setAddressee(objAd);
				Channel canal = new Channel();
				ChannelInfo chInfo = new ChannelInfo();
				if (Constantes.CANAL_AVISO_EMAIL
						.equals(datosAviso.getTipo068())) {
					canal.setChannelType(ConstantesPlateaTramitacion.CS_TIPO_AVISO_EMAIL);
					chInfo.setEmailAddress(datosAviso.getValor068());
				} else if (Constantes.CANAL_AVISO_SMS.equals(datosAviso
						.getTipo068())) {
					canal.setChannelType(ConstantesPlateaTramitacion.CS_TIPO_AVISO_SMS);
					chInfo.setSmsNumber(datosAviso.getValor068());
				}
				canal.setChannelInfo(chInfo);
				obj.setChannel(canal);
				objNotices.getNotice().add(obj);
			}
		}

		return objNotices;
	}

	/**
	 * A partir de un ContextSubmission, devuelve su representación XML en un
	 * String.
	 * 
	 *  contextSubmission
	 *            objeto de tipo ContextSubmission
	 *  String e
	 *
	 * @param contextSubmission the context submission
	 * @return the context submission as string
	 */
	public String getContextSubmissionAsString(
			ContextSubmission contextSubmission) {
		MessageUnparser<ContextSubmission> unparser = new MessageUnparser<ContextSubmission>();

		// guardamos y sustituimos para que el marshaller no lo transforme
		String strSubmissionTypeName = this
				.getPlateaDescriptionAsString((com.ejie.platea.generic.xml.Description) (contextSubmission
						.getSubmissionTypeName()));
		contextSubmission.setSubmissionTypeName("##SUBMISSIONTYPENAME##");

		String resultado = null;
		try {
			resultado = unparser.parse(contextSubmission);

			resultado = resultado.replace("##SUBMISSIONTYPENAME##",
					strSubmissionTypeName);
		} catch (Exception e) {
			PPSUtils.LOGGER
					.error("Error en el parseo del objeto getContextSubmissionAsString",
							e);
		}
		return resultado;
	}

	/**
	 * A partir de un Description, devuelve su representación XML en un String.
	 * 
	 *  description
	 *            objeto de tipo Description
	 *  String e
	 *
	 * @param description the description
	 * @return the platea description as string
	 */
	public String getPlateaDescriptionAsString(
			com.ejie.platea.generic.xml.Description description) {

		MessageUnparser<com.ejie.platea.generic.xml.Description> unparser = new MessageUnparser<com.ejie.platea.generic.xml.Description>();

		String resultado = null;
		try {
			resultado = unparser.parse(description);
		} catch (Exception e) {
			PPSUtils.LOGGER
					.error("Error en el parseo del objeto getPlateaDescriptionAsString",
							e);
		}
		return resultado;
	}

	/**
	 * Devuelve un objeto DataControl correspondiente a la seccion dataControl
	 * del ContextSubmission.
	 * 
	 *  List<DataControl>
	 *
	 * @return the list data control
	 */
	public List<DataControl> getListDataControl() {

		List<DataControl> list = new ArrayList<DataControl>();
		DataControl dataControl = new DataControl();

		dataControl
				.setType(ConstantesPlateaTramitacion.CTXSUBMISSION_TYPE_MESSAGE_CONTROL);
		dataControl
				.setValue(ConstantesPlateaTramitacion.CTXSUBMISSION_VALUE_MESSAGE_CONTROL);
		list.add(dataControl);

		dataControl = new DataControl();
		dataControl
				.setType(ConstantesPlateaTramitacion.CTXSUBMISSION_TYPE_CERTIFIED_VALIDATION_MODE);
		dataControl
				.setValue(ConstantesPlateaTramitacion.CTXSUBMISSION_VALUE_CERTIFIED_VALIDATION_MODE);
		list.add(dataControl);

		return list;
	}

	/**
	 * Devuelve un objeto RequestReturn a partir de su representación XML en
	 * String.
	 * 
	 *  response
	 *            String
	 *  RequestReturn
	 *
	 * @param response the response
	 * @return the PPS as request return
	 * @throws AB04BParseException             expcepción al parsear la respuesta del PPS
	 */
	public RequestReturn getPPSAsRequestReturn(String response)
			throws AB04BParseException {

		PPSUtils.LOGGER.info("getPPSAsRequestReturn");

		RequestReturn obj = null;
		try {
			obj = (RequestReturn) new MessageParser<RequestReturn>(
					RequestReturn.class.getPackage().getName()).parse(response);
		} catch (Exception e) {
			PPSUtils.LOGGER
					.error("Error en el parseo del objeto response como RequestReturn",
							e);

			throw new AB04BParseException(
					e,
					"LOG NEGOCIO: getPPSAsRequestReturn --> Error en el parseo del objeto response como RequestReturn");
		}

		return obj;
	}

	/**
	 * Obtener PPS return info.
	 * 
	 *  requestReturn
	 *            RequestReturn
	 *  PPSReturnInfo
	 *
	 * @param requestReturn the request return
	 * @return the PPS return info
	 */
	public PPSReturnInfo obtenerPPSReturnInfo(RequestReturn requestReturn) {

		PPSReturnInfo ppsReturnInfo = new PPSReturnInfo();

		try {
			if (requestReturn != null && requestReturn.getProperty() != null) {
				for (Property property : requestReturn.getProperty()) {
					Node node = ((Node) property.getXmlValue().get(0))
							.getFirstChild();
					if (ConstantesPlateaTramitacion.PPS_RETURN_PROPERTY_REGISTRY
							.equals(property.getName())) {
						String snode = XmlUtils.parseDocument2String(node);
						ContextRegistry contextRegistry = this
								.getRegistryInfoAsContextRegistry(snode);

						ppsReturnInfo.setNumRegistro(contextRegistry
								.getRegistryNumber());
						ppsReturnInfo
								.setFecRegistro(new SimpleDateFormat(
										ConstantesPlateaTramitacion.PPS_REGISTRY_TIMESTAMP_FORMAT)
										.parse(contextRegistry
												.getRegistryTimestamp()));

					} else if (ConstantesPlateaTramitacion.PPS_RETURN_PROPERTY_APPLICATION
							.equals(property.getName())) {
						boolean encontrado = false;
						NodeList nodeList = node.getChildNodes();
						for (int i = 0; i < nodeList.getLength() && !encontrado; i++) {
							if (PPSUtils.TAG_STORED_APPLICATION_INFO_FOLDERID
									.equals(nodeList.item(i).getNodeName())) {
								ppsReturnInfo.setFolderId(nodeList.item(i)
										.getFirstChild().getNodeValue());
								encontrado = true;
							}
						}
					}
				}
			}
			return ppsReturnInfo;
		} catch (Exception ex) {
			PPSUtils.LOGGER.error("Error al parsear RequestReturn", ex);
			return null;
		}
	}

	/**
	 * Devuelve un objeto RequestReturn a partir de su representación XML en
	 * String.
	 * 
	 *  registryInfo
	 *            String
	 *  ContextRegistry
	 *
	 * @param registryInfo the registry info
	 * @return the registry info as context registry
	 * @throws AB04BParseException             expcepción al parsear la respuesta
	 */
	public ContextRegistry getRegistryInfoAsContextRegistry(String registryInfo)
			throws AB04BParseException {

		PPSUtils.LOGGER.info("getRegistryInfoAsContextRegistry");

		ContextRegistry obj = null;
		try {
			obj = (ContextRegistry) new MessageParser<ContextRegistry>(
					ContextRegistry.class.getPackage().getName())
					.parse(registryInfo);
		} catch (Exception e) {
			PPSUtils.LOGGER
					.error("Error en el parseo del objeto response como ContextRegistry",
							e);

			throw new AB04BParseException(
					e,
					"LOG NEGOCIO: getRegistryInfoAsContextRegistry --> Error en el parseo del objeto registryInfo como ContextRegistry");
		}

		return obj;
	}

}
