// MobyPrimaryDataSimple.java
//
//    senger@ebi.ac.uk
//    May 2003
//

package org.biomoby.shared;

import java.util.Enumeration;
import java.util.Vector;

import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * A container representing a way how various primary data types
 * are used in a service. It points to a MobyDataType where the
 * real data type is stored, and to a MobyNamespace where the
 * namespace is stored.
 *
 *<p>
 * @author <A HREF="mailto:senger@ebi.ac.uk">Martin Senger</A>
 * @version $Id: MobyPrimaryDataSimple.java,v 1.12 2008/01/07 22:11:36 gordonp Exp $
 */

public class MobyPrimaryDataSimple
    extends MobyPrimaryData implements Cloneable{

    protected Vector<MobyNamespace> namespaces = new Vector<MobyNamespace>();
    protected MobyDataType dataType;

    /**************************************************************************
     * Default constructor.
     *************************************************************************/
    public MobyPrimaryDataSimple() {
	super();
    }

    /**************************************************************************
     * Normal constructor. Other characteristics are empty - which is usually
     * wrong - therefore use 'set' method to fill them.
     *************************************************************************/
    public MobyPrimaryDataSimple (String name) {
	super (name);
    }

    /**************************************************************************
     * Construct this instance from a piece of XML.
     * The XML looks like this:
     *
     *   <Simple articleName="NameOfArticle">
     *      <objectType>ObjectOntologyTerm</objectType>
     *      <Namespace>NamespaceTerm</Namespace>
     *      <Namespace>...</Namespace><!-- one or more... -->
     *   </Simple>
     *
     *************************************************************************/
    public MobyPrimaryDataSimple (Element elem) {
	super (elem.getAttribute ("articleName"));
	NodeList children = elem.getChildNodes();
	for (int i = 0; i < children.getLength(); i++) {
	    String childName = children.item (i).getNodeName();
	    if (childName.equals ("objectType")) {
		if (children.item (i).getFirstChild() != null) {
			MobyDataType mdt = new MobyDataType (children.item (i).getFirstChild().getNodeValue());
			NamedNodeMap map = (children.item (i).getAttributes());
			if (map != null) {
				Node node = map.getNamedItemNS(children.item(i).getNamespaceURI(),"lsid");
				if (node != null)
					mdt.setLSID(node.getNodeValue());
			}
			setDataType (mdt);
		}
	    } else if (childName.equals ("Namespace")) {
		if (children.item (i).getFirstChild() != null) {
			MobyNamespace namespace = new MobyNamespace (children.item(i).getFirstChild().getNodeValue());
			NamedNodeMap map = (children.item (i).getAttributes());
			if (map != null) {
				Node node = map.getNamedItemNS(children.item(i).getNamespaceURI(),"lsid");
				if (node != null)
					namespace.setLSID(node.getNodeValue());
			}
			addNamespace (namespace);
		}
	    }
	}
    }

    public MobyPrimaryDataSimple clone(){
	MobyPrimaryDataSimple clone = new MobyPrimaryDataSimple(name);
	clone.setId(getId());
	clone.namespaces = new Vector<MobyNamespace>(namespaces);
	clone.dataType = dataType;
	return clone;
    }

    /**************************************************************************
     *
     *************************************************************************/
    public MobyDataType getDataType() {
	return dataType;
    }

    /**************************************************************************
     *
     *************************************************************************/
    public void setDataType (MobyDataType value) {
	dataType = value;
    }

    /**************************************************************************
     * Return all namespaces defined in this data container.
     *************************************************************************/
    public MobyNamespace[] getNamespaces() {
        synchronized(namespaces){
	    MobyNamespace[] result = new MobyNamespace [namespaces.size()];
	    namespaces.copyInto (result);
	    return result;
        }
    }

    /**************************************************************************
     * Replace all existing namespaces (if any) by a new array of
     * namespaces. Do not accept duplicates (same names).
     *************************************************************************/
    public void setNamespaces (MobyNamespace[] value) {
        synchronized(namespaces){
	    if (value == null) {
    	        namespaces.clear();
    	    } else {
	        for (int i = 0; i < value.length; i++)
		    addNamespace (value[i]);
	    }
        }
    }

    /**************************************************************************
     * Add one namespace to already existing ones (but only if a
     * namespace of the same name does not exist yet).
     *************************************************************************/
    public void addNamespace (MobyNamespace value) {
	synchronized (namespaces) {
	    if (! namespaces.contains (value)){
		// GET RID OF ANY BLANK NAMESPACE IF WE'VE GOT A REAL ONE
		if(namespaces.size() == 1 &&
		   namespaces.elementAt(0).getName().length() == 0){
		    namespaces.remove(0);
		}
		namespaces.addElement (value);
	    }
	}
    }

    /**************************************************************************
     * Remove namespace given by its name.
     *************************************************************************/
    public void removeNamespace (String namespaceName) {
	removeNamespace (new MobyNamespace (namespaceName));
    }

    /**************************************************************************
     * Remove given namespace.
     *************************************************************************/
    public void removeNamespace (MobyNamespace value) {
	synchronized (namespaces) {
	    int index = namespaces.indexOf (value);
	    if (index > -1)
		namespaces.remove (index);
	}
    }

    /**************************************************************************
     * Convert this instance into XML.
     * The XML will look like this:
     *
     *      <Simple articleName="NameOfArticle">
     *        <objectType>ObjectOntologyTerm</objectType>
     *        <Namespace>NamespaceTerm</Namespace>
     *        <Namespace>...</Namespace><!-- one or more... -->
     *      </Simple>
     *************************************************************************/
    public String toXML() {
	StringBuffer buf = new StringBuffer();
	buf.append ("<Simple articleName=\"");
	buf.append (name);
	buf.append ("\">\n");
	buf.append ("<objectType>");
	if (dataType != null) buf.append (dataType.getName());
	buf.append ("</objectType>\n");
	if (namespaces.size() > 0) {
	    for (Enumeration en = namespaces.elements(); en.hasMoreElements(); ) {
                MobyNamespace ns = (MobyNamespace)en.nextElement();
 		if(ns != null){
 		    buf.append ("<Namespace>");
 		    buf.append ( ns.getName() );
 		    buf.append ("</Namespace>");
 		}
	    }
	}
	buf.append ("</Simple>");
	buf.append ("\n");
	return new String (buf);
    }

    public String toString() {
	StringBuffer buf = new StringBuffer();
	if (name != null && name.length() != 0)
	    buf.append ("Name:    " + name + "\n");
	if (id != null) buf.append ("ID:      " + id + "\n");
	if (dataType != null)
	    buf.append ("Data Type:\n" + dataType.format (1));
	if (namespaces.size() > 0) {
	    buf.append ("Namespaces:\n");
	    for (Enumeration en = namespaces.elements(); en.hasMoreElements(); ) {
		buf.append (((MobyNamespace)en.nextElement()).format (1));
		buf.append ("\n");
	    }
	}
	return new String (buf);
    }

    public String format (int indent) {
	return Utils.format (this, indent);
    }

}
