package edu.uga.cs.lsdis.meteors.wadls;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

import javax.wadls.Application;
import javax.wadls.ModelReference;
import javax.wadls.WADLSException;

/**
 * This class represents a ModelReference.
 * 
 * @author Zixin Wu (wuzixin@uga.edu)
 *
 */
public class ModelReferenceImpl implements ModelReference {

	/**
	 * The URI of the ontology used in the model reference
	 */
	protected URI namespace;
	
	/**
	 * The parent WSDL-S element of this model reference
	 */
	protected Object parent;
	
	/**
	 * The NS Prefix of the model reference
	 */
	protected String prefix;
	
	/**
	 * The ontology concept of this model reference
	 */
	protected String concept;
	
	/**
	 * Get the concept of this modelReference.
	 * @return The concept of this modelReference.
	 */
	public String getConcept(){
		return this.concept;
	}

	/**
	 * Set the concept of this modelReference
	 * @param concept The desired concept of this modelReference
	 */
	public void setConcept(String concept){
		this.concept = concept;
	}

	/**
	 * Get the prefix of this modelReference
	 * @return The prefix  of this modelReference
	 */
	public String getPrefix(){
		return this.prefix;
	}

	/**
	 * Set the prefix of the ontology used in this modelReference
	 * @param prefix The desired prefix of the ontology used in this modelReference
	 */
	public void setPrefix(String prefix){
		this.prefix = prefix;
	}

	/**
	 * Get the namespace of the ontology used in this modelReference
	 * @return The namespace of the ontology used in this modelReference
	 */
	public URI getNamespace(){
		return this.namespace;
	}

	/**
	 * Set the namespace of the ontology used in this modelReference
	 * @param nameSpace The desired namespace of the ontology used in this modelReference
	 */
	public void setNamespace(String nameSpace)
			throws URISyntaxException{
		//System.out.println("namespace is "+nameSpace);
		this.namespace = new URI(nameSpace);
	}

	/**
	 * Get the parent object of this modelReference
	 * @return The parent object of this modelReference
	 */
	public Object getParent(){
		return this.parent;
	}

	/**
	 * Set the parent object of this modelReference
	 * @param parent The desired parent object of this modelReference
	 */
	public void setParent(Object parent){
		this.parent = parent;
	}

	/**
	 * Return a formatted string representing this modelReference.
	 * @return A formatted string representing this modelReference.
	 */
	public String value(){
		if (this.concept == null || this.namespace == null)
			return null;
		return (this.namespace + "#" + this.concept);
	}
	
	public String toString(){
		if (this.concept == null)
			return null;
		if (this.prefix != null){		//use the prefix
			return (this.prefix + "#" + this.concept);
		}
		else if (this.namespace != null){		//use the namespace
			return (this.namespace + "#" + this.concept);
		}
		else
			return null;
	}
	
	public static List<ModelReference> getModelReferences(String mrefs, Application app) throws URISyntaxException, WADLSException {
		String[] refs = mrefs.split(" ");
		List<ModelReference> list = new ArrayList<ModelReference>(refs.length);
		for(String ref : refs) {
			ModelReference mr = app.createModelReference();
			mr.valueOf(ref, app);
			list.add(mr);
		}
		return list;
	}
	
	public void valueOf(String modelReferenceAsString, Application app) throws URISyntaxException, WADLSException{
		int    index        = modelReferenceAsString.indexOf('#');
		String prefix       = (index != -1)
									? modelReferenceAsString.substring(0, index)
									: null;
		String namespaceURI = prefix;
		String localPart    = null;

		//System.out.println("Namespace URI:"+namespaceURI);
		//assume the user give prefix#localName
		if (prefix != null){
			//try to find a namespaceURI for that prefix
			String tmpNamespaceURI = app.getNamespace(prefix);
			//System.out.println("Temp Namespace URI:"+tmpNamespaceURI);
			if(tmpNamespaceURI != null) {	//the user did give prefix
				namespaceURI = tmpNamespaceURI.substring(0, tmpNamespaceURI.length());
			}
			else{							//the user gave namespaceURI instead of prefix
				//try to find a prefix for that namespaceURI
				prefix = app.getPrefix(namespaceURI);
				if (prefix == null)
					prefix = app.getPrefix(namespaceURI+"#");
			}
			localPart = modelReferenceAsString.substring(index + 1);
		}
		else if (!prefix.equals("")){		//no prefix or namespaceURI is given, but '#' is included
			//use target namespace
			namespaceURI = app.getTargetNamespace();
			prefix = app.getPrefix(namespaceURI);
			localPart = modelReferenceAsString.substring(1);
		}
		else{
            throw new IllegalArgumentException(
		                "No Namespace URI is provided for this modelReference: " +
		                modelReferenceAsString
		                + ".");
		}

		if (namespaceURI != null){
			System.out.println("namespaceURI is "+namespaceURI);
			this.setNamespace(namespaceURI);
		    //System.out.println("Concept:"+localPart);
			this.setConcept(localPart);
			this.setPrefix(prefix);
		}
		else{
			String faultCode = (prefix == null)
			  ? WADLSException.NO_PREFIX_SPECIFIED
			  : WADLSException.UNBOUND_PREFIX;

			WADLSException wadlExc = new WADLSException(faultCode,
		                         "Unable to determine " +
		                         "namespace of '" +
		                         modelReferenceAsString + "'.");

			throw wadlExc;
		}
	}

    /**
     * Equals method  overriden to compare two modelreferences.
     * We campare the namespace and the concept name (literally)
     * @param obj
     */
    public boolean equals(Object obj) {
        if (!(obj instanceof ModelReference)){
            return false;
        }else{
            ModelReference ref = (ModelReference)obj;
            return (concept.equals(ref.getConcept()) &&
                    namespace.equals(ref.getNamespace()));
        }
    }
    
    public int hashCode(){
    	return this.value().hashCode();
    }
}
