/*
 * Copyright 2014-2016, Rene Gollent, rene@gollent.com.
 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */
 
 
#include "ExpressionValues.h"
 
#include <new>
 
#include "FunctionID.h"
#include "model/Thread.h"
#include "StringUtils.h"
 
 
struct ExpressionValues::Key {
	FunctionID*			function;
	::Thread*			thread;
	BString				expression;
 
	Key(FunctionID* function, ::Thread* thread, const BString& expression)
		:
		function(function),
		thread(thread),
		expression(expression)
	{
	}
 
	uint32 HashValue() const
	{
		return function->HashValue() ^ thread->ID()
			^ StringUtils::HashValue(expression);
	}
 
	bool operator==(const Key& other) const
	{
		return *function == *other.function
			&& thread->ID() == other.thread->ID()
			&& expression == other.expression;
	}
};
 
 
struct ExpressionValues::ValueEntry : Key {
	BVariant			value;
	ValueEntry*			next;
 
	ValueEntry(FunctionID* function, ::Thread* thread,
		const BString& expression)
		:
		Key(function, thread, expression)
	{
		function->AcquireReference();
		thread->AcquireReference();
	}
 
	~ValueEntry()
	{
		function->ReleaseReference();
		thread->ReleaseReference();
	}
};
 
 
struct ExpressionValues::ValueEntryHashDefinition {
	typedef Key			KeyType;
	typedef	ValueEntry	ValueType;
 
	size_t HashKey(const Key& key) const
	{
		return key.HashValue();
	}
 
	size_t Hash(const ValueEntry* value) const
	{
		return value->HashValue();
	}
 
	bool Compare(const Key& key, const ValueEntry* value) const
	{
		return key == *value;
	}
 
	ValueEntry*& GetLink(ValueEntry* value) const
	{
		return value->next;
	}
};
 
 
ExpressionValues::ExpressionValues()
	:
	fValues(NULL)
{
}
 
 
ExpressionValues::ExpressionValues(const ExpressionValues& other)
	:
	fValues(NULL)
{
	try {
		// init
		if (Init() != B_OK)
			throw std::bad_alloc();
 
		// clone all values
		for (ValueTable::Iterator it = other.fValues->GetIterator();
				ValueEntry* entry = it.Next();) {
			if (SetValue(entry->function, entry->thread, entry->expression,
				entry->value) != B_OK) {
				throw std::bad_alloc();
			}
		}
	} catch (...) {
		_Cleanup();
		throw;
	}
}
 
 
ExpressionValues::~ExpressionValues()
{
	_Cleanup();
}
 
 
status_t
ExpressionValues::Init()
{
	fValues = new(std::nothrow) ValueTable;
	if (fValues == NULL)
		return B_NO_MEMORY;
 
	return fValues->Init();
}
 
 
bool
ExpressionValues::GetValue(FunctionID* function, ::Thread* thread,
	const BString* expression, BVariant& _value) const
{
	ValueEntry* entry = fValues->Lookup(Key(function, thread, *expression));
	if (entry == NULL)
		return false;
 
	_value = entry->value;
	return true;
}
 
 
bool
ExpressionValues::HasValue(FunctionID* function, ::Thread* thread,
	const BString* expression) const
{
	return fValues->Lookup(Key(function, thread, *expression)) != NULL;
}
 
 
status_t
ExpressionValues::SetValue(FunctionID* function, ::Thread* thread,
	const BString& expression, const BVariant& value)
{
	ValueEntry* entry = fValues->Lookup(Key(function, thread, expression));
	if (entry == NULL) {
		entry = new(std::nothrow) ValueEntry(function, thread, expression);
		if (entry == NULL)
			return B_NO_MEMORY;
		fValues->Insert(entry);
	}
 
	entry->value = value;
	return B_OK;
}
 
 
void
ExpressionValues::_Cleanup()
{
	if (fValues != NULL) {
		ValueEntry* entry = fValues->Clear(true);
 
		while (entry != NULL) {
			ValueEntry* next = entry->next;
			delete entry;
			entry = next;
		}
 
		delete fValues;
		fValues = NULL;
	}
}

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: next.