
package org.biomoby.shared.data;

import java.util.*;

import org.biomoby.registry.meta.Registry;
import org.biomoby.shared.Central;
import org.biomoby.shared.MobyDataType;
import org.biomoby.shared.MobyException;
import org.biomoby.shared.MobyNamespace;
import org.biomoby.shared.MobyPrefixResolver;
import org.biomoby.shared.MobyRelationship;

/**
 * This class is primarily intended for use by MobyDataComposite to represent
 * Object members in the HAS (1-to-many) relationship. Not all MobyDataObject
 * behaviours are well defined for this object, but should rather be called on its members.
 * If you are looking to represent a MOBY XML Collection please see MobyDataObjectSet.
 */

public class MobyDataObjectVector extends MobyDataObject implements List<MobyDataObject>{
    private Vector<MobyDataObject> members;

    /**
     * Builds a vector with an initial capacity of 5.
     */
    public MobyDataObjectVector(String name){
	this(name, null);
    }

    public MobyDataObjectVector(String name, Registry registry){
	this(name, 5, registry);
    }

    public MobyDataObjectVector(String name, int initialCapacity){
      this(name, initialCapacity, null);
    }

    public MobyDataObjectVector(String name, int initialCapacity, Registry registry){
	super(name, registry);
	members = new Vector<MobyDataObject>(initialCapacity);
    }

    // TODO: deal with cloning, CRIB and PIB setting

    public String toXML(){
	StringBuffer concatXML = new StringBuffer();
	Iterator<MobyDataObject> iter = members.iterator();
	while(iter.hasNext()){
	    MobyDataObject mdsi = iter.next();
	    if(!getName().equals(mdsi.getName())){
		mdsi.setName(getName());
	    }

	    int oldXmlMode = mdsi.getXmlMode();
	    if(oldXmlMode != xmlMode){
		mdsi.setXmlMode(xmlMode);
	    }
	    concatXML.append(mdsi.toXML()+"\n");
	    if(oldXmlMode != xmlMode){
		mdsi.setXmlMode(oldXmlMode);
	    }
	}
	return concatXML.toString();
    }

    /**
     * Add an object to the list.  If the object is another MobyDataObjectVector, the 
     * list is flattened first, as MOBY XML does not allow nested lists (equivalent to calling addAll).
     */
    public boolean add(MobyDataObject mdo){
	if(mdo instanceof MobyDataObjectVector){
	    return addAll((MobyDataObjectVector) mdo);
	}
	else{
	    return members.add(mdo);
	}
    }

    /**
     * Inserts the specified element at the specified position in this list.
     * If the object is another MobyDataObjectVector, the 
     * list is flattened first, as MOBY XML does not allow nested lists (equivalent to calling addAll).
     */
    public void add(int index, MobyDataObject mdo){
	if(mdo instanceof MobyDataObjectVector){
	    addAll(index, (MobyDataObjectVector) mdo);
	}
	else{
	    members.add(index, mdo);
	}
    }

    /**
     * Appends all of the elements in the specified collection to the end of this list,
     * in the order that they are returned by the specified collection's iterator.
     * Usually the argument would be a MobyDataObjectSet, or another MobyDataObjectVector.
     */
    public boolean addAll(Collection<? extends MobyDataObject> c){
	return members.addAll(c);
    }

    /**
     * Inserts all of the elements in the specified collection into 
     * this list at the specified position.  Usually the argument would be a 
     * MobyDataObjectSet, or another MobyDataObjectVector.
     */
    public boolean addAll(int index, Collection<? extends MobyDataObject> c){
	return members.addAll(index, c);
    }

    /**
     * Removes all of the elements from this list.
     */
    public void clear(){
	members.clear();
    }

    /**
     * Returns true if this list contains the specified element.
     */
    public boolean contains(Object o){
	return members.contains(o);
    }

    /**
     * Returns true if this list contains all of the elements of the specified collection.
     */
    public boolean containsAll(Collection c){
	return members.containsAll(c);
    }

    /**
     * Compares the specified object with this list for equality.
     */
    public boolean equals(Object o){
	return members.equals(o);
    }

    /**
     * Returns the element at the specified position in this list.
     */
    public MobyDataObject get(int index){
	return members.get(index);
    }

    /**
     * Returns the hash code value for this list.
     */
    public int hashCode(){
	return members.hashCode();
    }

    /**
     * Returns the index in this list of the first occurrence of the 
     * specified element, or -1 if this list does not contain this element.
     */
    public int indexOf(Object o){
	return members.indexOf(o);
    }
         
    public boolean isEmpty(){
	return members.isEmpty();
    }

    /**
     * Returns an iterator over the elements in this list in proper sequence.
     */
    public Iterator<MobyDataObject> iterator(){
	return members.iterator();
    }

    /**
     * Returns the index in this list of the last occurrence of the specified 
     * element, or -1 if this list does not contain this element.
     */
    public int lastIndexOf(Object o){
	return members.lastIndexOf(o);
    }

    /**
     * Returns a list iterator of the elements in this list (in proper sequence).
     */
    public ListIterator<MobyDataObject> listIterator(){
	return members.listIterator();
    }

    /**
     * Returns a list iterator of the elements in this list (in proper sequence), 
     * starting at the specified position in this list.
     */
    public ListIterator<MobyDataObject> listIterator(int index){
	return members.listIterator(index);
    }

    /**
     * Removes the element at the specified position in this list (optional operation). 
     */
    public MobyDataObject remove(int index){
	return members.remove(index);
    }
        
    /**
     * Removes the first occurrence in this list of the specified element.
     */
    public boolean remove(Object o){
	return members.remove(o);
    }

    /**
     * Removes from this list all the elements that are contained in the specified collection.
     */
    public boolean removeAll(Collection c){
	return members.removeAll(c);
    }

    /**
     * Retains only the elements in this list that are contained in the specified collection (optional operation).
     */
    public boolean retainAll(Collection c){
	return members.retainAll(c);
    }

    /**
     * Replaces the element at the specified position in this list with the specified element (optional operation).
     * If the element to be set is another MobyDataObjectVector, the list is flatten first because
     * MOBY XML does not support nested lists.
     */
    public MobyDataObject set(int index, MobyDataObject element){
	if(element instanceof MobyDataObjectVector){
	    MobyDataObject removedObject = remove(index);
	    addAll(index, (MobyDataObjectVector) element);
	    return removedObject;
	}
	else{	    
	    return members.set(index, element);
	}
    }

    /**
     * Returns the number of elements in this list.
     */
    public int size(){
	return members.size();
    }

    /**
     * Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive.
     */
    public List<MobyDataObject> subList(int fromIndex, int toIndex){
	return members.subList(fromIndex, toIndex);
    }

    /**
     * Returns an array containing all of the elements in this list in proper sequence.
     */
    public Object[] toArray(){
	return members.toArray();
    }

    public <T> T[] toArray(T[] a) throws ClassCastException{
	return members.toArray(a);
    }
}
