/*
 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */
 
 
#include "VariablesViewStateHistory.h"
 
#include <new>
 
#include "FunctionID.h"
#include "VariablesViewState.h"
 
 
// #pragma mark - Key
 
 
struct VariablesViewStateHistory::Key {
	thread_id	threadID;
	FunctionID*	functionID;
 
	Key(thread_id threadID, FunctionID* functionID)
		:
		threadID(threadID),
		functionID(functionID)
	{
	}
 
	uint32 HashValue() const
	{
		return functionID->HashValue() ^ threadID;
	}
 
	bool operator==(const Key& other) const
	{
		return threadID == other.threadID && *functionID == *other.functionID;
	}
};
 
 
// #pragma mark - StateEntry
 
 
struct VariablesViewStateHistory::StateEntry : Key, VariablesViewNodeInfo {
	StateEntry*			next;
	VariablesViewState*	state;
 
	StateEntry(thread_id threadID, FunctionID* functionID)
		:
		Key(threadID, functionID),
		state(NULL)
	{
		functionID->AcquireReference();
	}
 
	~StateEntry()
	{
		functionID->ReleaseReference();
		if (state != NULL)
			state->ReleaseReference();
	}
 
	void SetState(VariablesViewState* state)
	{
		if (state == this->state)
			return;
 
		if (state != NULL)
			state->AcquireReference();
 
		if (this->state != NULL)
			this->state->ReleaseReference();
 
		this->state = state;
	}
};
 
 
struct VariablesViewStateHistory::StateEntryHashDefinition {
	typedef Key			KeyType;
	typedef	StateEntry	ValueType;
 
	size_t HashKey(const Key& key) const
	{
		return key.HashValue();
	}
 
	size_t Hash(const StateEntry* value) const
	{
		return HashKey(*value);
	}
 
	bool Compare(const Key& key, const StateEntry* value) const
	{
		return key == *value;
	}
 
	StateEntry*& GetLink(StateEntry* value) const
	{
		return value->next;
	}
};
 
 
VariablesViewStateHistory::VariablesViewStateHistory()
	:
	fStates(NULL)
{
}
 
 
VariablesViewStateHistory::~VariablesViewStateHistory()
{
	if (fStates != NULL) {
		StateEntry* entry = fStates->Clear(true);
 
		while (entry != NULL) {
			StateEntry* next = entry->next;
			delete entry;
			entry = next;
		}
 
		delete fStates;
	}
}
 
 
status_t
VariablesViewStateHistory::Init()
{
	fStates = new(std::nothrow) StateTable;
	if (fStates == NULL)
		return B_NO_MEMORY;
 
	return fStates->Init();
}
 
 
VariablesViewState*
VariablesViewStateHistory::GetState(thread_id threadID, FunctionID* functionID)
	const
{
	// first try an exact match with the thread ID
	if (threadID >= 0) {
		StateEntry* stateEntry = fStates->Lookup(Key(threadID, functionID));
		if (stateEntry != NULL)
			return stateEntry->state;
	}
 
	// just match the function ID
	StateEntry* stateEntry = fStates->Lookup(Key(-1, functionID));
	return stateEntry != NULL ? stateEntry->state : NULL;
}
 
 
VariablesViewState*
VariablesViewStateHistory::GetState(FunctionID* functionID) const
{
	StateEntry* stateEntry = fStates->Lookup(Key(-1, functionID));
	return stateEntry != NULL ? stateEntry->state : NULL;
}
 
 
status_t
VariablesViewStateHistory::SetState(thread_id threadID, FunctionID* functionID,
	VariablesViewState* state)
{
	// Make sure the default entry for the function exists.
	StateEntry* defaultEntry = fStates->Lookup(Key(-1, functionID));
	bool newDefaultEntry = false;
 
	if (defaultEntry == NULL) {
		defaultEntry = new(std::nothrow) StateEntry(-1, functionID);
		if (defaultEntry == NULL)
			return B_NO_MEMORY;
		fStates->Insert(defaultEntry);
		newDefaultEntry = true;
	}
 
	// If we have a valid thread ID, make sure the respective entry for the
	// function exists.
	StateEntry* threadEntry = NULL;
	if (threadID >= 0) {
		threadEntry = fStates->Lookup(Key(threadID, functionID));
 
		if (threadEntry == NULL) {
			threadEntry = new(std::nothrow) StateEntry(threadID, functionID);
			if (threadEntry == NULL) {
				if (newDefaultEntry) {
					fStates->Remove(defaultEntry);
					delete defaultEntry;
				}
				return B_NO_MEMORY;
			}
			fStates->Insert(threadEntry);
		}
	}
 
	defaultEntry->SetState(state);
	if (threadEntry != NULL)
		threadEntry->SetState(state);
 
	return B_OK;
}

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