text: // --------------------------------------------------------------------------
  //                   OpenMS -- Open-Source Mass Spectrometry
  // --------------------------------------------------------------------------
  // Copyright The OpenMS Team -- Eberhard Karls University Tuebingen,
  // ETH Zurich, and Freie Universitaet Berlin 2002-2013.
  //
  // This software is released under a three-clause BSD license:
  //  * Redistributions of source code must retain the above copyright
  //    notice, this list of conditions and the following disclaimer.
  //  * Redistributions in binary form must reproduce the above copyright
  //    notice, this list of conditions and the following disclaimer in the
  //    documentation and/or other materials provided with the distribution.
  //  * Neither the name of any author or any participating institution
  //    may be used to endorse or promote products derived from this software
  //    without specific prior written permission.
  // For a full list of authors, refer to the file AUTHORS.
  // --------------------------------------------------------------------------
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  // ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING
  // INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  //
  // --------------------------------------------------------------------------
  // $Maintainer: Stephan Aiche $
  // $Authors: Clemens Groepl, Stephan Aiche $
  // --------------------------------------------------------------------------
  
  #ifndef OPENMS_CONCEPT_FUZZYSTRINGCOMPARATOR_H
  #define OPENMS_CONCEPT_FUZZYSTRINGCOMPARATOR_H
  
  #include <OpenMS/CONCEPT/Types.h>
  #include <OpenMS/DATASTRUCTURES/String.h>
  #include <OpenMS/DATASTRUCTURES/StringListUtils.h>
  
  #include <cstdlib> // for strtod()
  #include <fstream>
  #include <iostream>
  #include <cctype> // for isspace()
  #include <limits> // for NaN
  #include <sstream>
  #include <map>
  
  #ifdef OPENMS_HAS_STREAM_EXTRACTION_BUG
  #include <boost/lexical_cast.hpp>
  #endif // OPENMS_HAS_STREAM_EXTRACTION_BUG
  
  namespace OpenMS
  {
    namespace Internal
    {
      namespace ClassTest
      {
        void OPENMS_DLLAPI testStringSimilar(const char * file, 
                                             int line,
                                             const std::string & string_1,
                                             const char * string_1_stringified,
                                             const std::string & string_2,
                                             const char * string_2_stringified);
  
        bool OPENMS_DLLAPI isFileSimilar(const std::string &, 
                                         const std::string &);
      }
    }
  
    /**
      @brief Fuzzy comparison of strings, tolerates numeric differences.
    */
    class OPENMS_DLLAPI FuzzyStringComparator
    {
  
      friend void OPENMS_DLLAPI
      Internal::ClassTest::testStringSimilar(
        const char * file,
        int line,
        const std::string & string_1,
        const char * string_1_stringified,
        const std::string & string_2,
        const char * string_2_stringified);
  
      friend bool OPENMS_DLLAPI
      Internal::ClassTest::isFileSimilar(const std::string &,
                                         const std::string &);
  
      /// %Internal exception class.
      struct AbortComparison
      {
      };
  
  public:
  
      ///@name the fabulous four
      //@{
  
      /// Constructor
      FuzzyStringComparator();
  
      /// Destructor
      virtual
      ~FuzzyStringComparator();
  
      /// Copy constructor intentionally not implemented
      FuzzyStringComparator(const FuzzyStringComparator & rhs);
  
      /// Assignment operator intentionally not implemented
      FuzzyStringComparator & operator=(const FuzzyStringComparator & rhs);
  
      //@}
  
      /// Acceptable relative error (a number >= 1.0)
      const double & getAcceptableRelative() const;
      
      /// Acceptable relative error (a number >= 1.0)
      void setAcceptableRelative(const double rhs);
  
      /// Acceptable absolute difference (a number >= 0.0)
      const double & getAcceptableAbsolute() const;
  
      /// Acceptable absolute difference (a number >= 0.0)
      void setAcceptableAbsolute(const double rhs);
  
      /// White list.  If both lines contain the same element from this list, they are skipped over.
      const StringList & getWhitelist() const;
  
      /// White list.  If both lines contain the same element from this list, they are skipped over.
      StringList & getWhitelist();
  
      /// White list.  If both lines contain the same element from this list, they are skipped over.
      void setWhitelist(const StringList & rhs);
  
      /**
        @brief verbose level
  
        - 0 = very quiet mode (absolutely no output)
        - 1 = quiet mode (no output unless differences detected)
        - 2 = default (include summary at end)
        - 3 = continue after errors
      */
      const int & getVerboseLevel() const;
  
      /**
        @brief verbose level
  
        - 0 = very quiet mode (absolutely no output)
        - 1 = quiet mode (no output unless differences detected)
        - 2 = default (include summary at end)
        - 3 = continue after errors
       */
      void setVerboseLevel(const int rhs);
  
      /**
        @brief get tab width (for column numbers)
      */
      const int & getTabWidth() const;
  
      /**
        @brief set tab width (for column numbers)
      */
      void setTabWidth(const int rhs);
  
      /**
        @brief get first column (for column numbers)
      */
      const int & getFirstColumn() const;
  
      /**
        @brief set first column (for column numbers)
      */
      void setFirstColumn(const int rhs);
  
      /**
        @brief Log output is written to this destination.
  
        The default is std::cout. Use std::ostringstream etc. to save the output
        in a string.
      */
      std::ostream & getLogDestination() const;
  
      /**
        @brief Log output is written to this destination.
  
        The default is std::cout. Use std::ostringstream etc. to save the output
        in a string.
  
        @internal There seems to be an issue with this under Windows, see comment
        in FuzzyStringComparator_test.C
  
      */
      void setLogDestination(std::ostream & rhs);
  
      /**
        @brief Compare two strings.
  
        This compares all lines of the input.
  
        @return true in case of no differences found
      */
      bool compareStrings(std::string const & lhs, std::string const & rhs);
  
      /**
        @brief Compare two streams of input.
  
        This compares all lines of the input.  Intended to be used for file
        streams.
  
        @return true in case of no differences found
      */
      bool compareStreams(std::istream & input_1, std::istream & input_2);
  
      /**
        @brief Simple diff-like application to compare two input files.
        Numeric differences are tolerated up to a certain ratio or absolute
        difference.
  
        where
        @param filename_1 first input file
        @param filename_2 second input file
        @return true in case of no differences found
  
        @sa ratio_max_allowed_
        @sa absdiff_max_allowed_
        @sa verbose_level_
      */
      bool compareFiles(const std::string & filename_1, 
                        const std::string & filename_2);
  
  protected:
  
      /**
        @brief Compare two lines of input.
  
        This implements the core functionality.  Intended to be used for a single
        line of input.
  
        @return true (non-zero) in case of success
       */
      bool compareLines_(std::string const & line_str_1, std::string const & line_str_2);
  
      /// Report good news.
      void reportSuccess_() const;
  
      /// Report bad news.
      /// @exception AbortComparison
      void reportFailure_(char const * const message) const;
  
      /// Write info about hits in the whitelist
      void writeWhitelistCases_(const std::string & prefix) const;
  
      /// read the next line in input stream, skipping over empty lines
      /// and lines consisting of whitespace only
      void readNextLine_(std::istream & input_stream, std::string & line_string, int & line_number) const;
  
      /// opens and checks an input file stream std::ifstream
      bool openInputFileStream_(const std::string & filename, std::ifstream & input_stream) const;
  
      /// Log and results output goes here
      std::ostream * log_dest_;
  
      /// Name of first input e.g., filename
      std::string input_1_name_;
      /// Name of second input e.g., filename
      std::string input_2_name_;
  
      /// Stores information about the current input line (i.e., stream for the line and the current position in the stream)
      struct InputLine
      {
        std::stringstream line_;
        std::ios::pos_type line_position_;
  
        InputLine();
  
        /// Initialize the input line to the passed string
        void setToString(const std::string & s);
  
        /// Save current position of the stream
        void updatePosition();
  
        /// Resets the stream to the last saved position
        void seekGToSavedPosition();
  
        /**
          @brief Convert to bool
  
          The function indicates success when none of the error flags (either failbit or badbit of the nested std::stringstream) are set.
  
          @return False on error, true otherwise.
        */
        bool ok() const;
      };
  
      InputLine input_line_1_;
      InputLine input_line_2_;
  
      int line_num_1_;
      int line_num_2_;
  
      int line_num_1_max_;
      int line_num_2_max_;
  
      std::string line_str_1_max_;
      std::string line_str_2_max_;
  
      /// Maximum ratio of numbers allowed, see @em ratio_max_.
      double ratio_max_allowed_;
  
      /// Maximum ratio of numbers observed so far, see @em ratio_max_allowed_.
      double ratio_max_;
  
      /// Maximum absolute difference of numbers allowed, see @em absdiff_max_.
      double absdiff_max_allowed_;
  
      /// Maximum difference of numbers observed so far, see @em absdiff_max_allowed_.
      double absdiff_max_;
  
      /// Stores information about characters, numbers, and white spaces loaded from the InputStream
      struct StreamElement_
      {
        double number;
        unsigned char letter;
        bool is_number;
        bool is_space;
  
        StreamElement_();
  
        /// reset all elements of the element to default value
        void reset();
  #ifdef OPENMS_HAS_STREAM_EXTRACTION_BUG
        /**
          @brief Tries to extract digits from the stream in InputLine.
        
          @param input_line The stream from which the digits should be extracted.
          @param target_buffer The target string where the digits should be stored.
          @param c_buffer The current peek of the stream.
          
          @return Returns true if at least one digit was extracted from the stream.
        */
        bool readdigits(InputLine & input_line, std::string & target_buffer, char & c_buffer);
        
        /** 
          @brief Try to extract a double from the InputLine
        
          @param input_line The input line where the double should be extracted
          @param target Target variable where the double should be stored
          @return True if extraction succeeded, false otherwise.
        */
        bool tryExtractDouble(InputLine & input_line, double & target);
  #endif
        /// Read the next element from an InputLine and update the InputLine accordingly
        void fillFromInputLine(InputLine & input_line);
      };
  
      /// Stores information about characters, numbers, and white spaces loaded from the first input stream
      StreamElement_ element_1_;
      /// Stores information about characters, numbers, and white spaces loaded from the second input stream
      StreamElement_ element_2_;
  
      /// Wrapper for the prefix information computed for the failure report
      struct PrefixInfo_
      {
        OpenMS::String prefix;
        OpenMS::String prefix_whitespaces;
        int line_column;
  
        PrefixInfo_(const InputLine & input_line, const int tab_width_, const int first_column_);
      };
  
      bool is_absdiff_small_;
  
      int verbose_level_;
      int tab_width_;
      int first_column_;
  
      /**
        @brief Has comparison been successful so far?  Note: this flag is
               changed in reportFailure_();
       */
      bool is_status_success_;
  
      /// use a prefix when reporting
      bool use_prefix_;
  
      /// Whitelist
      StringList whitelist_;
      /// Occurences of whitelist entries
      std::map<String, UInt> whitelist_cases_;
  
    }; // class FuzzyStringComparator
  
  } //namespace OpenMS
  
  #endif //OPENMS_CONCEPT_FUZZYSTRINGCOMPARATOR_H
  