/*
 * Copyright 2011-2016, Haiku, Inc. All rights reserved.
 * Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
 * Distributed under the terms of the MIT License.
 */


#include "FilterList.h"

#include <set>
#include <stdio.h>

#include <Directory.h>
#include <PathFinder.h>
#include <Path.h>


FilterList::FilterList(direction dir)
	:
	fDirection(dir)
{
}


FilterList::~FilterList()
{
	_MakeEmpty();
}


void
FilterList::Reload()
{
	_MakeEmpty();

	std::set<BString> knownNames;

	BString subPath("mail_daemon/");
	subPath << (fDirection == kIncoming
		? "inbound_filters" : "outbound_filters");

	BStringList paths;
	BPathFinder().FindPaths(B_FIND_PATH_ADD_ONS_DIRECTORY, subPath, paths);
	for (int32 i = 0; i < paths.CountStrings(); i++) {
		BPath path(paths.StringAt(i));

		BDirectory dir(path.Path());
		if (dir.InitCheck() != B_OK)
			continue;

		BEntry entry;
		while (dir.GetNextEntry(&entry) == B_OK) {
			// Ignore entries we already had before (ie., user add-ons are
			// overriding system add-ons)
			if (knownNames.find(entry.Name()) != knownNames.end())
				continue;

			if (_LoadAddOn(entry) == B_OK)
				knownNames.insert(entry.Name());
		}
	}
}


int32
FilterList::CountInfos() const
{
	return fList.size();
}


const FilterInfo&
FilterList::InfoAt(int32 index) const
{
	return fList[index];
}


int32
FilterList::InfoIndexFor(const entry_ref& ref) const
{
	for (size_t i = 0; i < fList.size(); i++) {
		const FilterInfo& info = fList[i];
		if (info.ref == ref)
			return i;
	}
	return -1;
}


BString
FilterList::SimpleName(int32 index,
	const BMailAccountSettings& accountSettings) const
{
	return DescriptiveName(index, accountSettings, NULL);
}


BString
FilterList::SimpleName(const entry_ref& ref,
	const BMailAccountSettings& accountSettings) const
{
	return DescriptiveName(InfoIndexFor(ref), accountSettings, NULL);
}


BString
FilterList::DescriptiveName(int32 index,
	const BMailAccountSettings& accountSettings,
	const BMailAddOnSettings* settings) const
{
	if (index < 0 || index >= CountInfos())
		return "-";

	const FilterInfo& info = InfoAt(index);
	return info.name(accountSettings, settings);
}


BString
FilterList::DescriptiveName(const entry_ref& ref,
	const BMailAccountSettings& accountSettings,
	const BMailAddOnSettings* settings) const
{
	return DescriptiveName(InfoIndexFor(ref), accountSettings, settings);
}


BMailSettingsView*
FilterList::CreateSettingsView(const BMailAccountSettings& accountSettings,
	const BMailAddOnSettings& settings)
{
	const entry_ref& ref = settings.AddOnRef();
	int32 index = InfoIndexFor(ref);
	if (index < 0)
		return NULL;

	const FilterInfo& info = InfoAt(index);
	return info.instantiateSettingsView(accountSettings, settings);
}


void
FilterList::_MakeEmpty()
{
	for (size_t i = 0; i < fList.size(); i++) {
		FilterInfo& info = fList[i];
		unload_add_on(info.image);
	}
	fList.clear();
}


status_t
FilterList::_LoadAddOn(BEntry& entry)
{
	FilterInfo info;

	BPath path(&entry);
	info.image = load_add_on(path.Path());
	if (info.image < 0)
		return info.image;

	status_t status = get_image_symbol(info.image,
		"instantiate_filter_settings_view", B_SYMBOL_TYPE_TEXT,
		(void**)&info.instantiateSettingsView);
	if (status == B_OK) {
		status = get_image_symbol(info.image, "filter_name", B_SYMBOL_TYPE_TEXT,
			(void**)&info.name);
	}
	if (status != B_OK) {
		fprintf(stderr, "Filter \"%s\" misses required hooks!\n", path.Path());
		unload_add_on(info.image);
		return B_NAME_NOT_FOUND;
	}

	entry.GetRef(&info.ref);
	fList.push_back(info);
	return B_OK;
}
