/*  $Id: blast_options.hpp 562577 2018-04-24 15:51:23Z fongah2 $
 * ===========================================================================
 *
 *                            PUBLIC DOMAIN NOTICE
 *               National Center for Biotechnology Information
 *
 *  This software/database is a "United States Government Work" under the
 *  terms of the United States Copyright Act.  It was written as part of
 *  the author's official duties as a United States Government employee and
 *  thus cannot be copyrighted.  This software/database is freely available
 *  to the public for use. The National Library of Medicine and the U.S.
 *  Government have not placed any restriction on its use or reproduction.
 *
 *  Although all reasonable efforts have been taken to ensure the accuracy
 *  and reliability of the software and data, the NLM and the U.S.
 *  Government do not and cannot warrant the performance or results that
 *  may be obtained by using this software or data. The NLM and the U.S.
 *  Government disclaim all warranties, express or implied, including
 *  warranties of performance, merchantability or fitness for any particular
 *  purpose.
 *
 *  Please cite the author in any work or product based on this material.
 *
 * ===========================================================================
 *
 * Author:  Christiam Camacho
 *
 */

/** @file blast_options.hpp
 * Declares class to encapsulate all BLAST options
 */

#ifndef ALGO_BLAST_API___BLAST_OPTION__HPP
#define ALGO_BLAST_API___BLAST_OPTION__HPP

#include <objects/scoremat/PssmWithParameters.hpp>

#include <algo/blast/api/blast_types.hpp>
#include <algo/blast/api/blast_aux.hpp>
#include <algo/blast/api/blast_exception.hpp>

#include <algo/blast/core/blast_options.h>
#include <algo/blast/composition_adjustment/composition_constants.h>

// Forward declarations of classes that need to be declared friend 
// (mostly unit test classes)
class CTracebackTestFixture; 
class CBlastSetupTestFixture;
class CUniformSearchTest; 
class CTracebackSearchTestFixture;

class CBlastTabularFormatThread;

BEGIN_NCBI_SCOPE

BEGIN_SCOPE(objects)
    class CSeq_loc;
    class CBlast4_parameters;
END_SCOPE(objects)

/** @addtogroup AlgoBlast
 *
 * @{
 */

BEGIN_SCOPE(blast)

//#ifndef SKIP_DOXYGEN_PROCESSING


// Forward declarations
class CBlastOptionsLocal;
class CBlastOptionsRemote;
class CBlastOptionsMemento;

/// Encapsulates ALL the BLAST algorithm's options. To ensure that the default
/// options are set properly, it is recommended that this object is not created
/// directly by the calling code, instead, it should be obtained from calling
/// CBlastOptionsHandle::[GS]etOptions().
/// @note This class provides accessors and mutators for all BLAST options 
/// without preventing the caller from setting inconsistent options.
/// @sa @ref blast_opts_cookbook
class NCBI_XBLAST_EXPORT CBlastOptions : public CObject
{
public:
    /// Enumerates the possible contexts in which objects of this type can be
    /// used
    enum EAPILocality {
        /// To be used for running BLAST locally. 
        /// @sa CBl2Seq, CLocalBlast
        eLocal,
        /// To be used when running BLAST remotely. 
        /// @sa CRemoteBlast
        eRemote,
        eBoth
    };
    
    /// Constructor which allows specification of local or remote version of
    /// the options (might change in the future)
    /// @param locality specification of whether this type will be used with a
    /// remote or local BLAST search database class
    CBlastOptions(EAPILocality locality = eLocal);

    /// Destructor
    ~CBlastOptions();

    /// Explicit deep copy of the Blast options object.
    /// @return Copy of this Blast options object.
    CRef<CBlastOptions> Clone() const;

    /// Return the locality used when the object was created
    EAPILocality GetLocality() const;
    
    /// Validate the options
    bool Validate() const;
    
    /// Accessors/Mutators for individual options

    /// Returns the task this object is best suited for
    EProgram GetProgram() const;
    /// Sets the task this object is best suited for
    void SetProgram(EProgram p);

