/*
 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */


#include "PackageLinksDirectory.h"

#include <AutoDeleter.h>

#include "DebugSupport.h"
#include "PackageLinkDirectory.h"
#include "PackageLinksListener.h"
#include "Utils.h"


PackageLinksDirectory::PackageLinksDirectory()
	:
	Directory(0),
	fListener(NULL)
		// the ID needs to be assigned later, when added to a volume
{
	get_real_time(fModifiedTime);
}


PackageLinksDirectory::~PackageLinksDirectory()
{
}


timespec
PackageLinksDirectory::ModifiedTime() const
{
	return fModifiedTime;
}


status_t
PackageLinksDirectory::AddPackage(Package* package)
{
	// Create a package link directory -- there might already be one, but since
	// that's unlikely, we don't bother to check and recheck later.
	PackageLinkDirectory* linkDirectory
		= new(std::nothrow) PackageLinkDirectory;
	if (linkDirectory == NULL)
		return B_NO_MEMORY;
	BReference<PackageLinkDirectory> linkDirectoryReference(linkDirectory,
		true);

	status_t error = linkDirectory->Init(package);
	if (error != B_OK)
		RETURN_ERROR(error);

	// add the link directory
	DirectoryWriteLocker writeLocker(this);
	if (Node* child = FindChild(linkDirectory->Name())) {
		// There already is an entry with the name.
		PackageLinkDirectory* otherLinkDirectory
			= dynamic_cast<PackageLinkDirectory*>(child);
		if (otherLinkDirectory == NULL)
			RETURN_ERROR(B_BAD_VALUE);

		// There's already a package link directory. Delete the one we created
		// and add the package to the pre-existing one.
		linkDirectory->RemovePackage(package, NULL);
		linkDirectoryReference.Unset();

		linkDirectory = otherLinkDirectory;
		linkDirectory->AddPackage(package, fListener);
	} else {
		// No entry is in the way, so just add the link directory.
		AddChild(linkDirectory);

		if (fListener != NULL)
			fListener->PackageLinkNodeAdded(linkDirectory);
	}

	return B_OK;
}


void
PackageLinksDirectory::RemovePackage(Package* package)
{
	DirectoryWriteLocker writeLocker(this);

	// get the package's link directory and remove the package from it
	PackageLinkDirectory* linkDirectory = package->LinkDirectory();
	if (linkDirectory == NULL)
		return;

	BReference<PackageLinkDirectory> linkDirectoryReference(linkDirectory);

	linkDirectory->RemovePackage(package, fListener);

	// if empty, remove the link directory itself
	if (linkDirectory->IsEmpty()) {
		if (fListener != NULL) {
			DirectoryWriteLocker linkDirectoryWriteLocker(linkDirectory);
			fListener->PackageLinkNodeRemoved(linkDirectory);
		}

		RemoveChild(linkDirectory);
	}
}


void
PackageLinksDirectory::UpdatePackageDependencies(Package* package)
{
	DirectoryWriteLocker writeLocker(this);

	PackageLinkDirectory* linkDirectory = package->LinkDirectory();
	if (linkDirectory == NULL)
		return;

	linkDirectory->UpdatePackageDependencies(package, fListener);
}