Skip to content
Snippets Groups Projects
PublicDBDocumentEntry.java 28.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • tjc's avatar
    tjc committed
    /* PublicDBDocumentEntry.java
     *
     * created: Sat Sep 11 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.
     *
    
    tjc's avatar
    tjc committed
     * $Header: //tmp/pathsoft/artemis/uk/ac/sanger/artemis/io/PublicDBDocumentEntry.java,v 1.22 2008-12-15 14:07:57 tjc Exp $
    
    tjc's avatar
    tjc committed
     */
    
    package uk.ac.sanger.artemis.io;
    
    
    import uk.ac.sanger.artemis.FeatureSegmentVector;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.Options;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.components.genebuilder.GeneUtils;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.components.genebuilder.cv.GoBox;
    
    import uk.ac.sanger.artemis.sequence.AminoAcidSequence;
    import uk.ac.sanger.artemis.sequence.Bases;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.util.*;
    
    import java.io.IOException;
    
    tjc's avatar
    tjc committed
    import java.io.InputStream;
    import java.util.Enumeration;
    
    tjc's avatar
    tjc committed
    import java.util.List;
    
    tjc's avatar
    tjc committed
    import java.util.Properties;
    import java.util.Vector;
    
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    tjc's avatar
    tjc committed
    
    /**
     *  This class extends the Entry class with the data for the entry coming from
     *  a Document object.  The Document must contain an EMBL entry or a GENBANK
     *  entry.
     *
     *  @author Kim Rutherford
    
    tjc's avatar
    tjc committed
     *  @version $Id: PublicDBDocumentEntry.java,v 1.22 2008-12-15 14:07:57 tjc Exp $
    
    tjc's avatar
    tjc committed
     **/
    
    public class PublicDBDocumentEntry extends SimpleDocumentEntry
        implements DocumentEntry 
    {
    
      // database keys mapping to EMBL keys with any extra
      // qualifiers to add in.
    
    tjc's avatar
    tjc committed
      private static Object[][] DATABASE_MAP_KEYS;
    
    tjc's avatar
    tjc committed
      
    
      // database qualifiers mapping to EMBL qualifiers
    
    tjc's avatar
    tjc committed
      private static String[][] DATABASE_QUALIFIERS_TO_MAP;
      
      // database qualifiers to ignore when converting to embl
      private static Object[] DATABASE_QUALIFIERS_TO_REMOVE;
      
    
      public static boolean IGNORE_OBSOLETE_FEATURES = true;
    
    tjc's avatar
    tjc committed
      
    
    tjc's avatar
    tjc committed
      /**
       *  Create a new PublicDBDocumentEntry object associated with the given
       *  Document.
       *  @param entry_information The EntryInformation object of the new Entry.
       *  @param document This is the file that we will read from.  This is also
       *    used for saving the entry back to the file it came from and to give
       *    the new object a name.
       *  @param listener The object that will listen for ReadEvents.
       *  @exception IOException thrown if there is a problem reading the entry -
       *    most likely ReadFormatException.
       *  @exception EntryInformationException Thrown if force is false and if this
       *    Entry cannot contain the Key, Qualifier or Key/Qualifier combination of
       *    one of the features in the given Entry.
       **/
      PublicDBDocumentEntry(final EntryInformation entry_information,
                            final Document document, final ReadListener listener)
          throws IOException, EntryInformationException 
      {
        super(entry_information, document, listener);
      }
    
      /**
       *  Create a new PublicDBDocumentEntry that will be a copy of the given
       *  Entry and has no Document associated with it.  The new
       *  PublicDBDocumentEntry cannot be saved to a file with save () unless save
       *  (Document) has been called first.
       *  @param entry_information The EntryInformation object of the new Entry.
       *  @param force If true then invalid qualifiers and any features with
       *    invalid keys in the new Entry will be quietly thrown away.  "Invalid"
       *    means that the key/qualifier is not allowed to occur in an Entry of
       *    this type (probably determined by the EntryInformation object of this
       *    Entry).  If false an EntryInformationException will be thrown for
       *    invalid keys or qualifiers.
       *  @exception EntryInformationException Thrown if force is false and if this
       *    Entry cannot contain the Key, Qualifier or Key/Qualifier combination of
       *    one of the features in the given Entry.
       **/
      public PublicDBDocumentEntry(final EntryInformation entry_information,
                                   final Entry new_entry, final boolean force)
          throws EntryInformationException 
      {
        super(entry_information, new_entry, force);
      }
    
      /**
       *  Create a new empty PublicDBDocumentEntry object that has no Document
       *  associated with it.  The new PublicDBDocumentEntry cannot be saved to a
       *  file with save () unless save (Document) has been called first.  The
       *  save (Document) method will assign a Document.
       *  @param entry_information The EntryInformation object of the Entry that
       *    will contain this Feature.
       **/
      public PublicDBDocumentEntry(final EntryInformation entry_information) 
      {
        super(entry_information);
      }
    
      /**
       *  If the given feature can be added directly to this Entry, then return
       *  it, otherwise create and return a new feature of the appropriate type.
       *  @param copy if true then always new a new copy of the Feature.
       **/
    
      protected Object makeNativeFeature(final Feature feature,
    
    tjc's avatar
    tjc committed
                                         final boolean copy) 
    
    tjc's avatar
    tjc committed
      {
        if (!copy && (feature instanceof EmblStreamFeature &&
                      this instanceof EmblDocumentEntry ||
                      feature instanceof GenbankStreamFeature &&
                      this instanceof GenbankDocumentEntry)) 
        {
          return (PublicDBStreamFeature) feature;
        } 
        else 
        {
    
    tjc's avatar
    tjc committed
            if(feature instanceof GFFStreamFeature)
    
              return mapGffToNativeFeature(feature);
            else if (this instanceof EmblDocumentEntry)
              return new EmblStreamFeature(feature);
            else
              return new GenbankStreamFeature(feature);
          }
          catch(NullPointerException npe)
          {
            System.err.println( 
                ((uk.ac.sanger.artemis.Feature)feature.getUserData()).getIDString() );
            throw npe;
          }
    
    tjc's avatar
    tjc committed
        }
      }
    
    tjc's avatar
    tjc committed
     
    
    tjc's avatar
    tjc committed
    
    
      /**
       * Map GFF features to EMBL/Genbank
       * @param feature
       * @return
       */
    
      private Object mapGffToNativeFeature(final Feature feature)
    
    tjc's avatar
    tjc committed
        if(DATABASE_MAP_KEYS == null)
          initDatabaseMappings();
    
        
        Key key = feature.getKey();
        QualifierVector qualifiers = feature.getQualifiers().copy();
    
        // ignore if obsolete
        if(IGNORE_OBSOLETE_FEATURES)
        {
          Qualifier isObsoleteQualifier = qualifiers.getQualifierByName("isObsolete");
          if(isObsoleteQualifier != null)
          {
            String value = (String)isObsoleteQualifier.getValues().get(0);
            if(Boolean.parseBoolean(value))
              return null;
          }
        }
        
    
    tjc's avatar
    tjc committed
        key = map(key, qualifiers);
        if(getEntryInformation().isValidQualifier((String) DATABASE_QUALIFIERS_TO_REMOVE[0]))
        { 
    
          try
          {
            if(this instanceof EmblDocumentEntry)
              return new EmblStreamFeature (
                  key, 
                  feature.getLocation(), 
                  qualifiers);
            else
              return new GenbankStreamFeature (
                key, 
                feature.getLocation(), 
                qualifiers);
          }
          catch(InvalidRelationException e)
          {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
        }
        
    
    tjc's avatar
    tjc committed
        Location location = joinUtrs(feature, key, qualifiers);
        if(location == null)
          return null;
    
    tjc's avatar
    tjc committed
        // flatten gene model - combining qualifiers
    
        if(key.getKeyString().equals(DatabaseDocument.EXONMODEL) &&
            ((GFFStreamFeature)feature).getChadoGene() != null)
    
    tjc's avatar
    tjc committed
          ChadoCanonicalGene chadoGene = ((GFFStreamFeature)feature).getChadoGene();
    
          final String name = GeneUtils.getUniqueName(feature);
          final String transcriptName = chadoGene.getTranscriptFromName(name);
          
    
          StringVector sv = new StringVector();
          sv.add(transcriptName);
          final Feature transcript = chadoGene.containsTranscript(sv);
          
          if(transcript != null && GeneUtils.isNonCodingTranscripts(transcript.getKey()))
            return null;
          
    
    tjc's avatar
    tjc committed
          qualifiers.removeQualifierByName("ID");
    
    tjc's avatar
    tjc committed
          int ntranscripts = 0;
    
          // add transcript & protein qualifiers to CDS
    
          try
          {
            final Feature protein = chadoGene.getProteinOfTranscript(transcriptName);
            if(protein != null)
    
              combineQualifiers(qualifiers, protein.getQualifiers().copy(), false);
    
    tjc's avatar
    tjc committed
              ntranscripts = handleTranscripts(qualifiers, transcript, ntranscripts, chadoGene);
    
          }
          catch(NullPointerException npe){}
    
    tjc's avatar
    tjc committed
          
          // add gene qualifiers to CDS
    
    tjc's avatar
    tjc committed
          QualifierVector geneQualifiers = chadoGene.getGene().getQualifiers().copy();
          
          // multiple transcripts
          if(ntranscripts > 1 && geneQualifiers.getQualifierByName("ID") != null)
          {
          	Qualifier newIDQualifier = 
            	new Qualifier("shared_id", (String)geneQualifiers.getQualifierByName("ID").getValues().get(0));
        	addNewQualifier(qualifiers, newIDQualifier);
        	geneQualifiers.removeQualifierByName("ID");
          }
    
          else if(ntranscripts == 1)
          {
    
            if(qualifiers.getQualifierByName("Start_range") != null)
              addNewQualifier(qualifiers, qualifiers.getQualifierByName("Start_range"));
            if(qualifiers.getQualifierByName("End_range") != null)
              addNewQualifier(qualifiers, qualifiers.getQualifierByName("End_range"));
    
          combineQualifiers(qualifiers, geneQualifiers, true);
    
        else if(GeneUtils.isNonCodingTranscripts(key))
        {
          // use gene id for non-coding transcripts
          ChadoCanonicalGene chadoGene = ((GFFStreamFeature)feature).getChadoGene();
          if(chadoGene != null)
          {
            qualifiers.removeQualifierByName("ID");
            QualifierVector geneQualifiers = chadoGene.getGene().getQualifiers().copy();
            combineQualifiers(qualifiers, geneQualifiers, true);
    
            
            if(qualifiers.getQualifierByName("product") != null)
            {
              Qualifier newQualifier = new Qualifier("product", processProductValues(qualifiers.getQualifierByName("product")));
              qualifiers.setQualifier(newQualifier);
            }
    
          location = handlePartials(qualifiers, location);
    
          for(int i=0; i<DATABASE_QUALIFIERS_TO_MAP.length; i++)
    
            if(!getEntryInformation().isValidQualifier(DATABASE_QUALIFIERS_TO_MAP[i][0]))
    
              changeQualifierName(qualifiers, DATABASE_QUALIFIERS_TO_MAP[i][0], 
                                              DATABASE_QUALIFIERS_TO_MAP[i][1]);
    
          if(qualifiers.getQualifierByName("stop_codon_redefined_as_selenocysteine") != null)
          {
            handleSelenocysteine(qualifiers, feature);
          }
          
    
    tjc's avatar
    tjc committed
          for(int i=0; i<DATABASE_QUALIFIERS_TO_REMOVE.length; i++)
    
    tjc's avatar
    tjc committed
            if(!getEntryInformation().isValidQualifier((String) DATABASE_QUALIFIERS_TO_REMOVE[i]))
              qualifiers.removeQualifierByName((String) DATABASE_QUALIFIERS_TO_REMOVE[i]);
    
    tjc's avatar
    tjc committed
         
          if(key.getKeyString().equals("polypeptide"))
    
    tjc's avatar
    tjc committed
            return null;
          else if(key.getKeyString().equals("gene"))
            return null;
    
    tjc's avatar
    tjc committed
          else if(key.getKeyString().equals("centromere"))
            return null;
    
    tjc's avatar
    tjc committed
          else if(key.getKeyString().equals("transcript") || 
                  key.getKeyString().equals("mRNA"))
    
    tjc's avatar
    tjc committed
            return null;
    
    tjc's avatar
    tjc committed
          
    
          
          if(this instanceof EmblDocumentEntry)
            return new EmblStreamFeature (
    
    tjc's avatar
    tjc committed
                key, location, 
    
                qualifiers);
          else
            return new GenbankStreamFeature (
    
    tjc's avatar
    tjc committed
                key, location, 
    
                qualifiers);
        }
        catch(InvalidRelationException e)
        {
          e.printStackTrace();
          if(feature instanceof DatabaseStreamFeature)
            return new EmblStreamFeature ();
          else
            return new GenbankStreamFeature ();
        }
      }
      
    
    tjc's avatar
    tjc committed
      /**
       * Handle UTR joins
       * @param feature
       * @param key
       * @param qualifiers
       * @return
       */
      private Location joinUtrs(Feature feature, Key key, QualifierVector qualifiers)
      {
        Location location = feature.getLocation();
        if(key.getKeyString().equals("5'UTR") ||
           key.getKeyString().equals("3'UTR"))
        {
          ChadoCanonicalGene gene = ((GFFStreamFeature)feature).getChadoGene();
          String utrName = GeneUtils.getUniqueName(feature);
          String transcriptName = gene.getTranscriptFromName(utrName);
          List<Feature> utrs;
          
          if(key.getKeyString().equals("5'UTR"))
            utrs = gene.get5UtrOfTranscript(transcriptName);
          else
            utrs = gene.get3UtrOfTranscript(transcriptName);
          
          if(utrs.size() > 1)
          {
            int start = Integer.MAX_VALUE;
            RangeVector ranges = new RangeVector();
            for(int i=0; i<utrs.size(); i++)
            {
              Feature utr = utrs.get(i);
              Range range = utr.getLocation().getTotalRange();
              if(start > range.getStart())
                start = range.getStart();
              ranges.add(range);
            }
            
            if(start != feature.getLocation().getTotalRange().getStart())
              return null;
            
    
            if(feature.getLocation().isComplement())
              ranges.reverse();
    
    tjc's avatar
    tjc committed
            location =
              new Location(ranges, feature.getLocation().isComplement());
          }
    
    
          int ntranscripts = gene.getTranscripts().size();
          if(ntranscripts == 1)
        	  transcriptName = gene.getGeneUniqueName();
    
    tjc's avatar
    tjc committed
          qualifiers.setQualifier(new Qualifier("locus_tag", transcriptName));
          qualifiers.removeQualifierByName("ID");
        }
        return location;
      }
    
    tjc's avatar
    tjc committed
      /**
    
       * Merge qualifiers
    
    tjc's avatar
    tjc committed
       * @param qualifiers
    
       * @param newQualifiers
    
      private void combineQualifiers(final QualifierVector qualifiers,
    
                                     final QualifierVector newQualifiers,
                                     final boolean isGene)
    
        for(int i=0; i<newQualifiers.size(); i++)
    
          Qualifier newQualifier = (Qualifier) newQualifiers.get(i);
          
    
          if( newQualifier.getName().equals("ID") && !isGene )
    
    tjc's avatar
    tjc committed
          {
        	continue;
          }
    
    tjc's avatar
    tjc committed
          
          // convert GO evidence to codes (e.g. ND=No biological Data available)
          if(newQualifier.getName().equals("GO"))
          {
            final StringVector newValues = newQualifier.getValues();
            final StringVector tmpNewValues = new StringVector();
            for(int j=0; j<newValues.size(); j++)
            {
              String val = GoBox.getEvidenceCodeGoTextFromText((String)newValues.get(j));
              tmpNewValues.add(val);
            }
     
            newQualifier = new Qualifier("GO", tmpNewValues);
          }
          
    
    tjc's avatar
    tjc committed
          if(newQualifier.getName().equals("product"))
          {
    
            newQualifier = new Qualifier("product", processProductValues(newQualifier));
    
          if(newQualifier.getName().equals("orthologous_to") ||
             newQualifier.getName().equals("paralogous_to"))
    
            final StringVector newValues = newQualifier.getValues();
            final StringVector tmpNewValues = new StringVector();
            for(int j=0; j<newValues.size(); j++)
            {
              if(!newValues.get(j).equals(""))
                tmpNewValues.add(newValues.get(j));
            }
    
    tjc's avatar
    tjc committed
            if(tmpNewValues.size() == 0)
              continue;
    
    tcarver's avatar
    tcarver committed
            Pattern p = Pattern.compile("\\w+[ :]link=\\w+");
    
            for(int j=0; j<tmpNewValues.size(); j++)
            {
              String valueStr = (String)tmpNewValues.get(j);
              String newValueStr;
              int indexEnd = valueStr.indexOf(';');
              String endStr = "";
              if(indexEnd > -1)
                endStr = valueStr.substring(indexEnd);
              Matcher m = p.matcher(valueStr);
              while(m.find())
              {
                int index = valueStr.indexOf("link=", m.start());
                newValueStr = valueStr.substring(m.start(), index)+
                              valueStr.substring(index+5, m.end())+endStr;
                if(newQualifier.getName().equals("orthologous_to"))
                  newQualifier = new Qualifier("orthologous_to", newValueStr);
                else
                  newQualifier = new Qualifier("paralogous_to", newValueStr);
                qualifiers.addElement(newQualifier);
              }
            }
            continue;
    
    tjc's avatar
    tjc committed
          addNewQualifier(qualifiers, newQualifier);
        }
      }
      
    
      /**
       * Process product qualifier
       * @param productQualifier
       * @return
       */
      private StringVector processProductValues(Qualifier productQualifier)
      {
        final StringVector values = productQualifier.getValues();
        final StringVector tmpNewValues = new StringVector();
    
        for(String val: values)
    
        {
          int ind = 0;
          if((ind=val.indexOf(";db_xref="))>-1 && this instanceof EmblDocumentEntry)
            val = val.substring(0,ind);
    
          if((ind=val.indexOf(";evidence="))>-1 && this instanceof EmblDocumentEntry)
            val = val.substring(0,ind);
    
          if((ind=val.indexOf(";with="))>-1 && this instanceof EmblDocumentEntry)
            val = val.substring(0,ind);
    
    
          if((ind=val.indexOf("rank="))>-1 && this instanceof EmblDocumentEntry)
          {
            int ind2 = val.indexOf(";", ind);
            if(ind == 0 && ind2 > -1)
              val = val.substring(ind2+1);
          }
    
    
          if(val.startsWith("term="))
            val = val.substring(5,  val.length());
    
          if(val.endsWith(";"))
            val = val.substring(0,  val.length()-1);
    
          tmpNewValues.add(val);
        }
        return tmpNewValues;
      }
      
    
    tjc's avatar
    tjc committed
      /**
       * Add a new qualifier to a list of qualifiers
       * @param qualifiers
       * @param newQualifier
       */
      private void addNewQualifier(QualifierVector qualifiers, Qualifier newQualifier)
      {
    	Qualifier qualifier;
        if( (qualifier = qualifiers.getQualifierByName(newQualifier.getName())) != null)
        { 
          final StringVector newValues = newQualifier.getValues();
          final StringVector values = qualifier.getValues();
    
    tjc's avatar
    tjc committed
          
          if(newValues == null)
            return;
    
    tjc's avatar
    tjc committed
          for(int j=0; j<newValues.size(); j++)
          {
            String newValue = (String) newValues.get(j);
            if(!values.contains(newValue))
              qualifier.addValue(newValue);
          }
        }
        else
          qualifiers.addElement(newQualifier);
      }
    
      /**
       * Routine to combine transcript qualifiers and for multiple transcripts 
       * create links to the other transcripts (other_transcript) and 
       * to use the transcript ID.
       * @param qualifiers
       * @param transcript
       * @param ntranscripts
       * @param chadoGene
       */
      private int handleTranscripts(QualifierVector qualifiers, 
    		                        Feature transcript,
    		                        int ntranscripts,
    		                        ChadoCanonicalGene chadoGene)
      {
    	QualifierVector transcriptQualifiers = transcript.getQualifiers().copy();
    
        combineQualifiers(qualifiers, transcriptQualifiers, false);
    
    tjc's avatar
    tjc committed
        ntranscripts = chadoGene.getTranscripts().size();
        if(ntranscripts > 1)
        {
          addNewQualifier(qualifiers, transcriptQualifiers.getQualifierByName("ID"));
    
    tjc's avatar
    tjc committed
          List<Feature> transcripts = chadoGene.getTranscripts();
    
    tjc's avatar
    tjc committed
          for(int i=0;i<ntranscripts;i++)
          {
            Feature thisTranscript = (Feature)transcripts.get(i);
            String thisTranscriptName = GeneUtils.getUniqueName(thisTranscript);
            if(!thisTranscriptName.equals( GeneUtils.getUniqueName(transcript )))
    
    tjc's avatar
    tjc committed
              Qualifier qualifier = new Qualifier("other_transcript", thisTranscriptName);
              addNewQualifier(qualifiers, qualifier);
    
    tjc's avatar
    tjc committed
        return ntranscripts;
    
    tjc's avatar
    tjc committed
      /**
    
    tjc's avatar
    tjc committed
       * Maps database (SO) keys to EMBl keys.
    
    tjc's avatar
    tjc committed
       * @param key
       * @return
       */
    
      protected static Key mapKeys(final Key key)
      {
    
    tjc's avatar
    tjc committed
        if(DATABASE_MAP_KEYS == null)
          initDatabaseMappings();
    
        for(int i=0; i<DATABASE_MAP_KEYS.length; i++)
        {
          if(key.getKeyString().equals(DATABASE_MAP_KEYS[i][0]))
            return new Key((String)DATABASE_MAP_KEYS[i][1]);
        }
        return key;
      }
      
      
      /**
       * Maps database (SO) keys to EMBl keys. It will add any extra qualifiers
       * found in the 3rd column of DATABASE_MAP_KEYS.
       * @param key
       * @return
       */
      private Key map(final Key key, final QualifierVector qualifiers)
    
    tjc's avatar
    tjc committed
      {
    
    tjc's avatar
    tjc committed
        if(DATABASE_MAP_KEYS == null)
          initDatabaseMappings();
    
        for(int i=0; i<DATABASE_MAP_KEYS.length; i++)
    
    tjc's avatar
    tjc committed
        {
    
          if(key.getKeyString().equals(DATABASE_MAP_KEYS[i][0]))
          {
            Key mappedKey = new Key((String)DATABASE_MAP_KEYS[i][1]);
            if(DATABASE_MAP_KEYS[i][2] != null)
            {
              
              Qualifier newQualifier = (Qualifier) DATABASE_MAP_KEYS[i][2];
              if(!getEntryInformation().isValidQualifier(mappedKey, newQualifier.getName()))
              {
                try
                {
    
    tjc's avatar
    tjc committed
                  final int nvalues;
                  if(newQualifier.getValues() == null)
                    nvalues = 0;
                  else
                    nvalues = newQualifier.getValues().size();
                  
    
                  final int type;
                  if(nvalues == 0)
                    type = QualifierInfo.NO_VALUE;
                  else
                    type = QualifierInfo.QUOTED_TEXT;
                  getEntryInformation().addQualifierInfo(
                      new QualifierInfo(newQualifier.getName(), 
                          type, null, null,
                          false));
                }
                catch(QualifierInfoException e){}
              }
              
              qualifiers.addQualifierValues(newQualifier);
            }
            
            return mappedKey;
          }
    
    tjc's avatar
    tjc committed
        }
        return key;
      }
      
    
    tjc's avatar
    tjc committed
      /**
       * Change the name of a qualifier
       * @param qualifiers
       * @param oldName
       * @param newName
       */
    
      private void changeQualifierName(QualifierVector qualifiers, 
    
    tjc's avatar
    tjc committed
                                       final String oldName, 
                                       final String newName)
      {
    
        QualifierVector tmpQualifiers = new QualifierVector();
        for(int i=0; i<qualifiers.size(); i++)
    
    tjc's avatar
    tjc committed
        {
    
          Qualifier qualifier = (Qualifier) qualifiers.elementAt(i);
          if(!qualifier.getName().equals(oldName))
          {
            tmpQualifiers.addElement(qualifier);
            continue;
          }
    
          Qualifier newQualifier = new Qualifier(newName, qualifier.getValues());
          tmpQualifiers.addQualifierValues(newQualifier);
        }
        qualifiers.removeAllElements();
        
        for(int i=0; i<tmpQualifiers.size(); i++)
          qualifiers.addElement(tmpQualifiers.elementAt(i));
    
    tjc's avatar
    tjc committed
      }
      
    
    tjc's avatar
    tjc committed
      /**
       *  If the given Sequence can be added directly to this Entry, then return a
       *  copy of it, otherwise create and return a new feature of the appropriate
       *  type for this Entry.
       **/
      protected StreamSequence makeNativeSequence (final Sequence sequence) 
      {
    
    tjc's avatar
    tjc committed
        if(this instanceof EmblDocumentEntry)
    
    tjc's avatar
    tjc committed
          return new EmblStreamSequence (sequence);
        else 
          return new GenbankStreamSequence (sequence);
      }
    
    tjc's avatar
    tjc committed
      
    
    tjc's avatar
    tjc committed
      public static Object[] getDatabaseQualifiersToRemove()  
      {
        initDatabaseMappings();
        return DATABASE_QUALIFIERS_TO_REMOVE;
      }
      
    
    tjc's avatar
    tjc committed
      /**
       *  Read key and qualifier mappings for CHADO to EMBL
       **/
      private static void initDatabaseMappings()
      {
    
        InputStream keyStream = 
          Options.class.getResourceAsStream("/key_mapping");
        if (keyStream == null)
          keyStream = 
            Options.class.getResourceAsStream("/etc/key_mapping");
    
        InputStream qualifierStream = 
          Options.class.getResourceAsStream("/qualifier_mapping");
        if (qualifierStream == null)
          qualifierStream = 
            Options.class.getResourceAsStream("/etc/qualifier_mapping");
    
    
    tjc's avatar
    tjc committed
        final Properties keyMapProperties = new Properties();
        final Properties qualifierMapProperties = new Properties();
        try
        {
          keyMapProperties.load(keyStream);
          qualifierMapProperties.load(qualifierStream);
    
    tjc's avatar
    tjc committed
          
          if(System.getProperty("nohistory") != null)
            qualifierMapProperties.setProperty("history", "");
    
    tjc's avatar
    tjc committed
        }
        catch(IOException e)
        {
          e.printStackTrace();
        }
    
        // parse the keyMapProperties
        DATABASE_MAP_KEYS = new Object[keyMapProperties.size()][3];
        final Enumeration keysenum = keyMapProperties.propertyNames();
        int n = 0;
        while(keysenum.hasMoreElements()) 
        {
          String current_map_name = (String) keysenum.nextElement();
    
          final StringVector property_values =
              Options.getPropertyValues(keyMapProperties, current_map_name);
    
          DATABASE_MAP_KEYS[n][0] = current_map_name;
          DATABASE_MAP_KEYS[n][1] = property_values.get(0);
          if(property_values.size() == 2)
          {
            String qualifierString[] = ((String)property_values.get(1)).split("=");
            final uk.ac.sanger.artemis.io.Qualifier qualifier;
            if(qualifierString.length == 2)
              qualifier = new uk.ac.sanger.artemis.io.Qualifier(qualifierString[0], qualifierString[1]);
            else
              qualifier = new uk.ac.sanger.artemis.io.Qualifier(qualifierString[0]);
            DATABASE_MAP_KEYS[n][2] = qualifier; 
          }
          else
            DATABASE_MAP_KEYS[n][2] = null;
          n++; 
        }
        
        // parse the qualifier mappings
        Enumeration qualifiersenum = qualifierMapProperties.propertyNames();
        n = 0;
    
    
        Vector<String> qualifiersToRemove = new Vector<String>();
    
    tjc's avatar
    tjc committed
        while(qualifiersenum.hasMoreElements()) 
        {
          String current_map_name = (String) qualifiersenum.nextElement();
          final StringVector property_values =
            Options.getPropertyValues(qualifierMapProperties, current_map_name);
          if(property_values == null || property_values.size() == 0)
            qualifiersToRemove.add(current_map_name);
          else
            n++;
        }
        
        DATABASE_QUALIFIERS_TO_MAP = new String[n][2];
        DATABASE_QUALIFIERS_TO_REMOVE = qualifiersToRemove.toArray();
        
        qualifiersenum = qualifierMapProperties.propertyNames();
        n = 0;
    
        while(qualifiersenum.hasMoreElements()) 
        {
          String current_map_name = (String) qualifiersenum.nextElement();
          final StringVector property_values =
            Options.getPropertyValues(qualifierMapProperties, current_map_name);
          if(property_values != null && property_values.size() > 0)
          {
            DATABASE_QUALIFIERS_TO_MAP[n][0] = current_map_name;
            DATABASE_QUALIFIERS_TO_MAP[n][1] = (String) property_values.get(0);
            n++;
          }
        }
      }
    
      /**
       * Use '<' and '>' signs in the location descriptors to
       * indicate that the sequence is partial.
       * @param qualifiers
       * @param location
       * @return
       */
      private Location handlePartials(QualifierVector qualifiers, Location location)
      {
    
        if(qualifiers.getQualifierByName("Start_range") != null)
    
    tcarver's avatar
    tcarver committed
            location = new Location(location.toStringShort().replaceFirst("(\\d)", "<$1"));
    
          }
          catch (LocationParseException e)
          {
            e.printStackTrace();
          }
        }
    
        if(qualifiers.getQualifierByName("End_range") != null)
    
    tcarver's avatar
    tcarver committed
            location = new Location(location.toStringShort().replaceAll("^(.*)(\\.)(.*)$","$1$2>$3"));
    
          }
          catch (LocationParseException e)
          {
            e.printStackTrace();
          }
        }
        return location;
      }
      
    
      /**
       * Change the stop_codon_redefined_as_selenocysteine SO qualifier
       * to the transl_except EMBL qualifier.
       * @param qualifiers
       * @param feature
       */
      private void handleSelenocysteine(QualifierVector qualifiers, Feature feature)
      {
        if(!feature.getKey().getKeyString().equals(DatabaseDocument.EXONMODEL))
          return;
        qualifiers.removeQualifierByName("stop_codon_redefined_as_selenocysteine");
    
        uk.ac.sanger.artemis.Feature f = ((uk.ac.sanger.artemis.Feature)feature.getUserData());
        
        int translatedBasePosion = 0;
        String aa = f.getTranslation().toString();
        for(int i=0; i<aa.length(); i++)
        {
          if(AminoAcidSequence.isStopCodon(aa.charAt(i)))
          {
            translatedBasePosion = i*3;
            break;
          }
        }
    
        FeatureSegmentVector segments = f.getSegments();
        int nbases = 0;
        int sequenceloc = 0;
        for(int i=0; i<segments.size(); i++)
        {
          int seglen = segments.elementAt(i).getBases().length();
    
    tcarver's avatar
    tcarver committed
          if(nbases+seglen > translatedBasePosion && sequenceloc == 0)
    
          {
            Bases bases = f.getStrand().getBases();
            sequenceloc = segments.elementAt(i).getStart().getPosition() +
                                  (translatedBasePosion-nbases);
            
            if(!f.isForwardFeature())
              sequenceloc = bases.getComplementPosition(sequenceloc);
          }
          nbases += seglen;
        }
        
    
    tcarver's avatar
    tcarver committed
        String pos;
        if(f.isForwardFeature())
          pos = sequenceloc+".."+(sequenceloc+2);
        else
    
          pos = sequenceloc+".."+(sequenceloc-2);
    
        qualifiers.add(new Qualifier("transl_except","(pos:"+pos+",aa:Sec)"));
      }
    
    
    tjc's avatar
    tjc committed
    }