/**
 * Copyright 2008-2009 DRIVER PROJECT (Bielefeld University)
 * Original author: Marek Imialek <marek.imialek at uni-bielefeld.de>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package eu.dnetlib.data.sts.profile.utils;

import java.io.IOException;
import java.io.StringReader;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import eu.dnetlib.common.profile.Body;
import eu.dnetlib.common.profile.Profile;
import eu.dnetlib.common.profile.ProfileHeader;

import eu.dnetlib.data.sts.profile.sdo.SdoProfileBody;
import eu.dnetlib.data.sts.profile.sdo.SdoProfileConfiguration;
import eu.dnetlib.data.sts.profile.sdo.SdoProfileStatus;

/**
 * @author <a href="mailto:marek.imialek at uni-bielefeld.de">Marek Imialek</a>
 *
 */
public class SDOProfileUnmarshaller {
	
	/** The Constant log. */
	protected static final Logger log = Logger
			.getLogger(SDOProfileUnmarshaller.class);

	/** The Constant FIELDS_DELIMITER. */
	public static final String FIELDS_DELIMITER = ",";

	/** The db. */
	static DocumentBuilder db = null;

	static {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		factory.setIgnoringComments(true);
		factory.setValidating(false);
		
		try {
			db = factory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			log.error("Problem occured when creating document builder!", e);
		}

	}

	/**
	 * Unmarshall header.
	 * 
	 * @param headerElement the header element
	 * 
	 * @return the profile header
	 */
	private static ProfileHeader unmarshallHeader(Element headerElement) {
		if (headerElement == null)
			return null;
		String resourceIdentifier = Marshaller.getSingleElementValueAttr(headerElement,
				"RESOURCE_IDENTIFIER");
		String resourceType = Marshaller.getSingleElementValueAttr(headerElement,
				"RESOURCE_TYPE");
		String resourceKind = Marshaller.getSingleElementValueAttr(headerElement,
				"RESOURCE_KIND");
		ProfileHeader profileHeader = new ProfileHeader(resourceIdentifier,
				resourceType, resourceKind);
		profileHeader.setResourceURI(Marshaller.getSingleElementValueAttr(headerElement,
				"RESOURCE_URI"));
		profileHeader.setDateOfCreation(Marshaller.getSingleElementValueAttr(
				headerElement, "DATE_OF_CREATION"));

		return profileHeader;
	}

	/**
	 * Unmarshall sdo resource.
	 * 
	 * @param profileContent the profile content
	 * 
	 * @return the profile
	 */
	public static Profile unmarshallSDOResource(String profileContent) {
		try {
			
			if (profileContent == null)
				return null;
		
			Document doc = db.parse(new InputSource(new StringReader(
					profileContent)));
			Element root = doc.getDocumentElement();

			if (root == null || !root.getNodeName().equals("RESOURCE_PROFILE")) {
				log.info("Couldn't find RESOURCE_PROFILE as a root element!");
				return null;
			}
			NodeList headerList = root.getElementsByTagName("HEADER");
			if (headerList == null || headerList.getLength() != 1) {
				log.error("Couldn't find one HEADER element within profile!");
				return null;
			}
			NodeList bodyList = root.getElementsByTagName("BODY");
			if (bodyList == null || bodyList.getLength() != 1) {
				log.error("Couldn't find one BODY element within profile!");
				return null;
			}
			
			Profile profile = new Profile();
			profile.setHeader(unmarshallHeader((Element) headerList.item(0)));
			profile.setBody(unmarshallStoreDSBody((Element) bodyList.item(0)));
			
			return profile;
		} catch (SAXException e) {
			log.error("Exception occured when getting document element!", e);
			return null;
		} catch (IOException e) {
			log.error("Exception occured when getting document element!", e);
			return null;
		}
	}

	/**
	 * Unmarshall store ds body.
	 * 
	 * @param bodyElement the body element
	 * 
	 * @return the store body
	 */
	private static Body unmarshallStoreDSBody(Element bodyElement) {
		
		if (bodyElement == null)
			return null;
		
		SdoProfileBody profileBody = new SdoProfileBody();
		profileBody.setConfiguration(
			unmarshallStoreDSConfiguration(Marshaller.getSingleElement(
				bodyElement, "CONFIGURATION")));
		
		profileBody.setStatus(unmarshallStoreDSStatus(Marshaller.getSingleElement(
				bodyElement, "STATUS")));
		
		return profileBody;
	}

	/**
	 * Unmarshall sdo configuration.
	 * 
	 * @param element the element
	 * 
	 * @return the store configuration
	 */
	private static SdoProfileConfiguration unmarshallStoreDSConfiguration(
			Element element) {
		
		if (element == null)
			return null;
		
		SdoProfileConfiguration configuration = new SdoProfileConfiguration();
		
		Element sdoMimeType = 
			Marshaller.getSingleElement(element, "SDO_MIME_TYPE");
		if (sdoMimeType != null)
			configuration.setSdoMimeType(
					Marshaller.getElementContent(sdoMimeType));

		return configuration;
	}


	/**
	 * Unmarshall sdo status.
	 * 
	 * @param element the element
	 * 
	 * @return the store status
	 */
	private static SdoProfileStatus unmarshallStoreDSStatus(Element element) {
		if (element == null)
			return null;
		
		SdoProfileStatus status = new SdoProfileStatus();
		
		Element lastModificationDate = Marshaller.getSingleElement(element,
				"LAST_MODIFICATION_DATE");
		if (lastModificationDate != null)
			status.setLastModiifcationDate(
					Marshaller.getElementContent(lastModificationDate));
		
		Element sdoSize = Marshaller.getSingleElement(element,
				"SDO_SIZE");
		if (sdoSize != null)
			status.setSdoSize(Long.valueOf(
					Marshaller.getElementContent(sdoSize)));
		
		Element sdoVersion = Marshaller.getSingleElement(element,
				"SDO_VERSION");
		if (sdoVersion != null) {
			status.setSdoVersion(
					Marshaller.getElementContent(sdoVersion));
		} 
		
		Element sdoUri = Marshaller.getSingleElement(element,
				"SDO_URI");
		if (sdoUri != null) {
			status.setSdoUri(
					Marshaller.getElementContent(sdoUri));
		} 
	
		Element sdo = Marshaller.getSingleElement(element,
				"SDO");
		if (sdo != null) {
			status.setSdo(
					Marshaller.getElementContent(sdo));
		} 

		
		return status;
	}
}
