// This file is part of AspectC++.
// Copyright (C) 1999-2015  The AspectC++ developer team.
//                                                                
// 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                                            

#ifndef ACBASE_ErrorStream_H
#define ACBASE_ErrorStream_H

/** \file
 * Error stream implementation. */

#include <sstream>

namespace ACBase {

enum ErrorSeverity { sev_none, sev_message, sev_warning, sev_error, sev_fatal };
std::string to_string(ErrorSeverity sev);

enum ErrorStreamEnd { endMessage };

struct ErrorLocation {
  std::string filename_;
  unsigned line_;
  unsigned column_;
  ErrorLocation() = default;
  ErrorLocation(const std::string &filename, unsigned line = 0, unsigned column = 0) :
    filename_(filename), line_(line), column_(column) {}
  bool is_valid() const { return !filename_.empty(); }
};
std::string to_string(const ErrorLocation &loc);

/** \class ErrorStream
 * An error stream prints out an error message as soon as it is complete.
 * It also stores the maximum error severity value.
 * The error stream can be reset to its initial state. */
class ErrorStream {
  ErrorSeverity m_maxSeverity;
  ErrorSeverity m_currSeverity;
  ErrorLocation m_location;
  std::ostringstream m_msg;

  /* Clear the current message including location, text, and severity */
  void clear();

protected:
  /** Write the collected message to the output stream std::cerr.
   * This function might be refined by a derived class.
   * \param msg The collected message including the severity (if used) */
  virtual void output(const std::string &msg);

  ErrorSeverity message_severity() const { return m_currSeverity; }

public:
  ErrorStream() : m_maxSeverity(sev_none), m_currSeverity(sev_none) {}

  /** Set the location the error occurred.
   * \param location The error location.
   * \return A reference to this error stream. */
  ErrorStream &operator <<(const ErrorLocation &location);

  /** Add a text representation of some object to the error stream
   * \param obj The object to add.
   * \return A reference to this error stream. */
  template<typename T> ErrorStream &operator << (T obj) {
    m_msg << obj;
    return *this;
  }
  ErrorStream &operator << (ErrorStreamEnd obj);
  ErrorStream &operator << (ErrorSeverity sev);

  /** Reset the error stream to its initial state.
   * \return the current maximum error severity before resetting to sev_none
  */
  ErrorSeverity reset();

  /** Get the current error severity.
   * \return The error severity. */
  ErrorSeverity severity() const { return m_maxSeverity; }
  /** Set a new severity for all following messages.
   * \param sev The new severity. */
  ErrorSeverity set_severity(ErrorSeverity sev) {
    ErrorSeverity old = m_maxSeverity;
    m_maxSeverity = sev;
    return old;
  }
};

} // namespace ACBase

#endif /* ACBASE_ErrorStream_H */
