/* DocumentEntryFactory.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.
 *
 * $Header: /nfs/disk222/yeastpub/Repository/powmap/uk/ac/sanger/pathogens/embl/DocumentEntryFactory.java,v 1.10 2000/04/17 15:27:23 kmr Exp $
 */

package uk.ac.sanger.pathogens.embl;

import uk.ac.sanger.pathogens.*;

import java.io.*;

/**
 *  This class contains the method makeDocumentEntry (), which creates a
 *  DocumentEntry object of the appropriate class from a Document object.
 *
 *  @author Kim Rutherford
 *  @version $Id: DocumentEntryFactory.java,v 1.10 2000/04/17 15:27:23 kmr Exp $
 **/

abstract public class DocumentEntryFactory {
  /**
   *  Read a DocumentEntry object from the given Document with no restrictions
   *  on the possible keys and qualifiers.  
   **/
  public static DocumentEntry makeDocumentEntry (final Document document)
      throws IOException {
    try {
      final EntryInformation entry_information =
        SimpleEntryInformation.getDefaultEntryInformation ();

      return makeDocumentEntry (entry_information, document);
    } catch (EntryInformationException e) {
      throw new Error ("internal error - unexpected exception: " + e);
    }
  }

  /**
   *  Read a DocumentEntry object from the given Document.
   *  @param entry_information The EntryInformation to use when reading.  This
   *    supplies the list of valid keys and qualifiers
   *  @exception EntryInformationException Thrown if an Entry using the given
   *    EntryInformation object cannot contain the Key, Qualifier or
   *    Key/Qualifier combination of one of the features in the Document.
   **/
  public static DocumentEntry makeDocumentEntry (final EntryInformation
                                                   entry_information,
                                                 final Document document)
      throws IOException, EntryInformationException {
    final Reader document_reader = document.getReader ();

    final BufferedReader buffered_reader =
      new BufferedReader (document_reader);

    final String first_line = buffered_reader.readLine ();

    if (first_line == null) {
      // empty file - create an empty EmblDocumentEntry
      return new EmblDocumentEntry (entry_information, document);
    }

    final int first_line_type = LineGroup.getLineType (first_line);

    switch (first_line_type) {
    case LineGroup.GFF_FEATURE:
      return new GFFDocumentEntry (document);
    case LineGroup.MSPCRUNCH_FEATURE:
      return new MSPcrunchDocumentEntry (document);
    case LineGroup.GENBANK_MISC:
    case LineGroup.GENBANK_FEATURE:
      return new GenbankDocumentEntry (entry_information, document);
    default:
      return new EmblDocumentEntry (entry_information, document);
    }
  }
  
  /**
   *  Make a new (nameless) DocumentEntry from the given Entry.  The new Entry
   *  will have a copy of the EntryInformation object of the argument Entry.
   *  @param destination_type This parameter control the type of DocumentEntry
   *    that is created.  It should be a DocumentEntry type that can be
   *    constructed from any Entry eg. one of EMBL_FORMAT, GENBANK_FORMAT.
   *  @exception EntryInformationException Thrown if the destination Entry
   *    cannot contain the Key, Qualifier or Key/Qualifier combination of one
   *    of the features in the source Entry. 
   **/
  public static DocumentEntry makeDocumentEntry (final Entry entry,
                                                 final int destination_type)
      throws EntryInformationException {
    final EntryInformation entry_information =
      new SimpleEntryInformation (entry.getEntryInformation ());

    return makeDocumentEntry (entry_information, entry, destination_type,
                              false);
  }

  /**
   *  Make a new (nameless) DocumentEntry from the given Entry.
   *  @param entry_information The EntryInformation to use for the new object.
   *    This supplies the list of valid keys and qualifiers.  Note that this
   *    argument is ignored by some DocumentEntry types, because some formats
   *    (like GFF) have limitations on the possible keys and qualifiers.
   *  @param destination_type This parameter control the type of DocumentEntry
   *    that is created.  It should be a DocumentEntry type that can be
   *    constructed from any Entry eg. one of EMBL_FORMAT, GENBANK_FORMAT.
   *  @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 an Entry using the given
   *    EntryInformation object cannot contain the Key, Qualifier or
   *    Key/Qualifier combination of one of the features in the source Entry.
   **/
  public static DocumentEntry makeDocumentEntry (final EntryInformation
                                                   entry_information,
                                                 final Entry entry,
                                                 int destination_type,
                                                 final boolean force)
      throws EntryInformationException {

    if (destination_type == ANY_FORMAT) {
      if (entry instanceof EmblDocumentEntry) {
        destination_type = EMBL_FORMAT;
      } else {
        if (entry instanceof GenbankDocumentEntry) {
          destination_type = GENBANK_FORMAT;
        } else {
          if (entry instanceof GFFDocumentEntry) {
            destination_type = GFF_FORMAT;
          } else {
            destination_type = EMBL_FORMAT;
          }
        }
      }
    }
    
    switch (destination_type) {
    case EMBL_FORMAT:
      return new EmblDocumentEntry (entry_information, entry, force);
    case GENBANK_FORMAT:
      return new GenbankDocumentEntry (entry_information, entry, force);
    case GFF_FORMAT:
      return new GFFDocumentEntry (entry, force);
    default:
      throw new Error ("internal error - unknown DocumentEntry type");
    }
  }

  /**
   *  The tag use if the format of the entry is unknown.
   **/
  final public static int UNKNOWN_FORMAT = 0;

  /**
   *  The tag use if the format of the entry is not important.
   **/
  final public static int ANY_FORMAT = UNKNOWN_FORMAT;

  /**
   *  The tag use for an entry that is in EMBL format.
   **/
  final public static int EMBL_FORMAT = 1;

  /**
   *  The tag use for an entry that is in GENBANK format.
   **/
  final public static int GENBANK_FORMAT = 2;

  /**
   *  The tag use for an entry that is in GFF format.
   **/
  final public static int GFF_FORMAT = 3;
}


