//this file looks like plain C, but it's actually -*- c++ -*-
#ifndef __TQ_MESSAGESTREAM__
#define __TQ_MESSAGESTREAM__

#include <iostream>
#include <stdarg.h>
#include "QFramework/TQStringUtils.h"
#include "TClass.h"
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <initializer_list>

class TQMessageStream {
protected:
  std::ostream* stream;
  mutable bool owner;
  bool colors;
  TString endl;
  std::stringstream buffer;
  bool useBuffer;

  bool overhang;
  TString tmpString;
  TString filename;

public:
  inline std::ostream& activeStream(){
    if(this->useBuffer || !this->stream) return this->buffer;
    return *this->stream;
  }

  TString getStatusString();

  const TString& getFilename();
  TString getMessages();
  void clearMessages();
  void close();
  bool open(const TString& fname, bool append = false);
  void reopen(bool append = true);
  bool isGood();
  bool isFile();
  bool isCOUT();
  bool isCERR();
  void setLineEnd(const TString& s);
  TString getLineEnd();
  void absorb(const TQMessageStream& other);

  void newline();
  void newlines(size_t n);

  TQMessageStream();
  TQMessageStream(std::ostream& _stream, bool _owner = false, bool _colors=true);
  TQMessageStream(std::ostream* _stream, bool _owner = false, bool _colors=true);
  TQMessageStream(const TString& filename, bool _colors=false);
  ~TQMessageStream();

  //#ifndef __CINT__
  TQMessageStream& operator=(const TQMessageStream& other);

  // If you change this enum, make sure to initialize messageTypeAll and
  // messageTypesAlert correctly in cxx file.
  enum MessageType {
    DEBUG,VERBOSE,INFO,WARNING,ERROR,CRITICAL,BREAK
  };
  static std::initializer_list<TQMessageStream::MessageType> messageTypesAll;
  static std::initializer_list<TQMessageStream::MessageType> messageTypesAlert;

  enum InfoType {
    OK,FAIL,WARN,PENDING
  };

  void startProcessInfo (TQMessageStream::MessageType type, int lineWidth, const TString& align, TString fmt, ...);
  void endProcessInfo (TQMessageStream::InfoType result);
  void startBuffer();
  void flushBuffer();

  void sendMessage (TQMessageStream::MessageType type, TString, ...);
  void sendFileLineMessage (TQMessageStream::MessageType type, const TString& file, int line, TString fmt, ...);
  void sendClassFunctionMessage (TQMessageStream::MessageType type, TClass* tclass, const TString& fname, TString fmt, ...);
  void sendClassFunctionArgsMessage (TQMessageStream::MessageType type, TClass* tclass, const TString& fname, const TString& fargs, TString fmt, ...);
  void sendFunctionArgsMessage (TQMessageStream::MessageType type, const TString& fname, const TString& fargs, TString fmt, ...);
  void sendFunctionMessage (TQMessageStream::MessageType type, const TString& fname, TString fmt, ...);

  TString formatMessage (TQMessageStream::MessageType type, TString fmt, ...);
  TString formatFileLineMessage (TQMessageStream::MessageType type, const TString& file, int line, TString fmt, ...);
  TString formatClassFunctionMessage (TQMessageStream::MessageType type, TClass* tclass, const TString& fname, TString fmt, ...);
  TString formatClassFunctionArgsMessage (TQMessageStream::MessageType type, TClass* tclass, const TString& fname, const TString& fargs, TString fmt, ...);
  TString formatFunctionArgsMessage (TQMessageStream::MessageType type, const TString& fname, const TString& fargs, TString fmt, ...);
  TString formatFunctionMessage (TQMessageStream::MessageType type, const TString& fname, TString fmt, ...);

  static unsigned int getGlobMessageCount(TQMessageStream::MessageType type);
  static bool printGlobMessageCount(TQMessageStream::MessageType type, bool onlyNonZero = false);
  static void printGlobMessageCount();
  static void printGlobAlertMessageCount();
  void resetTmpMessageCount();
  void writeMessagesToStdout();

  //#endif

protected:

