/* Copyright (c) 2018
   Charles Jordan (Hokkaido University, Sapporo, Japan),
   Michael Joswig, Lars Kastner (Technische Universitaet Berlin, Germany)

   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 3, or (at your option) any
   later version: http://www.gnu.org/licenses/gpl.txt.

   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.
-----------------------------------------------------------------------------
*/

#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