    /// Returns the CORE BLAST notion of program type
    EBlastProgramType GetProgramType() const;

    bool IsIterativeSearch() const;

    /******************* Lookup table options ***********************/
    /// Returns WordThreshold
    double GetWordThreshold() const;
    /// Sets WordThreshold
    /// @param w WordThreshold [in]
    void SetWordThreshold(double w);

#ifndef SKIP_DOXYGEN_PROCESSING

    ELookupTableType GetLookupTableType() const;
    void SetLookupTableType(ELookupTableType type);

    int GetWordSize() const;
    void SetWordSize(int ws);

    Uint4 GetLookupTableStride() const;
    void SetLookupTableStride(Uint4 val);

    bool GetLookupDbFilter(void) const;
    void SetLookupDbFilter(bool val);

    /// Get maximum word count for lookup table word masking by database
    /// frequency
    Uint1 GetMaxDbWordCount(void) const;
    /// Set maximum word count for lookup table word masking by database
    /// frequency
    void SetMaxDbWordCount(Uint1 num);

    /// Megablast only lookup table options
    unsigned char GetMBTemplateLength() const;
    void SetMBTemplateLength(unsigned char len);

    unsigned char GetMBTemplateType() const;
    void SetMBTemplateType(unsigned char type);

    /******************* Query setup options ************************/
    void ClearFilterOptions();
#endif /* SKIP_DOXYGEN_PROCESSING */

    /// Return the filtering string used
    /// @return copy of the filtering options string, caller must free() the
    /// return value
    /// @deprecated Do not use this method, instead use the various methods to
    /// retrieve filtering options
    /// @sa GetMaskAtHash, GetDustFiltering, GetDustFilteringLevel,
    /// GetDustFilteringWindow, GetDustFilteringWindow, GetSegFiltering,
    /// GetSegFilteringWindow, GetSegFilteringLocut, GetSegFilteringHicut
    /// GetRepeatFiltering, GetRepeatFilteringDB
    NCBI_DEPRECATED char* GetFilterString() const;
#ifndef SKIP_DOXYGEN_PROCESSING
    NCBI_DEPRECATED void SetFilterString(const char* f, bool clear = true);

    bool GetMaskAtHash() const;
    void SetMaskAtHash(bool val = true);

    bool GetDustFiltering() const;
    void SetDustFiltering(bool val = true);

    int GetDustFilteringLevel() const;
    void SetDustFilteringLevel(int m);

    int GetDustFilteringWindow() const;
    void SetDustFilteringWindow(int m);

    int GetDustFilteringLinker() const;
    void SetDustFilteringLinker(int m);

    bool GetSegFiltering() const;
    void SetSegFiltering(bool val = true);

    int GetSegFilteringWindow() const;
    void SetSegFilteringWindow(int m);

    double GetSegFilteringLocut() const;
    void SetSegFilteringLocut(double m);

    double GetSegFilteringHicut() const;
    void SetSegFilteringHicut(double m);
#endif /* SKIP_DOXYGEN_PROCESSING */

    /// Returns true if repeat filtering is on
    bool GetRepeatFiltering() const;
    /// Turns on repeat filtering using the default repeat database, namely
    /// kDefaultRepeatFilterDb 
    /// @note Either SetRepeatFiltering or SetRepeatFilteringDB should be
    /// called, if both are called, only the last one called will take effect
    void SetRepeatFiltering(bool val = true);

    /// Returns the name of the repeat filtering database to use
    const char* GetRepeatFilteringDB() const;
    /// Sets the repeat filtering database to use
    /// @note Either SetRepeatFiltering or SetRepeatFilteringDB should be
    /// called, if both are called, only the last one called will take effect
    void SetRepeatFilteringDB(const char* db);

    /// Returns the tax id used for the windowmasker database to use, if set
    /// via SetWindowMaskerTaxId (otherwise, returns 0)
    int GetWindowMaskerTaxId() const;

