#include "ItemList.h"

inline BOOL   FPIL_ADDEXIST(const PluginPanelItem *p) { return ((p)->Reserved[0] && (p)->Reserved[1]); }
inline DWORD  FPIL_ADDSIZE(const PluginPanelItem *p)  { return FPIL_ADDEXIST(p) ? (DWORD)(p)->Reserved[0] : 0; }
inline LPVOID FPIL_ADDDATA(const PluginPanelItem *p)  { return FPIL_ADDEXIST(p) ? ((void*)(p)->Reserved[1]) : NULL; }
inline void   FPIL_ADDSET(PluginPanelItem *p, DWORD sz, LPVOID dt) { (p)->Reserved[0] = sz; (p)->Reserved[1] = (DWORD_PTR)dt; }

//---------------------------------------------------------------------------------
FP_ItemList::FP_ItemList(BOOL NeedToDelete)
{
	needToDelete = NeedToDelete;
	List         = NULL;
	ItemsCount   = 0;
	MaxCount     = 0;
}


BOOL FP_ItemList::Realloc(int NewSize)
{
	if(!NewSize)
		return FALSE;

	if(NewSize <= MaxCount)
		return TRUE;

	MaxCount = NewSize;

	if(!List)
		List = (PluginPanelItem*)malloc(sizeof(PluginPanelItem)*MaxCount);
	else
		List = (PluginPanelItem *)realloc(List,sizeof(PluginPanelItem)*MaxCount);

	if(!List)
	{
		ItemsCount = 0;
		MaxCount   = 0;
		return FALSE;
	}

	return TRUE;
}

PluginPanelItem *FP_ItemList::Add(const PluginPanelItem *pi,int icn)
{
	if(!Realloc(ItemsCount+icn))
		return NULL;

	PluginPanelItem *p = List + ItemsCount; //!! Do not use Item(ItemsCount) because we need point after last element
	Copy(p, pi, icn);
	ItemsCount += icn;
	return p;
}

void FP_ItemList::Clear(void)
{
	if(needToDelete)
		Free(List,ItemsCount);

	ItemsCount = 0;
	MaxCount   = 0;
	List       = NULL;
}


bool IsBadReadPtr(const void *p, size_t l)
{
	ULONG_PTR v = (ULONG_PTR)p;
	return v<0x10000;
}

void FP_ItemList::Copy(PluginPanelItem *dest,const PluginPanelItem *src,int cn)
{
	if(!cn) return;

	memmove(dest, src, sizeof(*dest)*cn);

	for(; cn; cn--,src++,dest++)
	{
		//User data
		if(IS_FLAG(src->Flags,PPIF_USERDATA))
		{
			DWORD sz = (src->UserData && !IsBadReadPtr((void*)src->UserData,sizeof(DWORD)))
				? (*((DWORD*)src->UserData))
				: 0;

			if(sz && !IsBadReadPtr((void*)src->UserData,sz))
			{
				dest->UserData = (DWORD_PTR)malloc(sz+1);
				memmove((char*)dest->UserData,(char*)src->UserData,sz);
			}
			else
			{
				dest->UserData = 0;
				CLR_FLAG(dest->Flags,PPIF_USERDATA);
			}
		}

		//CustomColumn
		if(src->CustomColumnNumber)
		{
			dest->CustomColumnData = (LPSTR*)malloc(sizeof(LPSTR*)*src->CustomColumnNumber);

			for(int n = 0; n < src->CustomColumnNumber; n++)
			{
				dest->CustomColumnData[n] = strdup(src->CustomColumnData[n]);
			}
		}

		//Description
		if(src->Description)
			dest->Description = strdup(src->Description);

		//Owner
		if(src->Owner)
			dest->Owner = strdup(src->Owner);

		//Additionals
		if(FPIL_ADDEXIST(src))
		{
			DWORD  sz  = FPIL_ADDSIZE(src);
			LPVOID ptr = malloc(sz);

			if(ptr)
			{
				memmove(ptr, FPIL_ADDDATA(src), sz);
				FPIL_ADDSET(dest, sz, ptr);
			}
			else
				FPIL_ADDSET(dest, 0, NULL);
		}
	}
}

void FP_ItemList::Free(PluginPanelItem *List,int count)
{
	PluginPanelItem *p = List;

	for(int i = 0; i < count; i++,List++)
	{
		//UserData
		if(IS_FLAG(List->Flags,PPIF_USERDATA))
		{
			free((char*)List->UserData);
			List->UserData = 0;
		}

		//CustomColumn
		for(int n = 0; n < List->CustomColumnNumber; n++)
			free(List->CustomColumnData[n]);

		if(List->CustomColumnData)
			free(List->CustomColumnData);

		//Description
		if(List->Description)
			free(List->Description), List->Description = NULL;

		//Owner
		if(List->Owner)
			free(List->Owner), List->Owner = NULL;

		//Additionals
		if(FPIL_ADDEXIST(List))
		{
			free(FPIL_ADDDATA(List));
			List->Reserved[0] = 0;
			List->Reserved[1] = 0;
		}
	}

	free(p);
}