  //#ifndef __CINT__
  inline TString getInfoTypeString(InfoType type){
    switch(type){
    case TQMessageStream::OK:
      return colors ? TQStringUtils::makeBoldWhite("[") + TQStringUtils::makeBoldGreen(" OK ") + TQStringUtils::makeBoldWhite("]") : "[ OK ]";
    case TQMessageStream::WARN:
      return colors ? TQStringUtils::makeBoldWhite("[") + TQStringUtils::makeBoldYellow("WARN") + TQStringUtils::makeBoldWhite("]") : "[WARN]";
    case TQMessageStream::FAIL:
      return colors ? TQStringUtils::makeBoldWhite("[") + TQStringUtils::makeBoldRed("FAIL") + TQStringUtils::makeBoldWhite("]") : "[FAIL]";
    case TQMessageStream::PENDING:
      return colors ? TQStringUtils::makeBoldWhite("[") + TQStringUtils::makeBoldWhite(" .. ") + TQStringUtils::makeBoldWhite("]") : "[ .. ]";
    }
    return colors ? TQStringUtils::makeBoldWhite("[") + TQStringUtils::makeBoldPink(" ?? ") + TQStringUtils::makeBoldWhite("]") : "[ ?? ]";
  }

  inline TString getMessageTypeString(MessageType type){
    if (colors)
      return TQMessageStream::getMessageTypeString_colors(type);
    return TQMessageStream::getMessageTypeString_noColors(type);
  }

  static inline TString getMessageTypeString_colors(MessageType type){
    switch(type){
    case TQMessageStream::DEBUG:
      return TQStringUtils::makeBoldPink("DEBUG");
    case TQMessageStream::VERBOSE:
      return TQStringUtils::makeBoldPink("INFO");
    case TQMessageStream::INFO:
      return TQStringUtils::makeBoldWhite("INFO");
    case TQMessageStream::WARNING:
      return TQStringUtils::makeBoldYellow("WARNING");
    case TQMessageStream::ERROR:
      return TQStringUtils::makeBoldRed("ERROR");
    case TQMessageStream::CRITICAL:
      return TQStringUtils::makeBoldRed("CRITICAL");
    case TQMessageStream::BREAK:
      return TQStringUtils::makeBoldRed("BREAK");
    }
    return "UNKNOWN MESSAGE TYPE";
  }

  static inline TString getMessageTypeString_noColors(MessageType type){
    switch(type){
    case TQMessageStream::DEBUG:
      return "DEBUG";
    case TQMessageStream::VERBOSE:
      return "INFO";
    case TQMessageStream::INFO:
      return "INFO";
    case TQMessageStream::WARNING:
      return "WARNING";
    case TQMessageStream::ERROR:
      return "ERROR";
    case TQMessageStream::CRITICAL:
      return "CRITICAL";
    case TQMessageStream::BREAK:
      return "BREAK";
    }
    return "UNKNOWN MESSAGE TYPE";
  }

  inline TString formatMessageContentText(MessageType type, const TString& text){
    switch(type){
    case TQMessageStream::DEBUG:
      return text;
    case TQMessageStream::VERBOSE:
      return text;
    case TQMessageStream::INFO:
      return text;
    case TQMessageStream::WARNING:
      return colors ? TQStringUtils::makeBoldWhite(text) : text;
    case TQMessageStream::ERROR:
      return colors ? TQStringUtils::makeBoldWhite(text) : text;
    case TQMessageStream::CRITICAL:
      return colors ? TQStringUtils::makeBoldYellow(text) : TQStringUtils::makeUppercase(text);
    case TQMessageStream::BREAK:
      return colors ? TQStringUtils::makeBoldRed(text) : TQStringUtils::makeUppercase(text);
    }
    return text;
  }
  inline TString formatMessageMetaText(MessageType type, const TString& text){
    switch(type){
    case TQMessageStream::DEBUG:
      return text;
    case TQMessageStream::VERBOSE:
      return text;
    case TQMessageStream::INFO:
      return text;
    case TQMessageStream::WARNING:
      return colors ? TQStringUtils::makeBoldWhite(text) : text;
    case TQMessageStream::ERROR:
      return colors ? TQStringUtils::makeBoldWhite(text) : text;
    case TQMessageStream::CRITICAL:
      return colors ? TQStringUtils::makeBoldWhite(text) : TQStringUtils::makeUppercase(text);
    case TQMessageStream::BREAK:
      return colors ? TQStringUtils::makeBoldRed(text) : TQStringUtils::makeUppercase(text);
    }
    return text;
  }
  inline void triggerMessageAction(MessageType type){
    // this line takes care that "refreshing lines" will never overlap the last message
    if(overhang && this->isCOUT()){
      this->overhang = false;
    }
    switch(type){
    case TQMessageStream::DEBUG:
      this->activeStream().flush();
      break;
    case TQMessageStream::ERROR:
      this->activeStream().flush();
      break;
    case TQMessageStream::BREAK:
      *(this->stream) << (colors ? TQStringUtils::makeBoldRed("EXIT") : "EXIT") << std::endl;
      this->flushBuffer();
      exit(1);
      break;
    default:
      return;
    }
  }
  //#endif