    /// Sets the tax id to select an appropriate windowmasker database
    /// Conversion algorithm from tax id to database name is specific to NCBI,
    /// will not work outside NCBI.
    /// @note this only runs on machines that have the WINDOW_MASKER_PATH
    /// configuration value set and have the the correct endianness. If
    /// windowmasker databases are not available, the filtering will fail
    /// silently
    void SetWindowMaskerTaxId(int taxid);

    /// Return the name of the windowmasker database to use
    const char* GetWindowMaskerDatabase() const;

    /// Sets the windowmasker database to use. This must be the name of a
    /// subdirectory of WINDOW_MASKER_PATH
    /// @note this only runs on machines that have the WINDOW_MASKER_PATH
    /// configuration value set and have the the correct endianness. If
    /// windowmasker databases are not available, the filtering will fail
    /// silently
    void SetWindowMaskerDatabase(const char* db);

    /// Returns true if next-generation read quality filtering is turned on
    bool GetReadQualityFiltering() const;

    /// Turn on/off next-generation read quality filtering with deafult
    /// parameters
    void SetReadQualityFiltering(bool val = true);

    /// Get maximum fraction of ambiguous bases for next-generation read
    /// quality filtering
    double GetReadMaxFractionAmbiguous() const;

    /// Set maximum fraction of ambiguous bases for next-generation read
    /// quality filtering
    void SetReadMaxFractionAmbiguous(double val);

    /// Get minimum dimer entropy for next-generation read quality filtering
    int GetReadMinDimerEntropy() const;

    /// Set minimum dimer entropy for next-generation read quality filtering
    void SetReadMinDimerEntropy(int val);

#ifndef SKIP_DOXYGEN_PROCESSING
    objects::ENa_strand GetStrandOption() const;
    void SetStrandOption(objects::ENa_strand s);

    int GetQueryGeneticCode() const;
    void SetQueryGeneticCode(int gc);

    /******************* Initial word options ***********************/
    int GetWindowSize() const;
    void SetWindowSize(int w);

    int GetOffDiagonalRange() const;
    void SetOffDiagonalRange(int r);

    double GetXDropoff() const;
    void SetXDropoff(double x);

    /******************* Gapped extension options *******************/
    double GetGapXDropoff() const;
    void SetGapXDropoff(double x);

    double GetGapXDropoffFinal() const;
    void SetGapXDropoffFinal(double x);

    double GetGapTrigger() const;
    void SetGapTrigger(double g);

    EBlastPrelimGapExt GetGapExtnAlgorithm() const;
    void SetGapExtnAlgorithm(EBlastPrelimGapExt a);

    EBlastTbackExt GetGapTracebackAlgorithm() const;
    void SetGapTracebackAlgorithm(EBlastTbackExt a);

    ECompoAdjustModes GetCompositionBasedStats() const;
    void SetCompositionBasedStats(ECompoAdjustModes mode);

    bool GetSmithWatermanMode() const;
    void SetSmithWatermanMode(bool m = true);

    int GetUnifiedP() const;
    void SetUnifiedP(int u = 0);

    int GetMaxMismatches() const;
    void SetMaxMismatches(int m);

    int GetMismatchWindow() const;
    void SetMismatchWindow(int w);

    /******************* Hit saving options *************************/
    int GetHitlistSize() const;
    void SetHitlistSize(int s);

    int GetMaxNumHspPerSequence() const;
    void SetMaxNumHspPerSequence(int m);

    int GetMaxHspsPerSubject() const;
    void SetMaxHspsPerSubject(int m);

    int GetCullingLimit() const;
    void SetCullingLimit(int s);

    bool GetSubjectBestHit() const;
    void SetSubjectBestHit();

    double GetBestHitOverhang() const;
    void SetBestHitOverhang(double overhang);
    double GetBestHitScoreEdge() const;
    void SetBestHitScoreEdge(double score_edge);

    // Expect value cut-off threshold for an HSP, or a combined hit if sum
    // statistics is used
    double GetEvalueThreshold() const;
    void SetEvalueThreshold(double eval);

