
#include <classes/Utility/tagitem.h>

#include <pragma/utility_lib.h>

TagItemC::TagItemC()
{
	taglist = NULL;
}

TagItemC::TagItemC(Tag tag1Type, ...)
{
	taglist = CloneTagItems((struct TagItem *) &tag1Type);
	if (!taglist)
		throw MemoryX(0);
}

TagItemC::TagItemC(struct TagItem *tags)
{
	taglist = CloneTagItems(tags);
	if (!taglist)
		throw MemoryX(0);
}

TagItemC::TagItemC(const TagItemC &tc)
{
	taglist = CloneTagItems(tc.taglist);
	if (!taglist)
		throw MemoryX(0);
}

// Eine Tag Liste mit TAG_MORE freigeben
static VOID FreeTagList(struct TagItem *taglist)
{
	if (!taglist)
		return;
	struct TagItem *tag = taglist;
	for (;;)
	{
		switch (tag->ti_Tag)
		{
			case TAG_END:
				FreeTagItems(taglist);
				return;
			case TAG_MORE:
				tag->ti_Tag = TAG_END;
				tag = (struct TagItem *) tag->ti_Data;
				FreeTagItems(taglist);
				if ((taglist = tag) == NULL)
					return;
				break;
			case TAG_SKIP:
				tag = tag+(tag->ti_Data+1);
				break;
			default:
				tag = tag+1;
		};
	};
}

TagItemC &TagItemC::operator= (const TagItemC &tc)
{
	if (this != &tc)
	{
		FreeTagList(taglist);
		taglist = CloneTagItems(tc.taglist);
		if (!taglist)
			throw MemoryX(0);
	};
	return *this;
}

TagItemC::~TagItemC()
{
	FreeTagList(taglist);
}

static struct TagItem *FindTagEND(struct TagItem *taglist)
{
	for (;;)
	{
		switch (taglist->ti_Tag)
		{
			case TAG_END:
				return taglist;
			case TAG_MORE:
				if (!taglist->ti_Data)
					return taglist;
				taglist = (struct TagItem *) taglist->ti_Data;
				break;
			case TAG_SKIP:
				taglist = taglist+(taglist->ti_Data+1);
				break;
			default:
				taglist = taglist+1;
		};
	};
}

VOID TagItemC::append(const TagItemC *tags)
{
	if (tags)
		append(tags->taglist);
}

VOID TagItemC::append(Tag tag1Type, ...)
{
	append((struct TagItem *) &tag1Type);
}

VOID TagItemC::append(const struct TagItem *tags)
{
	if (taglist)
	{
		struct TagItem *endtag = FindTagEND(taglist);
		endtag->ti_Tag = TAG_MORE;
		// Typumwandlung, damit 'tags' ein const Parameter sein kann
		endtag->ti_Data = (ULONG) CloneTagItems((struct TagItem *) tags);
		if (!endtag->ti_Data)
			throw MemoryX(0);
	}
	else {
		taglist = CloneTagItems((struct TagItem *) tags);
		if (!taglist)
			throw MemoryX(0);
	};
}

VOID TagItemC::set(const TagItemC *tags)
{
	if (tags)
		set(tags->taglist);
}

VOID TagItemC::set(Tag tag1Type, ...)
{
	set((struct TagItem *) &tag1Type);
}

VOID TagItemC::set(const struct TagItem *tags)
{
	if (taglist)
	{
		struct TagItem *ti;
		BOOL app = FALSE;
		TagItemCursorC tic((struct TagItem *) tags);
		while (!tic.isDone())
		{
			if (ti = find(tic.itemTag()))
			{
				ti->ti_Data = tic.itemData();
				tic.item()->ti_Tag = TAG_IGNORE;
			}
			else
				app = TRUE;
			tic.next();
		};
		if (app)
		{
			append(tags);
		};
	}
	else {
		taglist = CloneTagItems((struct TagItem *) tags);
		if (!taglist)
			throw MemoryX(0);
	};
}

struct TagItem *TagItemC::find(Tag tagType) const
{
	return FindTagItem(tagType,taglist);
}

ULONG TagItemC::getData(Tag tagType, ULONG defaultData) const
{
	return GetTagData(tagType,defaultData,taglist);
}

ULONG TagItemC::filter(LONG logic, Tag tagTypes[])
{
	return FilterTagItems(taglist,tagTypes,logic);
}

ULONG TagItemC::filter(LONG logic, Tag tag1, ... )
{
	return FilterTagItems(taglist,&tag1,logic);
}

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

TagItemCursorC::TagItemCursorC(TagItemC &tc)
{
	taglist = tc.tags();
	first();
}

TagItemCursorC::TagItemCursorC(struct TagItem *tags)
{
	taglist = tags;
	first();
}

BOOL TagItemCursorC::isDone()
{
	return pos == NULL;
}

VOID TagItemCursorC::first()
{
	cursor = taglist;
	pos = NextTagItem(&cursor);
}

VOID TagItemCursorC::next()
{
	if (pos)
		pos = NextTagItem(&cursor);
}

struct TagItem *TagItemCursorC::item() const
{
	return pos;
}

Tag TagItemCursorC::itemTag() const
{
	if (pos)
		return pos->ti_Tag;
	return TAG_END;
}

ULONG TagItemCursorC::itemData() const
{
	if (pos)
		return pos->ti_Data;
	return 0;
}
