#include <ncbi.h>
#include <dfa.h>

/***************************************************************************
*	dfa_contains(dp, pattern, patlen, patID)
*
*	Determine whether a given pattern/patID combination is accepted by
*	the DFA.  (This is kind of a mini-dfa_add()).  Only callable while
*	the DFA is in the operational state dfaOpstateOpen.
*
*	Return Values:  NULL if pattern was not found or bad letter in pattern,
*					dfa_patlist * if the pattern was found
***************************************************************************/
DFA_PatlistPtr _cdecl
dfa_contains(dp, pattern, patlen, patID)
	DFAPtr	dp;			/* the initialized DFA structure */
	unsigned char PNTR pattern;	/* the pattern to look for in the DFA */
	size_t	patlen;	/* length of the pattern (in DFA_Letters) */
	DFA_PatID	patID;		/* the associated patID */
{
	DFA_StatePtr	S;
#ifndef DFA_THENEED4SPEED
	int	patChr;
#endif
	DFA_AcceptPtr	A;
	DFA_PatlistPtr	P;
	int	i;
	DFA_StatePtr	state0;

#ifndef DFA_THENEED4SPEED
	if (dp == NULL || dp->magic != DFA_MAGIC) {
		dfaerrno = dfaErrBadPtr;
		return NULL;
	}
	if (dp->opstate != dfaOpstateOpen) {
		dfaerrno = dfaErrOpstate;
		return NULL;
	}
	if (patlen == 0) {
		dfaerrno = dfaErrPatlen;
		return NULL;
	}
#endif

	S = state0 = dp->state0;
	for (i=0; i<patlen-1; ++i) {
#ifndef DFA_THENEED4SPEED
		if ((patChr = *pattern++) < dp->amin || patChr > dp->amax)
			goto BadLetter;
		S = S->next[patChr];
#else
		S = S->next[*pattern++];
#endif
		if (S == state0)
			goto NotFound;
		if (!DFA_ISACCEPTING(S))
			continue;
		A = (DFA_AcceptPtr)DFA_UNMUNGED(S);
		S = A->retState;
		if (S == state0)
			goto NotFound;
	}

#ifndef DFA_THENEED4SPEED
	if ((patChr = *pattern) < dp->amin || patChr > dp->amax)
		goto BadLetter;
	if (!DFA_ISACCEPTING(S = S->next[patChr]))
		goto NotFound;
#else
	if (!DFA_ISACCEPTING(S = S->next[*pattern]))
		goto NotFound;
#endif

	A = (DFA_AcceptPtr)DFA_UNMUNGED(S);
	P = &A->pl;

	do
		if (memcmp((VoidPtr)&P->patID, (VoidPtr)&patID, sizeof(patID)) == 0)
			return (DFA_PatlistPtr)A; /* Found it! */
	while ((P = P->chain) != NULL);

NotFound:
	dfaerrno = dfaErrNotFound;
	return NULL;

#ifndef DFA_THENEED4SPEED
BadLetter:
	dfaerrno = dfaErrNonAlpha;
	return NULL;
#endif
}