    // Raw score cutoff threshold
    int GetCutoffScore() const;
    void SetCutoffScore(int s);

    // Raw score cutoff as a linear function of query length
    // x[0] + x[1] * length
    vector<double> GetCutoffScoreCoeffs() const;
    void SetCutoffScoreCoeffs(const vector<double>& c);

    double GetPercentIdentity() const;
    void SetPercentIdentity(double p);

    // Set max edit distance for mapping NGS sequences
    int GetMaxEditDistance() const;
    void SetMaxEditDistance(int e);

    double GetQueryCovHspPerc() const;
    void SetQueryCovHspPerc(double p);

    int GetMinDiagSeparation() const;
    void SetMinDiagSeparation(int d);

    /// Sum statistics options
    bool GetSumStatisticsMode() const;
    void SetSumStatisticsMode(bool m = true);

    /// for linking HSPs with uneven gaps
    /// @todo fix this description
    int GetLongestIntronLength() const;
    /// for linking HSPs with uneven gaps
    /// @todo fix this description
    void SetLongestIntronLength(int l);

    /// Returns true if gapped BLAST is set, false otherwise
    bool GetGappedMode() const;
    void SetGappedMode(bool m = true);

    /// Masklevel filtering option -RMH-
    int GetMaskLevel() const;
    void SetMaskLevel(int s);

    /// Returns true if cross_match-like complexity adjusted
    //  scoring is required, false otherwise. -RMH-
    bool GetComplexityAdjMode() const;
    void SetComplexityAdjMode(bool m = true);

    /// Sets a low score to drop ungapped alignments if hit list is full.
    double GetLowScorePerc() const;
    void SetLowScorePerc(double p = 0.0);

    // Return only paired reads, for mapping
    bool GetPaired() const;
    void SetPaired(bool p);

    /// Splice HSPs for each query (for mappring RNA-Seq reads to a genome)
    bool GetSpliceAlignments() const;
    void SetSpliceAlignments(bool s);

    /************************ Scoring options ************************/
    const char* GetMatrixName() const;
    void SetMatrixName(const char* matrix);

    int GetMatchReward() const;
    void SetMatchReward(int r);

    int GetMismatchPenalty() const;
    void SetMismatchPenalty(int p);

    int GetGapOpeningCost() const;
    void SetGapOpeningCost(int g);

    int GetGapExtensionCost() const;
    void SetGapExtensionCost(int e);

    int GetFrameShiftPenalty() const;
    void SetFrameShiftPenalty(int p);

    bool GetOutOfFrameMode() const;
    void SetOutOfFrameMode(bool m = true);

    /******************** Effective Length options *******************/
    Int8 GetDbLength() const;
    void SetDbLength(Int8 l);

    unsigned int GetDbSeqNum() const;
    void SetDbSeqNum(unsigned int n);

    Int8 GetEffectiveSearchSpace() const;
    void SetEffectiveSearchSpace(Int8 eff);
    void SetEffectiveSearchSpace(const vector<Int8>& eff);

    int GetDbGeneticCode() const;
    
    // Set both integer and string genetic code in one call
    void SetDbGeneticCode(int gc);

    /// @todo PSI-Blast options could go on their own subclass?
    const char* GetPHIPattern() const;
    void SetPHIPattern(const char* pattern, bool is_dna);

    /******************** PSIBlast options *******************/
    double GetInclusionThreshold() const;
    void SetInclusionThreshold(double u);

    int GetPseudoCount() const;
    void SetPseudoCount(int u);

    bool GetIgnoreMsaMaster() const;
    void SetIgnoreMsaMaster(bool val);
    

    /******************** DELTA-BLAST options *******************/

    double GetDomainInclusionThreshold(void) const;
    void SetDomainInclusionThreshold(double th);


