/*
 * This file is part of the Vamsas Client version 0.2. 
 * Copyright 2010 by Jim Procter, Iain Milne, Pierre Marguerite, 
 *  Andrew Waterhouse and Dominik Lindner.
 * 
 * Earlier versions have also been incorporated into Jalview version 2.4 
 * since 2008, and TOPALi version 2 since 2007.
 * 
 * The Vamsas Client is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *  
 * The Vamsas Client is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with the Vamsas Client.  If not, see <http://www.gnu.org/licenses/>.
 */
package uk.ac.vamsas.objects.core;

/**
 * Specify an ordered set of positions and/or regions on the principle dimension
 * of some associated vamsas object Keeping to jaxb-1.0 specification for the
 * moment - this choice should become a substitution group when we use jaxb-2.0
 * capable bindings
 * 
 * 
 * @version $Revision$ $Date$
 */
public abstract class RangeType extends uk.ac.vamsas.client.Vobject implements
    java.io.Serializable {

  // --------------------------/
  // - Class/Member Variables -/
  // --------------------------/

  /**
   * Internal choice value storage
   */
  private java.lang.Object _choiceValue;

  /**
   * a position within the associated object's coordinate system
   * 
   */
  private java.util.Vector _posList;

  /**
   * a region from start to end, with flag for inclusivity of terminii
   */
  private java.util.Vector _segList;

  // ----------------/
  // - Constructors -/
  // ----------------/

  public RangeType() {
    super();
    this._posList = new java.util.Vector();
    this._segList = new java.util.Vector();
  }

  // -----------/
  // - Methods -/
  // -----------/

  /**
   * 
   * 
   * @param vPos
   * @throws java.lang.IndexOutOfBoundsException
   *           if the index given is outside the bounds of the collection
   */
  public void addPos(final uk.ac.vamsas.objects.core.Pos vPos)
      throws java.lang.IndexOutOfBoundsException {
    this._posList.addElement(vPos);
  }

  /**
   * 
   * 
   * @param index
   * @param vPos
   * @throws java.lang.IndexOutOfBoundsException
   *           if the index given is outside the bounds of the collection
   */
  public void addPos(final int index, final uk.ac.vamsas.objects.core.Pos vPos)
      throws java.lang.IndexOutOfBoundsException {
    this._posList.add(index, vPos);
  }

  /**
   * 
   * 
   * @param vSeg
   * @throws java.lang.IndexOutOfBoundsException
   *           if the index given is outside the bounds of the collection
   */
  public void addSeg(final uk.ac.vamsas.objects.core.Seg vSeg)
      throws java.lang.IndexOutOfBoundsException {
    this._segList.addElement(vSeg);
  }

  /**
   * 
   * 
   * @param index
   * @param vSeg
   * @throws java.lang.IndexOutOfBoundsException
   *           if the index given is outside the bounds of the collection
   */
  public void addSeg(final int index, final uk.ac.vamsas.objects.core.Seg vSeg)
      throws java.lang.IndexOutOfBoundsException {
    this._segList.add(index, vSeg);
  }

  /**
   * Method enumeratePos.
   * 
   * @return an Enumeration over all uk.ac.vamsas.objects.core.Pos elements
   */
  public java.util.Enumeration enumeratePos() {
    return this._posList.elements();
  }

  /**
   * Method enumerateSeg.
   * 
   * @return an Enumeration over all uk.ac.vamsas.objects.core.Seg elements
   */
  public java.util.Enumeration enumerateSeg() {
    return this._segList.elements();
  }

  /**
   * Overrides the java.lang.Object.equals method.
   * 
   * @param obj
   * @return true if the objects are equal.
   */
  public boolean equals(final java.lang.Object obj) {
    if (this == obj)
      return true;

    if (super.equals(obj) == false)
      return false;

    if (obj instanceof RangeType) {

      RangeType temp = (RangeType) obj;
      boolean thcycle;
      boolean tmcycle;
      if (this._choiceValue != null) {
        if (temp._choiceValue == null)
          return false;
        if (this._choiceValue != temp._choiceValue) {
          thcycle = org.castor.util.CycleBreaker
              .startingToCycle(this._choiceValue);
          tmcycle = org.castor.util.CycleBreaker
              .startingToCycle(temp._choiceValue);
          if (thcycle != tmcycle) {
            if (!thcycle) {
              org.castor.util.CycleBreaker
                  .releaseCycleHandle(this._choiceValue);
            }
            ;
            if (!tmcycle) {
              org.castor.util.CycleBreaker
                  .releaseCycleHandle(temp._choiceValue);
            }
            ;
            return false;
          }
          if (!thcycle) {
            if (!this._choiceValue.equals(temp._choiceValue)) {
              org.castor.util.CycleBreaker
                  .releaseCycleHandle(this._choiceValue);
              org.castor.util.CycleBreaker
                  .releaseCycleHandle(temp._choiceValue);
              return false;
            }
            org.castor.util.CycleBreaker.releaseCycleHandle(this._choiceValue);
            org.castor.util.CycleBreaker.releaseCycleHandle(temp._choiceValue);
          }
        }
      } else if (temp._choiceValue != null)
        return false;
      if (this._posList != null) {
        if (temp._posList == null)
          return false;
        if (this._posList != temp._posList) {
          thcycle = org.castor.util.CycleBreaker.startingToCycle(this._posList);
          tmcycle = org.castor.util.CycleBreaker.startingToCycle(temp._posList);
          if (thcycle != tmcycle) {
            if (!thcycle) {
              org.castor.util.CycleBreaker.releaseCycleHandle(this._posList);
            }
            ;
            if (!tmcycle) {
              org.castor.util.CycleBreaker.releaseCycleHandle(temp._posList);
            }
            ;
            return false;
          }
          if (!thcycle) {
            if (!this._posList.equals(temp._posList)) {
              org.castor.util.CycleBreaker.releaseCycleHandle(this._posList);
              org.castor.util.CycleBreaker.releaseCycleHandle(temp._posList);
              return false;
            }
            org.castor.util.CycleBreaker.releaseCycleHandle(this._posList);
            org.castor.util.CycleBreaker.releaseCycleHandle(temp._posList);
          }
        }
      } else if (temp._posList != null)
        return false;
      if (this._segList != null) {
        if (temp._segList == null)
          return false;
        if (this._segList != temp._segList) {
          thcycle = org.castor.util.CycleBreaker.startingToCycle(this._segList);
          tmcycle = org.castor.util.CycleBreaker.startingToCycle(temp._segList);
          if (thcycle != tmcycle) {
            if (!thcycle) {
              org.castor.util.CycleBreaker.releaseCycleHandle(this._segList);
            }
            ;
            if (!tmcycle) {
              org.castor.util.CycleBreaker.releaseCycleHandle(temp._segList);
            }
            ;
            return false;
          }
          if (!thcycle) {
            if (!this._segList.equals(temp._segList)) {
              org.castor.util.CycleBreaker.releaseCycleHandle(this._segList);
              org.castor.util.CycleBreaker.releaseCycleHandle(temp._segList);
              return false;
            }
            org.castor.util.CycleBreaker.releaseCycleHandle(this._segList);
            org.castor.util.CycleBreaker.releaseCycleHandle(temp._segList);
          }
        }
      } else if (temp._segList != null)
        return false;
      return true;
    }
    return false;
  }

  /**
   * Returns the value of field 'choiceValue'. The field 'choiceValue' has the
   * following description: Internal choice value storage
   * 
   * @return the value of field 'ChoiceValue'.
   */
  public java.lang.Object getChoiceValue() {
    return this._choiceValue;
  }

  /**
   * Method getPos.
   * 
   * @param index
   * @throws java.lang.IndexOutOfBoundsException
   *           if the index given is outside the bounds of the collection
   * @return the value of the uk.ac.vamsas.objects.core.Pos at the given index
   */
  public uk.ac.vamsas.objects.core.Pos getPos(final int index)
      throws java.lang.IndexOutOfBoundsException {
    // check bounds for index
    if (index < 0 || index >= this._posList.size()) {
      throw new IndexOutOfBoundsException("getPos: Index value '" + index
          + "' not in range [0.." + (this._posList.size() - 1) + "]");
    }

    return (uk.ac.vamsas.objects.core.Pos) _posList.get(index);
  }

  /**
   * Method getPos.Returns the contents of the collection in an Array.
   * <p>
   * Note: Just in case the collection contents are changing in another thread,
   * we pass a 0-length Array of the correct type into the API call. This way we
   * <i>know</i> that the Array returned is of exactly the correct length.
   * 
   * @return this collection as an Array
   */
  public uk.ac.vamsas.objects.core.Pos[] getPos() {
    uk.ac.vamsas.objects.core.Pos[] array = new uk.ac.vamsas.objects.core.Pos[0];
    return (uk.ac.vamsas.objects.core.Pos[]) this._posList.toArray(array);
  }

  /**
   * Method getPosAsReference.Returns a reference to '_posList'. No type
   * checking is performed on any modifications to the Vector.
   * 
   * @return a reference to the Vector backing this class
   */
  public java.util.Vector getPosAsReference() {
    return this._posList;
  }

  /**
   * Method getPosCount.
   * 
   * @return the size of this collection
   */
  public int getPosCount() {
    return this._posList.size();
  }

  /**
   * Method getSeg.
   * 
   * @param index
   * @throws java.lang.IndexOutOfBoundsException
   *           if the index given is outside the bounds of the collection
   * @return the value of the uk.ac.vamsas.objects.core.Seg at the given index
   */
  public uk.ac.vamsas.objects.core.Seg getSeg(final int index)
      throws java.lang.IndexOutOfBoundsException {
    // check bounds for index
    if (index < 0 || index >= this._segList.size()) {
      throw new IndexOutOfBoundsException("getSeg: Index value '" + index
          + "' not in range [0.." + (this._segList.size() - 1) + "]");
    }

    return (uk.ac.vamsas.objects.core.Seg) _segList.get(index);
  }

  /**
   * Method getSeg.Returns the contents of the collection in an Array.
   * <p>
   * Note: Just in case the collection contents are changing in another thread,
   * we pass a 0-length Array of the correct type into the API call. This way we
   * <i>know</i> that the Array returned is of exactly the correct length.
   * 
   * @return this collection as an Array
   */
  public uk.ac.vamsas.objects.core.Seg[] getSeg() {
    uk.ac.vamsas.objects.core.Seg[] array = new uk.ac.vamsas.objects.core.Seg[0];
    return (uk.ac.vamsas.objects.core.Seg[]) this._segList.toArray(array);
  }

  /**
   * Method getSegAsReference.Returns a reference to '_segList'. No type
   * checking is performed on any modifications to the Vector.
   * 
   * @return a reference to the Vector backing this class
   */
  public java.util.Vector getSegAsReference() {
    return this._segList;
  }

  /**
   * Method getSegCount.
   * 
   * @return the size of this collection
   */
  public int getSegCount() {
    return this._segList.size();
  }

  /**
   * Overrides the java.lang.Object.hashCode method.
   * <p>
   * The following steps came from <b>Effective Java Programming Language
   * Guide</b> by Joshua Bloch, Chapter 3
   * 
   * @return a hash code value for the object.
   */
  public int hashCode() {
    int result = super.hashCode();

    long tmp;
    if (_choiceValue != null
        && !org.castor.util.CycleBreaker.startingToCycle(_choiceValue)) {
      result = 37 * result + _choiceValue.hashCode();
      org.castor.util.CycleBreaker.releaseCycleHandle(_choiceValue);
    }
    if (_posList != null
        && !org.castor.util.CycleBreaker.startingToCycle(_posList)) {
      result = 37 * result + _posList.hashCode();
      org.castor.util.CycleBreaker.releaseCycleHandle(_posList);
    }
    if (_segList != null
        && !org.castor.util.CycleBreaker.startingToCycle(_segList)) {
      result = 37 * result + _segList.hashCode();
      org.castor.util.CycleBreaker.releaseCycleHandle(_segList);
    }

    return result;
  }

  /**
   * Method isValid.
   * 
   * @return true if this object is valid according to the schema
   */
  public boolean isValid() {
    try {
      validate();
    } catch (org.exolab.castor.xml.ValidationException vex) {
      return false;
    }
    return true;
  }

  /**
     */
  public void removeAllPos() {
    this._posList.clear();
  }

  /**
     */
  public void removeAllSeg() {
    this._segList.clear();
  }

  /**
   * Method removePos.
   * 
   * @param vPos
   * @return true if the object was removed from the collection.
   */
  public boolean removePos(final uk.ac.vamsas.objects.core.Pos vPos) {
    boolean removed = _posList.remove(vPos);
    return removed;
  }

  /**
   * Method removePosAt.
   * 
   * @param index
   * @return the element removed from the collection
   */
  public uk.ac.vamsas.objects.core.Pos removePosAt(final int index) {
    java.lang.Object obj = this._posList.remove(index);
    return (uk.ac.vamsas.objects.core.Pos) obj;
  }

  /**
   * Method removeSeg.
   * 
   * @param vSeg
   * @return true if the object was removed from the collection.
   */
  public boolean removeSeg(final uk.ac.vamsas.objects.core.Seg vSeg) {
    boolean removed = _segList.remove(vSeg);
    return removed;
  }

  /**
   * Method removeSegAt.
   * 
   * @param index
   * @return the element removed from the collection
   */
  public uk.ac.vamsas.objects.core.Seg removeSegAt(final int index) {
    java.lang.Object obj = this._segList.remove(index);
    return (uk.ac.vamsas.objects.core.Seg) obj;
  }

  /**
   * 
   * 
   * @param index
   * @param vPos
   * @throws java.lang.IndexOutOfBoundsException
   *           if the index given is outside the bounds of the collection
   */
  public void setPos(final int index, final uk.ac.vamsas.objects.core.Pos vPos)
      throws java.lang.IndexOutOfBoundsException {
    // check bounds for index
    if (index < 0 || index >= this._posList.size()) {
      throw new IndexOutOfBoundsException("setPos: Index value '" + index
          + "' not in range [0.." + (this._posList.size() - 1) + "]");
    }

    this._posList.set(index, vPos);
  }

  /**
   * 
   * 
   * @param vPosArray
   */
  public void setPos(final uk.ac.vamsas.objects.core.Pos[] vPosArray) {
    // -- copy array
    _posList.clear();

    for (int i = 0; i < vPosArray.length; i++) {
      this._posList.add(vPosArray[i]);
    }
  }

  /**
   * Sets the value of '_posList' by copying the given Vector. All elements will
   * be checked for type safety.
   * 
   * @param vPosList
   *          the Vector to copy.
   */
  public void setPos(final java.util.Vector vPosList) {
    // copy vector
    this._posList.clear();

    this._posList.addAll(vPosList);
  }

  /**
   * Sets the value of '_posList' by setting it to the given Vector. No type
   * checking is performed.
   * 
   * @deprecated
   * 
   * @param posVector
   *          the Vector to set.
   */
  public void setPosAsReference(final java.util.Vector posVector) {
    this._posList = posVector;
  }

  /**
   * 
   * 
   * @param index
   * @param vSeg
   * @throws java.lang.IndexOutOfBoundsException
   *           if the index given is outside the bounds of the collection
   */
  public void setSeg(final int index, final uk.ac.vamsas.objects.core.Seg vSeg)
      throws java.lang.IndexOutOfBoundsException {
    // check bounds for index
    if (index < 0 || index >= this._segList.size()) {
      throw new IndexOutOfBoundsException("setSeg: Index value '" + index
          + "' not in range [0.." + (this._segList.size() - 1) + "]");
    }

    this._segList.set(index, vSeg);
  }

  /**
   * 
   * 
   * @param vSegArray
   */
  public void setSeg(final uk.ac.vamsas.objects.core.Seg[] vSegArray) {
    // -- copy array
    _segList.clear();

    for (int i = 0; i < vSegArray.length; i++) {
      this._segList.add(vSegArray[i]);
    }
  }

  /**
   * Sets the value of '_segList' by copying the given Vector. All elements will
   * be checked for type safety.
   * 
   * @param vSegList
   *          the Vector to copy.
   */
  public void setSeg(final java.util.Vector vSegList) {
    // copy vector
    this._segList.clear();

    this._segList.addAll(vSegList);
  }

  /**
   * Sets the value of '_segList' by setting it to the given Vector. No type
   * checking is performed.
   * 
   * @deprecated
   * 
   * @param segVector
   *          the Vector to set.
   */
  public void setSegAsReference(final java.util.Vector segVector) {
    this._segList = segVector;
  }

  /**
   * 
   * 
   * @throws org.exolab.castor.xml.ValidationException
   *           if this object is an invalid instance according to the schema
   */
  public void validate() throws org.exolab.castor.xml.ValidationException {
    org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
    validator.validate(this);
  }

}
