/**
 * @file cverb.cpp
 * verbose output stream
 *
 * @remark Copyright 2002, 2004  OProfile authors
 * @remark Read the file COPYING
 *
 * @author Philippe Elie
 * @author John Levon
 */

#include <cstring>

#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <cstring>

#include "cverb.h"

using namespace std;

cverb_object cverb;
verbose vlevel1("level1");
verbose vdebug("debug");
verbose vstats("stats");
verbose vsfile("sfile");
verbose vxml("xml");

namespace {

// The right way is to use: ofstream fout; but cverb(fout.rdbuf()) receive
// a null pointer and stl shipped with 2.91 segfault.
ofstream fout("/dev/null");
ostream null_stream(fout.rdbuf());

// Used to setup the bad bit in our null stream so output will fail earlier
// and overhead will be smaller.
struct setup_stream {
	setup_stream();
};

setup_stream::setup_stream()
{
	null_stream.clear(ios::badbit);
}

setup_stream setup;

// We use a multimap because user can create multiple verbose object with
// the same name, these are synonymous, setting up one to true will setup
// all with the same name to true.
typedef multimap<string, verbose *> recorder_t;
// The recorder is lazilly created by verbose object ctor
static recorder_t * object_map;

} // anonymous namespace


verbose::verbose(char const * name)
	:
	set(false)
{
	// all params is treated a part, there is no need to create a
	// verbose all("all"); it's meaningless. "all" verbose named object is
	// reserved.
	if (strcmp(name, "all") == 0)
		return;
	if (!object_map)
		object_map = new recorder_t;
	object_map->insert(recorder_t::value_type(name, this));
}


verbose verbose::operator|(verbose const & rhs)
{
	verbose result(*this);
	result.set = result.set || rhs.set;
	return result;
}


verbose verbose::operator&(verbose const & rhs)
{
	verbose result(*this);
	result.set = result.set && rhs.set;
	return result;
}


bool verbose::setup(string const & name)
{
	if (name == "all") {
		null_stream.rdbuf(cout.rdbuf());
		null_stream.clear();
		return true;
	}
	if (!object_map)
		object_map = new recorder_t;
	pair<recorder_t::iterator, recorder_t::iterator> p_it =
		object_map->equal_range(name);
	if (p_it.first == p_it.second)
		return false;
	for (; p_it.first != p_it.second; ++p_it.first)
		p_it.first->second->set = true;
	return true;
}


bool verbose::setup(vector<string> const & names)
{
	for (size_t i = 0; i < names.size(); ++i)
		if (!setup(names[i]))
			return false;
	return true;
}


ostream& operator<<(cverb_object &, verbose const & v)
{
	return v.set ? cout : null_stream;
}