    /******************** Megablast Database Index *******************/
    bool GetUseIndex() const;
    bool GetForceIndex() const;
    bool GetIsOldStyleMBIndex() const;
    bool GetMBIndexLoaded() const;
    const string GetIndexName() const;
    void SetMBIndexLoaded( bool index_loaded = true );
    void SetUseIndex( 
            bool use_index = true, const string & index_name = "", 
            bool force_index = false, bool old_style_index = false );

    /// Allows to dump a snapshot of the object
    /// @todo this doesn't do anything for locality eRemote
    void DebugDump(CDebugDumpContext ddc, unsigned int depth) const;
    
    void DoneDefaults() const;
    
    /// This returns a list of parameters for remote searches.
    typedef ncbi::objects::CBlast4_parameters TBlast4Opts;
    TBlast4Opts * GetBlast4AlgoOpts();
    
    bool operator==(const CBlastOptions& rhs) const;
    bool operator!=(const CBlastOptions& rhs) const;

#endif /* SKIP_DOXYGEN_PROCESSING */
    
    /// Set the program and service name for remote blast.
    void SetRemoteProgramAndService_Blast3(const string & p, const string & s)
    {
        m_ProgramName = p;
        m_ServiceName = s;
    }
    
    /// Get the program and service name for remote blast.
    virtual void GetRemoteProgramAndService_Blast3(string & p, string & s) const
    {
        _ASSERT(m_Remote);
        p = m_ProgramName;
        s = m_ServiceName;
    }

    /// Create a snapshot of the state of this object for internal use of its
    /// data structures (BLAST C++ APIs only)
    const CBlastOptionsMemento* CreateSnapshot() const;
    
    /// If this is true, remote options will ignore "Set" calls.
    void SetDefaultsMode(bool dmode);
    bool GetDefaultsMode() const;
    
private:
    /// Prohibit copy c-tor 
    CBlastOptions(const CBlastOptions& bo);
    /// Prohibit assignment operator
    CBlastOptions& operator=(const CBlastOptions& bo);

    // Pointers to local and remote objects
    
    CBlastOptionsLocal  * m_Local;
    CBlastOptionsRemote * m_Remote;
    
    /// Program Name for Blast3
    string m_ProgramName;
    
    /// Service Name for Blast3
    string m_ServiceName;
    
    /// Defaults mode (remote options will ignore Set ops).
    bool m_DefaultsMode;
    
    /// Auxiliary to throw CBlastExceptions
    /// @param msg message to pass in the exception [in]
    void x_Throwx(const string& msg) const;
    /// Returns QuerySetUpOptions for eLocal objects, NULL for eRemote
    /// @internal
    QuerySetUpOptions * GetQueryOpts() const;
    /// Returns LookupTableOptions for eLocal objects, NULL for eRemote
    LookupTableOptions * GetLutOpts() const;
    /// Returns BlastInitialWordOptions for eLocal objects, NULL for eRemote
    BlastInitialWordOptions * GetInitWordOpts() const;
    /// Returns BlastExtensionOptions for eLocal objects, NULL for eRemote
    BlastExtensionOptions * GetExtnOpts() const;
    /// Returns BlastHitSavingOptions for eLocal objects, NULL for eRemote
    BlastHitSavingOptions * GetHitSaveOpts() const;
    /// Returns PSIBlastOptions for eLocal objects, NULL for eRemote
    PSIBlastOptions * GetPSIBlastOpts() const;
    /// Returns BlastDatabaseOptions for eLocal objects, NULL for eRemote
    BlastDatabaseOptions * GetDbOpts() const;
    /// Returns BlastScoringOptions for eLocal objects, NULL for eRemote
    BlastScoringOptions * GetScoringOpts() const;
    /// Returns BlastEffectiveLengthsOptions for eLocal objects, NULL for 
    /// eRemote
    BlastEffectiveLengthsOptions * GetEffLenOpts() const;

    /// Perform a "deep copy" of Blast options
    /// @param opts Blast options object to copy from.
    void x_DoDeepCopy(const CBlastOptions& opts);

    /// This field is add
    CAutomaticGenCodeSingleton m_GenCodeSingletonVar;