  std::map<TQMessageStream::MessageType, unsigned int> tmpMessageCounter;
  void countTmpMessage(TQMessageStream::MessageType type, int increment = 1);
  static std::map<TQMessageStream::MessageType, unsigned int> globMessageCounter;
  static void countGlobMessage(TQMessageStream::MessageType type, int increment = 1);
  static void uncountGlobMessage(TQMessageStream::MessageType type);
  void countMessage(TQMessageStream::MessageType type);
  void addTmpMessageCountToGlobal();

};

#endif
 TQMessageStream.h:1
 TQMessageStream.h:2
 TQMessageStream.h:3
 TQMessageStream.h:4
 TQMessageStream.h:5
 TQMessageStream.h:6
 TQMessageStream.h:7
 TQMessageStream.h:8
 TQMessageStream.h:9
 TQMessageStream.h:10
 TQMessageStream.h:11
 TQMessageStream.h:12
 TQMessageStream.h:13
 TQMessageStream.h:14
 TQMessageStream.h:15
 TQMessageStream.h:16
 TQMessageStream.h:17
 TQMessageStream.h:18
 TQMessageStream.h:19
 TQMessageStream.h:20
 TQMessageStream.h:21
 TQMessageStream.h:22
 TQMessageStream.h:23
 TQMessageStream.h:24
 TQMessageStream.h:25
 TQMessageStream.h:26
 TQMessageStream.h:27
 TQMessageStream.h:28
 TQMessageStream.h:29
 TQMessageStream.h:30
 TQMessageStream.h:31
 TQMessageStream.h:32
 TQMessageStream.h:33
 TQMessageStream.h:34
 TQMessageStream.h:35
 TQMessageStream.h:36
 TQMessageStream.h:37
 TQMessageStream.h:38
 TQMessageStream.h:39
 TQMessageStream.h:40
 TQMessageStream.h:41
 TQMessageStream.h:42
 TQMessageStream.h:43
 TQMessageStream.h:44
 TQMessageStream.h:45
 TQMessageStream.h:46
 TQMessageStream.h:47
 TQMessageStream.h:48
 TQMessageStream.h:49
 TQMessageStream.h:50
 TQMessageStream.h:51
 TQMessageStream.h:52
 TQMessageStream.h:53
 TQMessageStream.h:54
 TQMessageStream.h:55
 TQMessageStream.h:56
 TQMessageStream.h:57
 TQMessageStream.h:58
 TQMessageStream.h:59
 TQMessageStream.h:60
 TQMessageStream.h:61
 TQMessageStream.h:62
 TQMessageStream.h:63
 TQMessageStream.h:64
 TQMessageStream.h:65
 TQMessageStream.h:66
 TQMessageStream.h:67
 TQMessageStream.h:68
 TQMessageStream.h:69
 TQMessageStream.h:70
 TQMessageStream.h:71
 TQMessageStream.h:72
 TQMessageStream.h:73
 TQMessageStream.h:74
 TQMessageStream.h:75
 TQMessageStream.h:76
 TQMessageStream.h:77
 TQMessageStream.h:78
 TQMessageStream.h:79
 TQMessageStream.h:80
 TQMessageStream.h:81
 TQMessageStream.h:82
 TQMessageStream.h:83
 TQMessageStream.h:84
 TQMessageStream.h:85
 TQMessageStream.h:86
 TQMessageStream.h:87
 TQMessageStream.h:88
 TQMessageStream.h:89
 TQMessageStream.h:90
 TQMessageStream.h:91
 TQMessageStream.h:92
 TQMessageStream.h:93
 TQMessageStream.h:94
 TQMessageStream.h:95
 TQMessageStream.h:96
 TQMessageStream.h:97
 TQMessageStream.h:98
 TQMessageStream.h:99
 TQMessageStream.h:100
 TQMessageStream.h:101
 TQMessageStream.h:102
 TQMessageStream.h:103
 TQMessageStream.h:104
 TQMessageStream.h:105
 TQMessageStream.h:106
 TQMessageStream.h:107
 TQMessageStream.h:108
 TQMessageStream.h:109
 TQMessageStream.h:110
 TQMessageStream.h:111
 TQMessageStream.h:112
 TQMessageStream.h:113
 TQMessageStream.h:114
 TQMessageStream.h:115
 TQMessageStream.h:116
 TQMessageStream.h:117
 TQMessageStream.h:118
 TQMessageStream.h:119
 TQMessageStream.h:120
 TQMessageStream.h:121
 TQMessageStream.h:122
 TQMessageStream.h:123
 TQMessageStream.h:124
 TQMessageStream.h:125
 TQMessageStream.h:126
 TQMessageStream.h:127
 TQMessageStream.h:128
 TQMessageStream.h:129
 TQMessageStream.h:130
 TQMessageStream.h:131
 TQMessageStream.h:132
 TQMessageStream.h:133
 TQMessageStream.h:134
 TQMessageStream.h:135
 TQMessageStream.h:136
 TQMessageStream.h:137
 TQMessageStream.h:138
 TQMessageStream.h:139
 TQMessageStream.h:140
 TQMessageStream.h:141
 TQMessageStream.h:142
 TQMessageStream.h:143
 TQMessageStream.h:144
 TQMessageStream.h:145
 TQMessageStream.h:146
 TQMessageStream.h:147
 TQMessageStream.h:148
 TQMessageStream.h:149
 TQMessageStream.h:150
 TQMessageStream.h:151
 TQMessageStream.h:152
 TQMessageStream.h:153
 TQMessageStream.h:154
 TQMessageStream.h:155
 TQMessageStream.h:156
 TQMessageStream.h:157
 TQMessageStream.h:158
 TQMessageStream.h:159
 TQMessageStream.h:160
 TQMessageStream.h:161
 TQMessageStream.h:162
 TQMessageStream.h:163
 TQMessageStream.h:164
 TQMessageStream.h:165
 TQMessageStream.h:166
 TQMessageStream.h:167
 TQMessageStream.h:168
 TQMessageStream.h:169
 TQMessageStream.h:170
 TQMessageStream.h:171
 TQMessageStream.h:172
 TQMessageStream.h:173
 TQMessageStream.h:174
 TQMessageStream.h:175
 TQMessageStream.h:176
 TQMessageStream.h:177
 TQMessageStream.h:178
 TQMessageStream.h:179
 TQMessageStream.h:180
 TQMessageStream.h:181
 TQMessageStream.h:182
 TQMessageStream.h:183
 TQMessageStream.h:184
 TQMessageStream.h:185
 TQMessageStream.h:186
 TQMessageStream.h:187
 TQMessageStream.h:188
 TQMessageStream.h:189
 TQMessageStream.h:190
 TQMessageStream.h:191
 TQMessageStream.h:192
 TQMessageStream.h:193
 TQMessageStream.h:194
 TQMessageStream.h:195
 TQMessageStream.h:196
 TQMessageStream.h:197
 TQMessageStream.h:198
 TQMessageStream.h:199
 TQMessageStream.h:200
 TQMessageStream.h:201
 TQMessageStream.h:202
 TQMessageStream.h:203
 TQMessageStream.h:204
 TQMessageStream.h:205
 TQMessageStream.h:206
 TQMessageStream.h:207
 TQMessageStream.h:208
 TQMessageStream.h:209
 TQMessageStream.h:210
 TQMessageStream.h:211
 TQMessageStream.h:212
 TQMessageStream.h:213
 TQMessageStream.h:214
 TQMessageStream.h:215
 TQMessageStream.h:216
 TQMessageStream.h:217
 TQMessageStream.h:218
 TQMessageStream.h:219
 TQMessageStream.h:220
 TQMessageStream.h:221
 TQMessageStream.h:222
 TQMessageStream.h:223
 TQMessageStream.h:224
 TQMessageStream.h:225
 TQMessageStream.h:226
 TQMessageStream.h:227
 TQMessageStream.h:228
 TQMessageStream.h:229
 TQMessageStream.h:230
 TQMessageStream.h:231
 TQMessageStream.h:232
 TQMessageStream.h:233
 TQMessageStream.h:234
 TQMessageStream.h:235