#ifndef MESSAGE_H
#define MESSAGE_H

#include <cassert>
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;

#include <typedefs.h>


class message;

/*!
\brief  Basic message writing.

Support for singleton.

Two ways to use with operator << - either through 
 operator () with ostream or 
 cast to base (message&) - which does have template
 issues.

// http://www.velocityreviews.com/forums/t279958-stdendl-type-unknown.html
\par Example - with casting down and template issue
\verbatim
  (message&)err << x << endl<char, char_traits<char> >;
\endverbatim
*/
class message
{
public:

  /** The current global message stream. */
  static message *global;

  /** This instance becomes the global message state. */
  void globalset()
    { global = this; }

  /** Write to the stream. */
  virtual ostream& operator()()=0; 

  /** Cleanup. */
  virtual ~message() {};

  /** Optionally pre process before << operator. */
  virtual void pre() {};
  /** Optionally post process before << operator. */
  virtual void post() {};
  /** Write with pre and post processing. */

  /** As I do not want to deal with streams pre and
    post put in for flexibility.  */ 
  template< typename T >
  message& operator << (T& x)
  { 
    pre(); 
    (*this)() << x; 
    post(); 
    return *this; 
  }

};

/*!
\brief The global message stream as an object.
*/
/*
class messageglobal : public message
{
public:
  
  // Write to the global stream. 
  ostream& operator()()
    { return (*message::global)(); }
};
*/

/** Access the global message stream. */
message& messageglobal();

/*!
\brief The cout stream as an object.
*/
class messagecout : public message
{
public:

  /** Write to the cout stream. */
  ostream& operator()() 
    { return cout; }
};

/*!
\brief Open a file for writing.

Just do it attitude to file opening, no error checking.

\par Example
\verbatim
  // Append to end of the file.
  messagefile err("error.txt",false);
  ...
  err() << "error: something happened." << endl;
\endverbatim

Without using a global variable.
\par Example
\verbatim
// Create a new file.
messagefile("error.txt",true);
...
messagefile("error.txt")() << "error: something happened." << endl;
\endverbatim
*/
class messagefile : public message
{
  messagefile();
  fstream* os;
public:

  /** Either append or write a new file. */
  messagefile
  (
    stringc& filename, 
    boolc killprevfile=false,  
    boolc binary=false
  );
  /** Cleanup. */
  ~messagefile();

  /** Write to the file stream. */
  ostream& operator()(); 
};


/*!
\brief Each output with << is added to a list of strings.
\par Example
\verbatim
  messagelist err;
  (message&)err << "a" << "love" << "boat" << "at" << "work";
\endverbatim
*/
class messagelist : public message
{
protected:
  /** buffer */ 
  stringstream ss;
public:

  /** List of strings. */
  vector<string> vi;

  /** Clear buffer. */ 
  void pre();
  /** Add string. */
  void post();
  
  /** << access the stringstream. */ 
  ostream& operator()();

};


#endif



