/*
**	patch.library
**
**	Copyright © 1993-1997 by Stefan Fuchs
**		Freely distributable.
*/

#ifndef _PATCH_INCLUDES_H
#include "patch_includes.h"
#endif


/****** patch.library/RemovePatchProjectA ***************************************
*
*   NAME
*        RemovePatchProjectA -- Remove all patches from the same project. (V4)
*        RemovePatchProject -- varargs stub for RemovePatchProjectA(). (V4)
*
*   SYNOPSIS
*        Error = RemovePatchProjectA( project, taglist )
*        D0                           A0       A1
*
*        ULONG Error RemovePatchProjectA( APTR, struct TagItem *);
*
*        Error = RemovePatchProject( project, ...)
*
*        ULONG Error RemovePatchProject( APTR, ...);
*
*   FUNCTION
*        Remove all patches from the given project.
*
*        This function simplifies the way, patches can be removed:
*        - All patches belonging to one project will be disabled
*        - The function then waits (depending on PATT_Timeout) until
*          the usagecounters of all patches become zero
*        - Now all patches will be removed via RemovePatchTags()
*        - If all patches are removed resources connected to the
*          project will be deallocted
*
*        You may call this function to cleanup a project, even if no
*        patch was successfully installed for this project.
*
*   INPUTS
*        project = pointer to a patch project obtained via
*                  CreatePatchProject()
*        taglist = pointer to array of tags
*
*   TAGS
*        same as RemovePatchTags()
*
*   RESULT
*        Error = errorcode as defined in patch.h.
*                same as RemovePatchTags()
*
*   NOTES
*        Removing a patch routine can never be made absolutely safe.
*        Although patch.library does anything possible to provide methods
*        to minimize the chance of a crash, there will always be a
*        slight chance.
*        So minimize the number of install and remove operations.
*
*   BUGS
*
*   SEE ALSO
*        CreatePatchProject(), InstallPatchTags(), RemovePatchTags(),
*        patch.h, patchtags.h
*
******************************************************************************
*
*/

ULONG LIBFUNC RemovePatchProjectA( REGA0 struct PatchProject *project GNUC_REGA0, REGA1 struct TagItem *taglist GNUC_REGA1)
{
LONG timeout;
ULONG result;
struct Patch *PatchPointer;
struct Node *pointer;
struct TagItem SetPatchDisableTags[2] = { PATT_Disabled, 1L, TAG_DONE };
struct TagItem SetPatchEnableTags[2] = { PATT_Disabled, 0L, TAG_DONE };

	if (project == NULL) return(NULL);

	timeout = GetTagData(PATT_TimeOut, 0L, taglist);

	result = SAVEObtainSemaphore();
	if(result) return(result);


/* Disable all Project related patches */

	project->PPR_Flags |= PPRF_InternalCall;
	Disable();		/* Patches muessen gleichzeitig disabled werden */
	SetPatchProjectA(project, SetPatchDisableTags);
	Enable();


	result = PATERR_PatchInUse;
	while(result)

/* Test usecount of all Project related patches */
	{
		for (pointer = (struct Node *) project->PPR_PatchListHeader.lh_Head;
		     pointer->ln_Succ;
		     pointer = (struct Node *)pointer->ln_Succ)
		{
			PatchPointer = (struct Patch *) (((UBYTE *)pointer) -offsetof(struct Patch, PS_ProjectNode.mln_Succ));
			result = TestUsage( PatchPointer);
			if( result == PATERR_Ok) break;
		}

		if (result)
		{
			timeout -= 30;
			if(timeout  < 1)
			{
				/* reenabel patches */
				project->PPR_Flags |= PPRF_InternalCall;
				Disable();		/* Patches muessen gleichzeitig disabled werden */
				SetPatchProjectA(project, SetPatchEnableTags);
				Enable();
				ReleaseSemaphore(&(PatchBase->PB_Semaphore)); /* Release Semaphore in order not to cause an deadlock */
				return( result);

			}

			ReleaseSemaphore(&(PatchBase->PB_Semaphore)); /* Release Semaphore in order not to cause an deadlock */
			MyDelay(30);
			ObtainSemaphore(&(PatchBase->PB_Semaphore));  /* No need to call SAVEObtainSemaphore here, because forbid was already broken by delay */
		}
	}
	for (pointer = (struct Node *) project->PPR_PatchListHeader.lh_Head;
	     pointer->ln_Succ;)
	{
		PatchPointer = (struct Patch *) (((UBYTE *)pointer) -offsetof(struct Patch, PS_ProjectNode));
		pointer = (struct Node *)pointer->ln_Succ;
		RemovePatchTagsA(PatchPointer, taglist);
	}
	ADeleteMyListNode((struct Node *)project);
	ReleaseSemaphore(&(PatchBase->PB_Semaphore));
	return( result);
}
