// MobyPrimaryDataSet.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.NodeList;

/**
 * A container representing a way how a named collection of various
 * primary data types is used in a service.
 *
 *<p>
 * @author <A HREF="mailto:senger@ebi.ac.uk">Martin Senger</A>
 * @version $Id: MobyPrimaryDataSet.java,v 1.10 2008/01/07 22:11:36 gordonp Exp $
 */

public class MobyPrimaryDataSet
    extends MobyPrimaryData implements Cloneable{

    protected Vector<MobyPrimaryDataSimple> elements =
	new Vector<MobyPrimaryDataSimple>();
    protected MobyDataType defaultDataType = new MobyDataType("Object");

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

    /**************************************************************************
     * Construct this instance from a piece of XML.
     * The XML looks like this:
     *
     *   <Collection articleName="NameOfArticle">
     *	    <Simple>......</Simple>
     *	    <Simple>......</Simple>
     *	 </Collection>
     *
     *************************************************************************/
    public MobyPrimaryDataSet (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 ("Simple")) {
		addElement (new MobyPrimaryDataSimple ((Element)children.item (i)));
	    }
	}
    }

    public MobyPrimaryDataSet clone(){
	MobyPrimaryDataSet clone = new MobyPrimaryDataSet(getName());
	clone.setDataType(getDataType());
	clone.setElements(getElements());  // also sets namespaces implicitly
	return clone;
    }

    public MobyPrimaryDataSimple[] getElements() {
	MobyPrimaryDataSimple[] result = new MobyPrimaryDataSimple [elements.size()];
	elements.copyInto (result);
	return result;
    }
    public void setElements (MobyPrimaryDataSimple[] value) {
	if (value == null) {
	    elements.clear();
	} else {
	    for (int i = 0; i < value.length; i++)
		elements.addElement (value[i]);
	}
    }
    public void addElement (MobyPrimaryDataSimple value) {
	elements.addElement (value);
    }

    /**************************************************************************
     * Return a data type of the first element of this collection
     * (according the Biomoby API, however, all elements should have
     * the same data type).
     *************************************************************************/
    public MobyDataType getDataType() {
	synchronized (elements) {
	    if (elements.size() > 0)
		return ((MobyPrimaryDataSimple)elements.firstElement()).getDataType();
	    else
		return defaultDataType;
	}
    }

    /**************************************************************************
     * Set given data type to all elements of this collection
     * (according the Biomoby API all elements should have the same
     * data type).
     *************************************************************************/
    public void setDataType (MobyDataType dataType) {
	defaultDataType = dataType;
	synchronized (elements) {
	    for (Enumeration en = elements.elements(); en.hasMoreElements(); )
		((MobyPrimaryDataSimple)en.nextElement()).setDataType (dataType);
	}
    }

    /**************************************************************************
     * Return namespaces of the first element of this collection.
     *************************************************************************/
    public MobyNamespace[] getNamespaces() {
	synchronized (elements) {
	    if (elements.size() > 0)
		return ((MobyPrimaryDataSimple)elements.firstElement()).getNamespaces();
	    else
		return new MobyNamespace[] {};
	}
    }

    /**************************************************************************
     * Set given namespaces of all elements of this collection.
     *************************************************************************/
    public void setNamespaces (MobyNamespace[] value) {
	synchronized (elements) {
	    for (Enumeration en = elements.elements(); en.hasMoreElements(); )
		((MobyPrimaryDataSimple)en.nextElement()).setNamespaces (value);
	}
    }

    /**************************************************************************
     * Add given namespace of all elements of this collection.
     *************************************************************************/
    public void addNamespace (MobyNamespace value) {
	synchronized (elements) {
	    for (Enumeration en = elements.elements(); en.hasMoreElements(); )
		((MobyPrimaryDataSimple)en.nextElement()).addNamespace (value);
	}
    }

    /**************************************************************************
     * Remove given namespace (defined by its name) from all elements
     * of this collection.
     *************************************************************************/
    public void removeNamespace (String namespaceName) {
	synchronized (elements) {
	    for (Enumeration en = elements.elements(); en.hasMoreElements(); )
		((MobyPrimaryDataSimple)en.nextElement()).removeNamespace (namespaceName);
	}
    }

    /**************************************************************************
     * Remove given namespace from all elements of this collection.
     *************************************************************************/
    public void removeNamespace (MobyNamespace value) {
	synchronized (elements) {
	    for (Enumeration en = elements.elements(); en.hasMoreElements(); )
		((MobyPrimaryDataSimple)en.nextElement()).removeNamespace (value);
	}
    }

    /**************************************************************************
     * Convert this instance to the XML.
     * The XML will look like this:
     *
     *    <Collection articleName="NameOfArticle">
     *      <Simple>......</Simple> <!-- Simple parameter type structure -->
     *      <Simple>......</Simple>
     *    </Collection>
     *
     *************************************************************************/
    public String toXML() {
	StringBuffer buf = new StringBuffer();
	buf.append ("<Collection articleName=\"");
	buf.append (name);
	buf.append ("\">\n");
	if (elements.size() > 0) {
	    for (Enumeration en = elements.elements(); en.hasMoreElements(); )
		buf.append (((MobyPrimaryDataSimple)en.nextElement()).toXML());
	}
	else{
	    MobyPrimaryDataSimple template = new MobyPrimaryDataSimple();
	    template.setDataType(defaultDataType);
	    buf.append(template.toXML());
	}
	buf.append ("</Collection>");
	buf.append ("\n");
	return new String (buf);
    }

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

    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");
	buf.append ("Elements in collection:\n");
	for (Enumeration en = elements.elements(); en.hasMoreElements(); ) {
	    buf.append (((MobyPrimaryDataSimple)en.nextElement()).format (1));
	}
	buf.append ("\n");
	return new String (buf);
    }

}