    friend class CBl2Seq;
    friend class CDbBlast;
    friend class CDbBlastTraceback;
    friend class CDbBlastPrelim;
    friend class CEffectiveSearchSpacesMemento;
    
    // Tabular formatting thread needs to calculate parameters structures
    // and hence needs access to individual options structures.
    friend class ::CBlastTabularFormatThread; 

    /// @todo Strive to remove these classes
    friend class ::CTracebackTestFixture;    // unit test class
    friend class ::CBlastSetupTestFixture;        // unit test class
    friend class ::CUniformSearchTest;     // unit test class
    friend class ::CTracebackSearchTestFixture;   // unit test class
};

//#endif /* SKIP_DOXYGEN_PROCESSING */

END_SCOPE(blast)
END_NCBI_SCOPE

/* @} */

/**
  @page blast_opts_cookbook C++ BLAST Options Cookbook

  The purpose of the C++ BLAST options APIs is to provide convenient access to
  the various algorithm options for a variety of users of BLAST as well as a 
  means to validating the options, while isolating them from the details of 
  the CORE BLAST implementation. Please note that these objects are
  instantiated with the default options set and these defaults can be queried 
  via the corresponding accessor method(s).

  @section _basic_opts_usage Basic usage
  For users who only want to perform a single BLAST searches using default 
  options for a specific task (EProgram) \em without modifying the options, 
  one can let the BLAST search classes create 
  and validate the appropriate BLAST options object internally:
  
  @code
  using ncbi::blast;
  try {
      // Task is specified by the eBlastp argument
      CBl2Seq bl2seq(query, subject, eBlastp);
      TSeqAlignVector results = bl2seq.Run();
  } catch (const CBlastException& e) { 
      // Handle exception ... 
  }
  @endcode

  Using the approach above guarantees that the BLAST options will be valid.
  
  An alternative to this approach is to use the CBlastOptionsFactory to create
  a CBlastOptionsHandle object, which allows the caller to set options which
  are applicable to all variants of BLAST (e.g.: E-value threshold, effective
  search space, window size). Furthermore, this approach allows the caller to
  reuse the CBlastOptionsHandle object with multiple BLAST search objects:

  @code
  using ncbi::blast;
  CRef<CBlastOptionsHandle> opts_handle(CBlastOptionsFactory::Create(eBlastn));
  ...
  opts_handle.SetEvalueThreshold(1e-20);
  CBl2Seq bl2seq(query, subjects, opts_handle);
  ...
  opts_handle.SetEvalueThreshold(1e-10);
  CLocalBlast blast(query_factory, opts_handle, seq_src);
  @endcode

  @section _validating_opts Options validation
  The CBlastOptionsHandle classes offers a <tt>Validate</tt> method in
  its interface which is called by the BLAST search classes prior to
  performing the actual search, but users of the C++ BLAST options APIs might
  also want to invoke this method so that any exceptions thrown by the
  BLAST search classes can be guaranteed not originate from an incorrect
  setting of BLAST options. Please note that the <tt>Validate</tt> method 
  throws a CBlastException in case of failure.

  @section _intermediate_opts_usage Intermediate options usage
  For users who want to obtain default options, yet modify the most popular
  options, one should create instances of derived classes of the 
  CBlastOptionsHandle, because these should expose an interface that is 
  relevant to the task at hand (although not an exhaustive interface, for that
  see @ref _advanced_opts_usage):

  @code
  using ncbi::blast;
  CBlastNucleotideOptionsHandle opts_handle;
  opts_handle.SetTraditionalBlastnDefaults();
  opts_handle.SetStrandOption(objects::eNa_strand_plus);
  CBl2Seq bl2seq(query, subject, opts_handle);
  TSeqAlignVector results = bl2seq.Run();
  @endcode

  By using this interface, the likelihood of setting invalid options is
  reduced, but the validity of the options cannot be fully guaranteed.
  @note BLAST help desk and developers reserve the right to determine which 
  options are popular.

  @section _advanced_opts_usage Advanced options usage
  For users who want to have full control over setting the algorithm's options,
  or whose options of interest are not available in any of the classes in the
  CBlastOptionsHandle hierarchy, the <tt>GetOptions</tt> and
  <tt>SetOptions</tt> methods of the CBlastOptionsHandle hierarchy allow 
  access to the CBlastOptions class, the lowest level class in the C++ BLAST 
  options API which contains all options available to all variants of the 
  BLAST algorithm. No guarantees about the validity of the options are made 
  if this interface is used, therefore invoking <tt>Validate</tt> is 
  \em strongly recommended.

  @code
  using ncbi::blast;
  try {
      CBlastProteinOptionsHandle opts_handle;
      opts_handle.SetMatrixName("PAM30");
      opts_handle.SetGapOpeningCost(9);
      opts_handle.SetGapExtensionCost(1);
      opts_handle.SetOptions().SetCompositionBasedStats(eCompositionBasedStats);
      opts_handle.Validate();

      CBl2Seq bl2seq(query, subject, opts_handle);
      TSeqAlignVector results = bl2seq.Run();
  } catch (const CBlastException& e) {
      // Handle exception ...
  }
  @endcode

  @sa @ref blast_opts_cpp_design.

  @author Christiam Camacho <camacho@ncbi.nlm.nih.gov>
 */

