/* EnsEMBLCorbaFeature.java
 *
 * created: Thu Oct 14 1999
 *
 * This file is part of Artemis
 *
 * Copyright (C) 1999  Genome Research Limited
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /nfs/disk222/yeastpub/Repository/powmap/uk/ac/sanger/pathogens/embl/EnsemblCorbaFeature.java,v 1.3 2000/02/24 13:12:50 kmr Exp $
 */

package uk.ac.sanger.pathogens.embl;

import uk.ac.sanger.pathogens.*;

/**
 *  This is an implementation of the Feature interface that can read itself
 *  from an EnsEMBL Corba server.
 *
 *  @author Kim Rutherford
 *  @version $Id: EnsemblCorbaFeature.java,v 1.3 2000/02/24 13:12:50 kmr Exp $
 **/

public class EnsemblCorbaFeature extends EMBLObject
    implements Feature, ComparableFeature {
  /**
   *  Create a new EnsemblCorbaFeature object.
   *  @param feature_handle The corba handle of the feature
   *  @exception InvalidRelationException Thrown if this Feature cannot contain
   *    one of the qualifiers that was read from the server.
   **/
  public EnsemblCorbaFeature (final Ensembl.artemis.Feature feature_handle)
      throws LocationParseException, InvalidKeyException,
             InvalidRelationException {
    this.feature_handle = feature_handle;

    final String location_string = feature_handle.getLocation ();

    System.out.println ("location: " + location_string);

    this.location = new Location (location_string);
    this.key = new Key (feature_handle.getKey ());
    grabQualifiers ();
  }

  /**
   *  Set the value of this object.
   *  @param key The new feature key
   *  @param location The Location object for the new feature
   *  @param qualifiers The qualifiers for the new feature
   *  @exception InvalidRelationException Thrown if this Feature cannot contain
   *    any of the given Qualifier objects.
   **/
  public void set (Key key,
                   Location location,
                   QualifierVector qualifiers)
      throws InvalidRelationException, ReadOnlyException {
    throw new ReadOnlyException ();
  }

  /**
   *  Set the owning Entry of this Feature.  Other objects should call
   *  setEnsemblCorbaEntry () to change the owner.
   *  @param entry The Entry that now owns this Feature.
   **/
  private void setEntry (EnsemblCorbaEntry entry) {
    this.entry = entry;
  }

  /**
   *  Set the owning EnsemblCorbaEntry of this Feature.
   *  @param entry The EnsemblCorbaEntry that now owns this Feature.
   **/
  void setEnsemblCorbaEntry (final EnsemblCorbaEntry entry) {
    setEntry (entry);
  }

  /**
   *  Set the key field of this object.
   *  @param key The new feature key
   **/
  public void setKey (Key key)
      throws ReadOnlyException {
    throw new ReadOnlyException ();
  }

  /**
   *  Set the location of this object.
   *  @param location The Location object for the new feature
   **/
  public void setLocation (Location location)
      throws ReadOnlyException {
    throw new ReadOnlyException ();
  }

  /**
   *  Set the qualifiers of this object discarding all the current qualifiers.
   *  @param qualifiers The qualifiers for the new feature
   *  @exception InvalidRelationException Throw if this Feature cannot contain
   *    any of the given Qualifier objects.
   **/
  public void setQualifiers (QualifierVector qualifiers)
      throws InvalidRelationException, ReadOnlyException {
    throw new ReadOnlyException ();
  }

  /**
   *  Add the given Qualifier to this Feature.  If this Feature contains a
   *  Qualifier with the same name as the new Qualifier it will be replaced.
   *  @param qualifier The new qualifier to add.
   *  @exception InvalidRelationException Throw if this Feature cannot contain
   *    the given Qualifier.
   **/
  public void setQualifier (Qualifier qualifier)
      throws InvalidRelationException, ReadOnlyException {
    throw new ReadOnlyException ();
  }

  /**
   *  Remove the Qualifier with the given name.  If there is no Qualifier with
   *  that name then return immediately.
   *  @param name The qualifier name to look for.
   **/
  public void removeQualiferByName (final String name)
      throws ReadOnlyException {
    throw new ReadOnlyException ();
  }

  /**
   *  Add the values from the given qualifier to the Qualifier object with the
   *  same name in this Feature or otherwise add a copy of the argument.
   *  @param qualifier This object contians name and values to add.
   *  @param values The values to add to the Qualifier.
   *  @return The Qualifier that was changed or created.
   *  @exception InvalidRelationException Thrown if this Feature cannot contain
   *    the given Qualifier.
   **/
  public Qualifier addQualifierValues (Qualifier qualifier)
      throws InvalidRelationException, ReadOnlyException {
    throw new ReadOnlyException ();
  }

  /**
   *  Return the unique identifier of this StreamFeature.
   **/
  public long getNumericID () {
    return id;
  }

  /**
   *  Return the key of this feature, as passed to the constructor.
   **/
  public Key getKey () {
    return key;
  }

  /**
   *  Return the Location of this Feature, as passed to the constructor.
   **/
  public Location getLocation () {
    return location;
  }

  /**
   *  Return a QualifierVector object containing the qualifiers for this
   *  feature.  This method does not return a copy of the qualifier vector so
   *  changing the vector will change the feature.
   **/
  public QualifierVector getQualifiers () {
    return qualifiers;
  }

  /**
   *  Return the Qualifier in this Feature with the given name or null if
   *  there no such Qualifier.
   **/
  public Qualifier getQualifierByName (final String name) {
    return getQualifiers ().getQualifierByName (name);
  }

  /**
   *  Return the first base of this feature.
   **/
  public int getFirstBase () {
    return getLocation ().getFirstBase ();
  }

  /**
   *  Return the last base of this feature.
   **/
  public int getLastBase () {
    return getLocation ().getLastBase ();
  }

  /**
   *  Return the Entry object that contains this Feature.
   **/
  public Entry getEntry () {
    return entry;
  }

  /**
   *  Return the reference of a new copy of this Feature.  The new Feature
   *  will not be in any Entry, so it should be explicitly added with a call
   *  to Entry.add ().
   **/
  public Feature copy () {
    throw new Error ("not implemented");
  }

  /**
   *  Read the qualifiers from the given NucFeature, create an embl.Qualifier
   *  for each one and put them in the qualifiers vector.
   **/
  private void grabQualifiers ()
      throws InvalidRelationException {
    qualifiers = new QualifierVector ();

    final Ensembl.artemis.Qualifier [] corba_qualifier_handles =
      feature_handle.getQualifiers ();

//      System.out.println ("feature " + getKey () + " - " +
//                          corba_qualifier_handles.length);

    for (int i = 0 ; i < corba_qualifier_handles.length ; ++i) {
      final Ensembl.artemis.Qualifier this_corba_qualifier =
        corba_qualifier_handles[i];

      final StringVector values =
        getQualifierStringValues (this_corba_qualifier);

      EntryInformation entry_info = getEntryInformation ();
      
      final String qualifier_name = this_corba_qualifier.name;

      if (!entry_info.isValidQualifier (getKey (),
                                        this_corba_qualifier.name)) {
        final String message =
          getKey () + " cannot have " + this_corba_qualifier.name +
          " as a qualifier";

        throw new InvalidRelationException (message, getKey (),
                                            new Qualifier (qualifier_name));
      }

      if (values.size () == 0) {
        qualifiers.setQualifier (new Qualifier (this_corba_qualifier.name));
      } else {
        qualifiers.setQualifier (new Qualifier (this_corba_qualifier.name,
                                                values));
      }
    }
  }

  /**
   *  Return (from corba) the values of the given qualifier as String objects.
   **/
  private StringVector
    getQualifierStringValues (Ensembl.artemis.Qualifier qualifier) {

    final String [] corba_values = qualifier.values;

    final StringVector return_array = new StringVector ();

    for (int value_index = 0 ;
         value_index < corba_values.length ;
         ++value_index) {

      return_array.add (corba_values[value_index]);
    }

    return return_array;
  }

  /**
   *  Return the EntryInformation object from the Entry of this feature (if
   *  there is an Entry) or SimpleEntryInformation.default_entry_information
   *  otherwise. 
   **/
  private EntryInformation getEntryInformation () {
    return SimpleEntryInformation.getDefaultEntryInformation ();
  }

  /**
   *  The Ensembl.artemis.Feature object that was passed to the constructor.
   **/
  private Ensembl.artemis.Feature feature_handle;

  /**
   *  The Location of this Feature, set by the constructor.
   **/
  private Location location;

  /**
   *  The Key of this Feature, set by the constructor.
   **/
  private Key key;

  /**
   *  The qualifiers of this Feature, set by the first call to the
   *  getQualifiers () method.
   **/
  private QualifierVector qualifiers = null;

  /**
   *  The EnsemblCorbaEntry object that contains this Feature as passed to the
   *  constructor.
   **/
  private EnsemblCorbaEntry entry;

  /**
   *  A unique identifier for this feature.
   **/
  private final long id = id_counter++;

  /**
   *  This is incremented each time a constructor is called.
   **/
  private static long id_counter = 0;
}
