/* ExternalSearchProgram.java
 *
 * created: Tue Jan 26 1999
 *
 * This file is part of Artemis
 *
 * Copyright (C) 1998,1999,2000  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/diana/ExternalSearchProgram.java,v 1.27 2000/09/18 09:48:00 kmr Exp $
 **/

package diana;

import uk.ac.sanger.pathogens.*;
import uk.ac.sanger.pathogens.embl.InvalidRelationException;
import uk.ac.sanger.pathogens.embl.StreamSequence;
import uk.ac.sanger.pathogens.embl.FastaStreamSequence;
import uk.ac.sanger.pathogens.embl.EntryInformationException;
import uk.ac.sanger.pathogens.embl.EntryInformation;

import java.io.*;
import java.text.*;

/**
 *  This class is an ExternalProgram that can run searches.
 *
 *  @author Kim Rutherford
 *  @version $Id: ExternalSearchProgram.java,v 1.27 2000/09/18 09:48:00 kmr Exp $
 **/

public class ExternalSearchProgram extends ExternalProgram {
  /**
   *  Create a new ExternalSearchProgram object.
   *  @param name The name of the program.
   *  @param search_options The default options to use when running the
   *    program.
   *  @param dna_search True if and only if ExternalSearchProgram.run () should
   *    dump out DNA sequence instead of protein sequence for each feature.
   **/
  public ExternalSearchProgram (final String name,
                                final String search_options,
                                final boolean dna_search) {
    super (name);

    this.search_options = search_options;
    this.dna_search     = dna_search;
  }

  /**
   *  Run this program with the options that were set with setOptions ().
   *  @param features The program will be run for each of these features.
   *  @return The Process object that is running the search or null if there
   *    is nothing to be done (for example if the FeatureVector is empty).
   *  @exception IOException Thrown if an IO error occur while trying to run
   *    the program (eg the program could not be found).
   *  @exception ExternalProgramException Thrown if there is a non-IO error
   *    while attempting to run the program.
   *  @exception ReadOnlyException Thrown if one (or more) of the given
   *    features is in a read-only entry.
   *  @exception EntryInformationException Thrown if there is no qualifier
   *    that can be used to store the output filename
   **/
  public Process run (final FeatureVector features)
      throws IOException, ExternalProgramException, EntryInformationException,
             ReadOnlyException {

    final String new_qualifier_name = getName () + "_file";

    // do this first so that we don't get an exception half way through the
    // list
    for (int i = 0 ; i < features.size () ; ++i) {
      final Feature this_feature = features.elementAt (i);

      if (this_feature.getEntry ().isReadOnly ()) {
        throw new ReadOnlyException ();
      }

      final EntryInformation entry_information =
        this_feature.getEntry ().getEntryInformation ();

      if (!entry_information.isValidQualifier (this_feature.getKey (),
                                               new_qualifier_name)) {
        final String message =
          this_feature.getKey () + " cannot have " + new_qualifier_name +
          " as a qualifier";
        throw new EntryInformationException (message);
      }
    }

    try {
      if (features.size () == 0) {
        return null;
      }

      makeDirectory (new File (getName ()));

      final StringVector sequence_file_names = new StringVector ();

      final NumberFormat number_format = NumberFormat.getNumberInstance ();

      number_format.setMaximumIntegerDigits (5);
      number_format.setMinimumIntegerDigits (5);
      number_format.setGroupingUsed (false);

      // The number to use to for the first sequence file name
      final int old_file_number = getFileNumber ();

      setFileNumber (old_file_number + features.size ());

      // write the sequences out
      for (int i = 0 ; i < features.size () ; ++i) {
        final Feature feature = features.elementAt (i);
        final String entry_name;

        {
          final String test_name = feature.getEntry ().getName ();
          if (test_name == null) {
            entry_name = "no_name";
          } else {
            entry_name = test_name;
          }
        }

        final String new_file_name =
          getName () + File.separatorChar + entry_name + ".seq." +
          number_format.format (old_file_number + i);

        sequence_file_names.add (new_file_name);

        final Writer writer = new FileWriter (new File (new_file_name));

        if (dna_search) {
          feature.writeBasesOfFeature (writer);
        } else {
          feature.writeAminoAcidsOfFeature (writer);
        }

        writer.close ();

        final uk.ac.sanger.pathogens.embl.Qualifier new_qualifier =
          new uk.ac.sanger.pathogens.embl.Qualifier (new_qualifier_name,
                                                     new_file_name + ".out");
        feature.setQualifier (new_qualifier);
      }

      // write the sequence file names to a file and then run the program with
      // that file as an argument
      final String file_of_filenames_name = getName () + File.separatorChar +
        "file_of_filenames." + old_file_number;

      final Writer filenames_writer = new FileWriter (file_of_filenames_name);

      final PrintWriter filenames_printwriter =
        new PrintWriter (filenames_writer);

      for (int i = 0 ; i < sequence_file_names.size () ; ++i) {
        filenames_printwriter.println (sequence_file_names.elementAt (i));
      }

      filenames_printwriter.close ();
      filenames_writer.close ();

      final String [] arguments = {
        file_of_filenames_name,
        getSearchOptions ()
      };

      final Process process =
        startProgram ("run_" + getName (), arguments);

      return process;
    } catch (SecurityException e) {
      // re-throw as an ExternalProgramException
      throw new ExternalProgramException ("SecurityException while running " +
                                          getName () + ": " + e.getMessage ());
    }
  }

  /**
   *  Return the options that will be used when the program is run.
   **/
  public String getSearchOptions () {
    if (search_options.equals ("-")) {
      return "";
    } else {
      return search_options;
    }
  }

  /**
   *  Set the options that will be used when the program is run.
   **/
  public void setSearchOptions (final String search_options) {
    this.search_options = search_options;
  }

  /**
   *  The default options to use for searches with this program.
   **/
  private String search_options;

  /**
   *  True if and only if ExternalSearchProgram.run () should dump out DNA
   *  sequence instead of protein sequence for each feature.
   **/
  final boolean dna_search;
}