/**
  @page blast_opts_cpp_design C++ BLAST Options Design

  @section _blast_opts_cpp_goals Design goals
  - Isolate C++ toolkit users from details of CORE BLAST
  - Allow easy setting of default options for common tasks for which BLAST is
    used
  - Expose in an interface only those options that are relevant to the task at
    hand
  - Provide a means of validating BLAST options
  - Allow 'power' users to have unrestricted access to all BLAST options
  - Design should be flexible to accomodate introduction/removal of options

  @section Components

  - CBlastOptionsFactory:
  This class offers a single static method to create CBlastOptionsHandle
  subclasses so that options that are applicable to all variants of BLAST can
  be inspected or modified. The actual type of the CBlastOptionsHandle returned
  by Create is determined by its EProgram argument. The return
  value of this function is guaranteed to have reasonable defaults set for the
  selected task.

  - CBlastOptionsHandle hierarchy:
  The intent of this class is to encapsulate options that are common to all
  variants of BLAST, from which more specific tasks can inherit the common
  options. The subclasses of CBlastOptionsHandle should present an interface
  that is more specific, i.e.: only contain options relevant to the task at 
  hand, although it might not be an exhaustive interface for all options 
  available for the task. Please note that the initialization of this class' 
  data members follows the template method design pattern, and this should be 
  followed by subclasses also.

  - CBlastOptions:
  This class contains all available BLAST options and it is provided to
  satisfy the design goal of allowing qualified users unrestricted access to
  all BLAST options. Because of this, it is very easy to set incorrect options,
  and hence it should be use sparingly. The use of its <tt>Validate</tt> 
  method is <em>strongly</em> recommended.

  @section _blast_opts_cpp_deficiencies Known deficiencies

  The current design in noticeably weak in fulfilling the last design goal, in
  that it uses an inheritance hierarchy of CBlastOptionsHandle classes to
  provide specific interfaces for tasks, but this approach is breaks when an
  option is applicable to a parent class and not its child.

  Furthermore, the EProgram enumeration is misnamed, as it should convey the
  notion of a task, similar to those exposed in the BLAST web page.

  @section _blast_opts_cpp_future Future plans
  A redesign of the C++ BLAST options API might be available in the future to
  overcome the deficiencies of the current APIs. Additional design goals
  include:
  - Consistent local/remote behavior
  - Provide distinction between algorithm options and application options
  - Provide well defined guarantees about the validity of BLAST options
  - <em>Easy to use correctly, difficult to use incorrectly</em>

  @author Christiam Camacho <camacho@ncbi.nlm.nih.gov>
 */

#endif  /* ALGO_BLAST_API___BLAST_OPTION__HPP */
