#include <ZUtil/ZRegistry.hpp>

/*************************************************************************/

ZRegistry::ZRegistry()
	: Lock(), Tree()
{

}

/*************************************************************************/

ZRegistry::ZRegistry( const ZKVTree& _tree )
	: Lock(), Tree(_tree)
{

}

/*************************************************************************/

ZRegistry::~ZRegistry()
{

}

/*************************************************************************/

void ZRegistry::Erase( const ZString& _key )
{
	Lock.LockForWriting(SST_WAIT_INFINITE);

	ZKVTree::Iterator itr = Tree.Find(_key);

	if (itr != Tree.End()) {
		Tree.Erase(itr);
	}

	Lock.EndWriting();
}

/*************************************************************************/

const ZRegistry::Value ZRegistry::Get( const ZString& _key ) const
{
	Lock.LockForReading(SST_WAIT_INFINITE);

	ZKVTree::Iterator itr = Tree.Find(_key);

	if (itr != Tree.End()) {
		ZRegistry::Value val(itr.GetValue(), true);
		Lock.EndReading();
		return val;
	}

	Lock.EndReading();	
	return ZRegistry::Value("", false);
}

/*************************************************************************/

bool ZRegistry::Put( const ZString& _key, const ZString& _value )
{
	size_t i = _key.Length();

	//ZRegistry does not support sibling nodes with the same name
	if (ZStringAlgo::FindFirstOf(_key, "[]") != ZSTL::InvalidPos)
		return false;

	Lock.LockForWriting(SST_WAIT_INFINITE);
	
	/*
	NOTE: This algorithm is not currently needed with the way ZKVTree works, but
	that may change - placing value-less nodes in KV tree may be incorrect.  If that
	changes, this should work.

	Algorithm:

	attempt to place full key
	if it succeeds, return true
	else
	while (valid path)
		attempt key - child (i.e., A.B.C.d -> A.B.C, A.B.C -> A.B, A.B -> A, A -> '')
		if success, attempt full key
		else repeat
	*/
	while (i > 0) {
		Tree.Put(ZString(_key, 0, i), _value);

		if (i == _key.Length()) {
			break;
		} else {
			i = _key.Length();
		}

		i = ZStringAlgo::FindLast(_key, ZKVTREE_PATH_SEPARATOR, 0, i);

		if (i == ZSTL::InvalidPos)
			break;
	}
	
	Lock.EndWriting();

	return i > 0;
}
