// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-

// Copyright (c) 2001-2007 International Computer Science Institute
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software")
// to deal in the Software without restriction, subject to the conditions
// listed in the XORP LICENSE file. These conditions include: you must
// preserve this copyright notice, and you cannot mention the copyright
// holders in advertising related to the Software without their permission.
// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
// notice is a summary of the XORP LICENSE file; the license in that file is
// legally binding.

#ident "$XORP: xorp/libxorp/profile.cc,v 1.8 2007/02/16 22:46:21 pavlin Exp $"

#include "libxorp_module.h"
#include "xorp.h"

#include "libxorp/timeval.hh"
#include "libxorp/timer.hh"

#include "xlog.h"
#include "debug.h"
#include "profile.hh"

Profile::Profile()
    : _profile_cnt(0)
{
}

inline
void
zap(const pair<string, ref_ptr<Profile::ProfileState> >& p)
{
    p.second->zap();
}

Profile::~Profile()
{
    for_each(_profiles.begin(), _profiles.end(), ptr_fun(zap));
}

void
Profile::create(const string& pname, const string& comment)
    throw(PVariableExists)
{
    // Catch initialization problems.
    if (_profiles.count(pname))
	xorp_throw(PVariableExists, pname.c_str());

    ProfileState *p = new ProfileState(comment, false, false, new logentries);
    _profiles[pname] = ref_ptr<ProfileState>(p);
}

void
Profile::log(const string& pname, string comment)
    throw(PVariableUnknown,PVariableNotEnabled)
{
    profiles::iterator i = _profiles.find(pname);

    // Catch any mispelt pnames.
    if (i == _profiles.end())
	xorp_throw(PVariableUnknown, pname.c_str());

    // In order to be logging, we must be enabled.
    if (!i->second->enabled())
	xorp_throw(PVariableNotEnabled, pname.c_str());
    
#if	0
    // Make sure that this variable is not locked.
    if (!i->second->locked())
	xorp_throw(PVariableLocked, pname.c_str());
#endif
    
    TimeVal tv;
    TimerList::system_gettimeofday(&tv);
    i->second->logptr()->push_back(ProfileLogEntry(tv, comment));
}

void
Profile::enable(const string& pname) throw(PVariableUnknown,PVariableLocked)
{
    profiles::iterator i = _profiles.find(pname);

    // Catch any mispelt pnames.
    if (i == _profiles.end())
	xorp_throw(PVariableUnknown, pname.c_str());

    // If this profile name is already enabled, get out of here
    // without updating the counter.
    if (i->second->enabled())
	return;

    // Don't allow a locked entry to be enabled.
    if (i->second->locked())
	xorp_throw(PVariableLocked, pname.c_str());
    
    i->second->set_enabled(true);
    _profile_cnt++;
}

void
Profile::disable(const string& pname) throw(PVariableUnknown)
{
    profiles::iterator i = _profiles.find(pname);

    // Catch any mispelt pnames.
    if (i == _profiles.end())
	xorp_throw(PVariableUnknown, pname.c_str());

    // If this profile name is already disabled, get out of here
    // without updating the counter.
    if (!i->second->enabled())
	return;
    i->second->set_enabled(false);
    _profile_cnt--;
}

void
Profile::lock_log(const string& pname) throw(PVariableUnknown,PVariableLocked)
{
    profiles::iterator i = _profiles.find(pname);

    // Catch any mispelt pnames.
    if (i == _profiles.end())
	xorp_throw(PVariableUnknown, pname.c_str());

    // Don't allow a locked entry to be locked again.
    if (i->second->locked())
	xorp_throw(PVariableLocked, pname.c_str());

    // Disable logging.
    disable(pname);

    // Lock the entry
    i->second->set_locked(true);

    i->second->set_iterator(i->second->logptr()->begin());
}

bool 
Profile::read_log(const string& pname, ProfileLogEntry& entry) 
    throw(PVariableUnknown,PVariableNotLocked)
{
    profiles::iterator i = _profiles.find(pname);

    // Catch any mispelt pnames.
    if (i == _profiles.end())
	xorp_throw(PVariableUnknown, pname.c_str());

    // Verify that the log entry is locked
    if (!i->second->locked())
	xorp_throw(PVariableNotLocked, pname.c_str());

    logentries::iterator li;
    i->second->get_iterator(li);
    if (li == i->second->logptr()->end())
	return false;

    entry = *li;
    i->second->set_iterator(++li);

    return true;
}

void
Profile::release_log(const string& pname) 
    throw(PVariableUnknown,PVariableNotLocked)
{
    profiles::iterator i = _profiles.find(pname);

    // Catch any mispelt pnames.
    if (i == _profiles.end())
	xorp_throw(PVariableUnknown, pname.c_str());

    // Verify that the log entry is locked
    if (!i->second->locked())
	xorp_throw(PVariableNotLocked, pname.c_str());

    // Unlock the entry
    i->second->set_locked(false);
}

void
Profile::clear(const string& pname) throw(PVariableUnknown,PVariableLocked)
{
    profiles::iterator i = _profiles.find(pname);

    // Catch any mispelt pnames.
    if (i == _profiles.end())
	xorp_throw(PVariableUnknown, pname.c_str());

    // Don't allow a locked entry to be cleared.
    if (i->second->locked())
	xorp_throw(PVariableLocked, pname.c_str());

    i->second->logptr()->clear();
}

class List: public unary_function<pair<string, 
				       ref_ptr<Profile::ProfileState> >,
				  void> {
 public:
    void operator()(const pair<string, ref_ptr<Profile::ProfileState> >& p) {
	_result += p.first;
	_result += "\t";
	_result += c_format("%d", p.second->size());
	_result += "\t";
	_result += p.second->enabled() ? "enabled" : "disabled";
	_result += "\t";
	_result += p.second->comment();
	_result += "\n";
    }

    string result() const {
	return _result;
    }
 private:
    string _result;
};

string
Profile::list() const
{
    return for_each(_profiles.begin(), _profiles.end(), List()).result();
}



syntax highlighted by Code2HTML, v. 0.9.1