////////////////////////////////////////////////////////////////////////////////
// 
// Message.hh 
//
//    produced: 2024-05-04 jr
//
////////////////////////////////////////////////////////////////////////////////
#ifndef MESSAGE_HH
#define MESSAGE_HH

#include <iostream>
#include <mutex>

#include "ContainerIO.hh"

namespace topcom {

  class IO_sync {
  public:
    static std::mutex mutex;
  };
  
  class Message {
  private:
    std::ostream*                       _ostptr;
  public:
    inline Message() : _ostptr(nullptr) {}
    inline Message(std::ostream& ost, bool activate = true) : _ostptr(activate ? &ost : nullptr) {}
    inline Message(std::ostream* ostptr, bool activate = true) : _ostptr(activate ? ostptr : nullptr) {}
    inline Message& activate(std::ostream& ost) { _ostptr = &ost; return *this; }
    inline Message& deactivate() { _ostptr = nullptr; return *this; }
    inline bool is_active() const { return (_ostptr != nullptr); }

    inline void lock() { IO_sync::mutex.lock(); }
    inline void unlock() { IO_sync::mutex.unlock(); }

    // short-cut functions for constant strings:
    inline Message& print_topcomheader() {
      *this << std::endl;
      *this << "==================================================================\n";
      *this << "--------------------- " << PACKAGE << " version " << VERSION << " -----------------------\n";
      *this << "   Triangulations of Point Configurations and Oriented Matroids   \n";
      *this << "------------------------ by Joerg Rambau -------------------------\n";
      *this << "==================================================================\n";
      *this << std::endl;
#ifdef DEBUG
#ifdef TOPCOM_CONTAINERS
      *this << "       -- using STL containers for hash tables --" << std::endl;
#endif
#ifdef TOPCOM_SYMMETRIES
      *this << "       -- using TOPCOM containers for symmetries  --" << std::endl;
#endif
#ifdef TOPCOM_FLIPS
      *this << "       --    using TOPCOM containers for flips    --" << std::endl;
#endif
#ifdef TOPCOM_CHIROTOPE
      *this << "       -- using TOPCOM containers for chirotopes  --" << std::endl;
#endif
      *this << std::endl;
#endif
      return *this;
    }
    
    inline Message& print_hseparator() {
      *this << "---------------------------------"
	    << "---------------------------------"
	    << "---------------------------------"
	    << "---------------------------------"
	    << "---------------------------------"
	    << "-------------------" << std::endl;
      return *this;
    }

    inline Message& print_dumpseparator() {
      *this << "#################################"
	    << "#################################"
	    << "#################################"
	    << "#################################"
	    << "#################################"
	    << "###################" << std::endl;
      return *this;
    }
    
    // friends for stream output:
    template <class T>
    friend Message& operator<<(Message&, const T&);
    friend Message& operator<<(Message&, std::ostream&(*)(std::ostream&));
  };

  template <class T>
  inline Message& operator<<(Message& msg, const T& output) {
    if (msg.is_active()) {
      *(msg._ostptr) << output;
    }
    return msg;
  }

  inline Message& operator<<(Message& msg, std::ostream&(*fp)(std::ostream&)) {
    if (msg.is_active()) {
      (*fp)(*msg._ostptr);
    }
    return msg;
  }

  class MessageStreams {
  private:
    static Message _result;
    static Message _forced;
    static Message _verbose;
    static Message _debug;
  public:
    static Message& result () { return _result;  }
    static Message& forced () { return _forced;  }
    static Message& verbose() { return _verbose; }
    static Message& debug  () { return _debug;   }
  };
  
  namespace message {

    // the following function define stream manipulators for messages:
    inline std::ostream& lock(std::ostream& ost) {
      ost.flush();
      IO_sync::mutex.lock();
      return ost;
    }

    inline std::ostream& unlock(std::ostream& ost) {
      ost.flush();
      IO_sync::mutex.unlock();
      return ost;
    }
    
    inline std::ostream& tab(std::ostream& ost) {
      ost << '\t';
      return ost;
    }
  }; // namespace message
  
}; // namespace topcom



#endif

// eof Message.hh
