// This file is part of the Coral project.
// Please read the copyright notice in the LICENSE file.

#include "debugstream.h"

#include <Python.h>

NAMESPACE_BEGIN(coral);

const char* debuglevel_str[] = {
	"all", // guaranteed to include every debug message
	"debug",
	"info",
	"warning",
	"error",
	"critical",
	"none",    // guaranteed to be last, nothing beats it
     NULL,
};

NAMESPACE_BEGIN();

PyObject* observer = NULL;

void callDebugObserver() {
	if (!observer || observer == Py_None) return;

	PyObject* args = PyTuple_New(0);
	if (!args) return;
	PyObject_Call(observer, args, NULL);
}

debuglevel current_debug_level = DEBUGLEVEL_WARNING;

NAMESPACE_END();

debugstreambuf::debugstreambuf(std::ostream& out)
	: m_output2(out),
	  current_message_dlevel(DEBUGLEVEL_DEBUG) {
	;
}

debugstreambuf::~debugstreambuf() {
	;
}

std::streamsize debugstreambuf::xsputn(const char_type* s, std::streamsize n) {
	if (current_debug_level > current_message_dlevel) return n;
	/*
	 * Always succeed
	 */
	try {
		m_output1.rdbuf()->sputn(s, n);
		callDebugObserver();
		m_output2.rdbuf()->sputn(s, n);
	} catch (...) {
		;
	}
	return n;
}

int debugstreambuf::overflow(int_type c) {
	if (current_debug_level > current_message_dlevel) return c;
	/*
	 * Always succeed
	 */
	try {
		m_output1.rdbuf()->sputc(c);
		callDebugObserver();
		m_output2.rdbuf()->sputc(c);
	} catch (...) {
		;
	}
	return c;
}

std::ostringstream& debugstreambuf::get_string_stream() {
	return m_output1;
}

debugstreambuf* dlogbuf = new debugstreambuf(std::clog);

std::ostream dlog(dlogbuf);


std::string getDebugLog() {
	std::ostringstream& s = dlogbuf->get_string_stream();
	std::string ret = s.str();
	s.str("");
	return ret;
}

void setDebugObserver(PyObject* p) {
	Py_INCREF(p);
	if (observer) Py_DECREF(observer);
	observer = p;
}



debuglevel setDebugLevel(debuglevel d) {
	debuglevel old = current_debug_level;
	current_debug_level = d;
	return old;
}

debuglevel getDebugLevel() {
	return current_debug_level;
}

std::ostream& operator<<(std::ostream& out, debuglevel d) {
	// A bit simple, we can only have one debugstream this way :(
	if (out != dlog) return out;

	// Debug messages can't be at NONE level
	if (d < DEBUGLEVEL_NONE) {
		dlogbuf->curMessageLevel() = d;
	}

	return out;
}

NAMESPACE_END();
