////////////////////////////////////////////////////////////////
//
// Copyright (C) 2005 Affymetrix, Inc.
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License
// (version 2.1) as published by the Free Software Foundation.
//
// This library 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 Lesser General Public License
// for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////

/**
 * @file   TextFileCheck.h
 * @brief  Class for checking two text files for equality.
 */
#ifndef TEXTFILECHECK_H
#define TEXTFILECHECK_H

//
#include "util/Fs.h"
#include "util/LineFile.h"
#include "util/RegressionCheck.h"
//
#include <string>

/**
 * Class for testing that two text files are equal, except
 * for line endings.
 */
class TextFileCheck : public RegressionCheck
{
public:
  /**
   * Constructor.
   *
   * @param generatedFile File generated by application.
   * @param goldFile Comparison file, assumed to be correct.
   * @param skipLines Number of lines to skip.
   */
  TextFileCheck(const std::string &generatedFile, const std::string &goldFile, const unsigned int skipLines)
    : m_GeneratedFile(generatedFile), m_GoldFile(goldFile), m_SkipLines(skipLines)    {
    m_Name = Fs::basename(generatedFile);
    m_HeaderDelimiter = "";
  }

  TextFileCheck(const std::string &generatedFile, const std::string &goldFile, const std::string &headerDelimiter)
    : m_GeneratedFile(generatedFile), m_GoldFile(goldFile), m_SkipLines(0), m_HeaderDelimiter(headerDelimiter) {
    m_Name = Fs::basename(generatedFile);
  }


  /**
   * Check that the two files are the same.
   *
   * @param errorMsg Error message generated if the test fails.
   * @return bool Returns true if files the same, else false.
   */
  bool check(std::string& errorMsg)  {
    // Open files.
    LineFile generatedStream;
    generatedStream.open(m_GeneratedFile, false);
    if(! generatedStream.is_open()) {
      errorMsg = "Unable to open generated file " + m_GeneratedFile;
      return false;
    }
    LineFile goldStream;
    goldStream.open(m_GoldFile, false);
    if(! goldStream.is_open()) {
      errorMsg = "Unable to open gold file " + m_GoldFile;
      return false;
    }

    unsigned int lineCount = 0;
    bool inHeader = !m_HeaderDelimiter.empty();
    bool goldPastHeader = false;
    bool genPastHeader = false;

    std::string goldLine, generatedLine;
    while(! goldStream.eof() && ! goldStream.fail()) {
      if(!inHeader || !goldPastHeader)
        goldStream.getline(goldLine);
      if(!inHeader ||  !genPastHeader)
        generatedStream.getline(generatedLine);
      if(generatedStream.eof() && ! goldStream.eof()) {
        errorMsg = "The generated file, " + m_GeneratedFile
                   + ", has fewer lines than the gold file, " + m_GoldFile;
        return false;
      }
      if(inHeader) {
        if(!goldPastHeader &&
            ((goldLine.size() < m_HeaderDelimiter.size()) ||
             (goldLine.substr(0, m_HeaderDelimiter.size()) != m_HeaderDelimiter))) {
          goldPastHeader = true;
        }
        if(!genPastHeader &&
            ((generatedLine.size() < m_HeaderDelimiter.size()) ||
             (generatedLine.substr(0, m_HeaderDelimiter.size()) != m_HeaderDelimiter))) {
          genPastHeader = true;
        }
        inHeader = !goldPastHeader || !genPastHeader;
      }
      // Skip header lines which need not be equal.
      if((++lineCount > m_SkipLines) && !inHeader) {
        if(goldLine != generatedLine) {
          errorMsg = "Mismatch reading generated file " + m_GeneratedFile
                     + ":\ngold line: '" + goldLine
                     + "'\ngenerated line: '" + generatedLine + "'";
          return false;
        }
      }
    }
    // The two files should reach eof at the same time.
    if(! generatedStream.eof()) {
      errorMsg = "The generated file, " + m_GeneratedFile
                 + ", has more lines than the gold file, " + m_GoldFile;
      return false;
    }

    return true;
  }


private:
  /// Name of file generated by application being tested.
  std::string m_GeneratedFile;
  /// Name of file assumed to be correct.
  std::string m_GoldFile;
  /// Number of lines to skip.
  const unsigned int m_SkipLines;
  /// Header Delimiter
  std::string m_HeaderDelimiter;

};

#endif /* TEXTFILECHECK_H */
