#ifndef OUTPUTWRAPPERS_HH
#define OUTPUTWRAPPERS_HH

#include <sstream>
#include <iostream>

#ifdef MTS
void put_error(const std::stringstream& stb);
void report_state(const std::stringstream& stb);
#endif
void err_print(const std::stringstream& stb);

template<bool firstWorkerOnly>
struct CerrWrapper {
   // Set print function to default. Implementation is located in 
   // CommandlineOptions.cc
   void (*print_func)(const std::stringstream&) = &err_print;

   void emit(const std::stringstream& stb){
      (*print_func)(stb);
   }

#ifdef MTS
   // Replace function pointers for MTS case.
   void redirect() {
      if (firstWorkerOnly)
         print_func = &report_state;
      else
         print_func = &put_error;
   }
#endif
};



template <typename T, bool firstWorkerOnly>
CerrWrapper<firstWorkerOnly>& operator<< (CerrWrapper<firstWorkerOnly> &s, const T &x) {
   std::stringstream stb;
   stb << x;
   s.emit(stb);
   return s;
}

template <bool firstWorkerOnly>
CerrWrapper<firstWorkerOnly>& operator<< (CerrWrapper<firstWorkerOnly> &s, std::ostream& (*f)(std::ostream &)){
   std::stringstream stb;
   stb << f;
   s.emit(stb);
   return s;
}

template <bool firstWorkerOnly>
CerrWrapper<firstWorkerOnly>& operator<< (CerrWrapper<firstWorkerOnly> &s, std::ostream& (*f)(std::ios &)){
   std::stringstream stb;
   stb << f;
   s.emit(stb);
   return s;
}

template <bool firstWorkerOnly>
CerrWrapper<firstWorkerOnly>& operator<< (CerrWrapper<firstWorkerOnly> &s, std::ostream& (*f)(std::ios_base &)){
   std::stringstream stb;
   stb << f;
   s.emit(stb);
   return s;
}

extern CerrWrapper<false> cerrWrap;
extern CerrWrapper<true> cerrFirstWorker;

#endif
