package org.biomoby.shared.extended;

import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;

import org.biomoby.client.rdf.vocabulary.DC_PROTEGE;
import org.biomoby.shared.MobyException;
import org.biomoby.shared.MobyNamespace;
import org.biomoby.shared.Utils;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.RDFReader;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.RDFS;


/**
 * 
 * @author Eddie created Oct 18, 2005
 * This class parses the RDF document that describes the namespace ontology.<p>
 * An example of how to use this class is below:
 * <pre><code>
 *       NamespaceParser p = new NamespaceParser("http://biomoby.org/RESOURCES/MOBY-S/Namespaces");
 *		MobyNamespace[] namespaces = p.getMobyNamespacesFromRDF();
 *		for (int i = 0; i < namespaces.length; i++) {
 *			System.out.println(namespaces[i]);
 *		}
 *  </code></pre><p>
 *  This would output the following: the name and description for each namespace in the document
 */
public class NamespaceParser {

	private URL url = null;
        private InputStream ins = null;

	/**
	 * Default constructor - need to set the URL for the RDF document that
	 * describes the Namespace ontology using setURL(String url) or setURL(URL
	 * url)
	 * 
	 */
	public NamespaceParser() {
	}

	/**
	 * Parameterized Constructor that takes in a string argument that is the url
	 * for the RDF document that describes the Namespace ontology.
	 * 
	 * @param url
	 *            a string representation for the URL that resolves to the RDF
	 *            document that describes the Namespace ontology
	 * @throws MobyException
	 *             thrown if the url is malformed
	 */
	public NamespaceParser(String url) throws MobyException {
		try {
			this.url = new URL(url);
		} catch (MalformedURLException e) {
			this.url = null;
			throw new MobyException("Invalid url specified by " + url + ".\n"
					+ e.getLocalizedMessage());
		}
	}

	/**
	 * Parameterized Constructor that takes in a url for the RDF document that
	 * describes the Namespace ontology.
	 * 
	 * @param url
	 *            the URL that resolves to the RDF document that describes the
	 *            Namespace ontology
	 * @throws MobyException
	 *             thrown if the url is malformed
	 */
	public NamespaceParser(URL url) throws MobyException {
		if (url != null)
			this.url = url;
		else {
			this.url = null;
			throw new MobyException("Invalid url specified by "
					+ url.toExternalForm() + ".");
		}
	}

	/**
	 * 
	 * @param url
	 *            the URL that resolves to the RDF document that describes the
	 *            Namespace ontology
	 * @throws MobyException
	 *             thrown if the url is malformed
	 */
	public void setUrl(URL url) throws MobyException {
		if (url != null)
			this.url = url;
		else {
			this.url = null;
			throw new MobyException("Invalid url specified by "
					+ url.toExternalForm() + ".");
		}
	}

	/**
	 * 
	 * @param url
	 *            the string representation of the URL that resolves to the RDF
	 *            document that describes the Namespace ontology
	 * @throws MobyException
	 *             thrown if the url is malformed
	 */
	public void setUrl(String url) throws MobyException {
		try {
			this.url = new URL(url);
		} catch (MalformedURLException e) {
			this.url = null;
			throw new MobyException("Invalid url specified by " + url + ".\n"
					+ e.getLocalizedMessage());
		}
	}

	/**
	 * 
	 * @return the url used to retrieve the RDF document that describes the
	 *         Namespace ontology.
	 */
	public URL getUrl() {
		return url;
	}

        /**
	 * If not null, overrides the URL when reading the definitions (e.g. if you have the RDF as a String, not a URL use this).
         */
        public void setInputStream(InputStream is){
	    ins = is;
	}

        public InputStream getInputStream(){
	    return ins;
        }

	/**
	 * 
	 * @return an array of MobyNamespace objects created by parsing the RDF
	 *         document
	 * @throws MobyException
	 *             thrown if the location of the RDF document describing the
	 *             Namsepace ontology is invalid
	 */
	public MobyNamespace[] getMobyNamespacesFromRDF() throws MobyException {
	        InputStream is = null;
	        if(ins != null){
		    is = ins;
	        }
	        // if url is invalid let client know
	        else{
		    if (this.url == null){
		        throw new MobyException(
		  			        "Invalid url specified for the location of the "
						+ "RDF document that describes the Namespace ontology: "
					        + this.url);
		    }
		    is = Utils.getInputStream(getUrl());
	        }

		// lets start parsing
		ArrayList<MobyNamespace> list = new ArrayList<MobyNamespace>();
		// create the model
		Model model = ModelFactory.createDefaultModel();
		RDFReader reader = model.getReader();
		reader.read(model, is, null);
		// get all subjects in the document
		ResIterator iterator = model.listSubjects();
		while (iterator.hasNext()) {
			Resource resource = iterator.nextResource();

			if (resource.getURI().equals(RDFS.comment.getURI()) || resource.getURI().equals(RDFS.label.getURI()))
				continue;
			// extract the name of the namespace
			String uri = resource.getURI();
			String name = "";
			if (uri.indexOf("#") > 0)
				name = uri.substring(uri.indexOf("#")+1);
			else if(uri.lastIndexOf("/Namespaces/") > 0) {
			    name = uri.substring(uri.lastIndexOf("/Namespaces/")+"/Namespaces/".length());
			}
			
			MobyNamespace namespace = new MobyNamespace(name);
			if (resource.hasProperty(DC_PROTEGE.identifier)) {
				RDFNode lsidNode = resource.getProperty(DC_PROTEGE.identifier).getObject();
				if (lsidNode != null)
					namespace.setLSID(lsidNode.toString());
			}
			
			
			// extract the comment (a literal in the document)
			String description = resource.getProperty(RDFS.comment).getLiteral().getString();
			namespace.setDescription(description);
			if (resource.hasProperty(DC_PROTEGE.creator)) {
				namespace.setEmailContact(resource.getProperty(DC_PROTEGE.creator).getObject().toString());
			}
			if (resource.hasProperty(DC_PROTEGE.publisher)) {
				namespace.setAuthority(resource.getProperty(DC_PROTEGE.publisher).getObject().toString());
			}
			list.add(namespace);
		}

		// return the array
		return (MobyNamespace[]) list.toArray(new MobyNamespace[list.size()]);
	}
	
	public static void main(String[] args) throws MobyException {
		// show how to use this class
		NamespaceParser p = new NamespaceParser("http://biomoby.org/RESOURCES/MOBY-S/Namespaces");
		MobyNamespace[] namespaces = p.getMobyNamespacesFromRDF();
		for (int i = 0; i < namespaces.length; i++) {
			System.out.println(namespaces[i]);
		}
	}
}
