/*
 wordfind.h

 Author:  Warren Gish
*/
#ifndef __BLAST_WORDFINDER__
#define __BLAST_WORDFINDER__
#include <dfa.h>
#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
		BLAST_Score		high_score;
		unsigned long	neighborhood_words;
		unsigned long	exact_words;

		unsigned long	word_hits;
		unsigned long	failed_extensions;
		/* word_hits - failed_extensions = excluded_hits */
		double	xword_hits;
		double	xfailed_extensions;

		unsigned long	spanned;
		unsigned long	passed;
		unsigned long	reported;
		unsigned long	reportable;
		unsigned long	saved;
		} BLAST_WFSearchStats, PNTR BLAST_WFSearchStatsPtr;

typedef struct {
			BLAST_Diag	diag;
			size_t	pos;
		} BLAST_Diagpos, PNTR BLAST_DiagposPtr;
#define BLAST_DIAGPOS_MAX	MIN(200000,BLAST_DIAG_MAX/sizeof(BLAST_Diagpos))

typedef struct {
			BLAST_OffsetPtr	diag_level, diag_level0;
			BLAST_DiagPtr	diag_stack, diag_stack_top;
			size_t			initlen, alloclen;
		} BLAST_Diagdata, PNTR BLAST_DiagdataPtr;

typedef enum {
	BLAST_WFTYPE_UNKNOWN = 0,
	BLAST_WFTYPE_1,
	BLAST_WFTYPE_2
	} BLAST_WFType, PNTR BLAST_WFTypePtr;

typedef struct _blast_wfcontext {
		unsigned		context;
		BLAST_Diagdata	dd;
		BLAST_ScoreMat	matrix;
		BLAST_Score		cutoff, X;
		struct _blast_wordfinder PNTR	wfp;
		BLAST_StrPtr	query, subject;
		BLAST_LetterPtr	q_str, s_str;
		size_t			q_len;
		BLAST_LetterPtr	sf, sf2;
		unsigned		remain; /* # of letters straggling in the last byte */
		unsigned		W;
		unsigned		enclen; /* encoded length, in bytes */
		unsigned		enclet; /* number of encoded letters */
		BLAST_KarlinBlkPtr	kbp;
		BLAST_ScoreBlkPtr	sbp;
		BLAST_WFSearchStats	stats;
		BLAST_FilterPtr	ffp;
		int				ff_id; /* id of filter function encountering error */
		BLAST_Error		ff_errno; /* errno reported by filter function */
		ValNode		user;
	} BLAST_WFContext, PNTR BLAST_WFContextPtr;

#define BLAST_WORDFINDER_CONTEXT_SHIFT 3
#define BLAST_WORDFINDER_CONTEXT_MAX	8 /* = 2**CONTEXT_SHIFT */
#define BLAST_WORDFINDER_CONTEXT_MASK 0x07

typedef enum _blast_wordfinder_state {
		BLAST_WFSTATE_INVALID=0,
		BLAST_WFSTATE_OPEN,
		BLAST_WFSTATE_CLOSED,
		BLAST_WFSTATE_COMPLETE,
		BLAST_WFSTATE_ZOMBIE
		} BLAST_WFState;

typedef struct _blast_wordfinder {
		ValNode		user;
		BLAST_WFState	state;
		BLAST_WFType	type;
		struct _blast_wordfinder	PNTR root;
		struct _blast_wordfinder	PNTR previous;
		struct _blast_wordfinder	PNTR next;
		size_t			maxlen;
		BLAST_AlphabetPtr	ap;
		BLAST_StrPtr	subject;
		unsigned	bpl, /* bits per letter */
					lpb; /* letters per byte */
		BLAST_WFSearchStats	stats;
		int		(LIBCALLBACK *wordfinder) PROTO((struct _blast_wordfinder PNTR));
		DFAPtr	dp;
		BLAST_Error	wf_errno;
		unsigned	context_cnt, /* no. of contexts that are actually in use */
					context_max, /* total no. of contexts available for use */
					context_mru; /* most-recently-used context */
		BLAST_WFContext	wfcontext[1];
	} PNTR BLAST_WordFinderPtr;

typedef struct _blast_wfhashhit {
		BLAST_Letter	rmask, rchr, lmask, lchr;
		unsigned long	u;
		unsigned char	enclen; /* encoded length */
	} BLAST_WFHashHit, PNTR BLAST_WFHashHitPtr;

typedef int (*BLAST_WFContextWordFltrFnPtr) PROTO((BLAST_FilterPtr ffp, size_t off, BLAST_LetterPtr word, int W, BLAST_ScoreBlkPtr sbp, BLAST_Score T, int slide));
typedef int (*BLAST_WordFltrPtr) PROTO((BLAST_FilterPtr ffp, size_t off, BLAST_LetterPtr word, int W, BLAST_Score T, int slide));


BLAST_WordFinderPtr LIBCALL BlastWordFinderNew PROTO((int neighboring, unsigned ncontexts, BLAST_AlphabetPtr ap, unsigned lpb, size_t maxlen));
BLAST_Error LIBCALL BlastWordFinderDestruct PROTO((BLAST_WordFinderPtr wfp));
BLAST_WFContextPtr LIBCALL BlastWordFinderContextNew PROTO((BLAST_WordFinderPtr, ValNodePtr, BLAST_StrPtr, BLAST_ScoreBlkPtr, int, BLAST_KarlinBlkPtr));
int LIBCALL BlastWFContextWordFltrApply PROTO((BLAST_FilterPtr ffp, BLAST_WFContextPtr wfcp, size_t start, size_t len, BLAST_Score T, int slide));
int LIBCALL	BlastWFContextAddWordFltr PROTO((BLAST_FilterPtr, size_t, BLAST_LetterPtr, int, BLAST_Score, int));
BLAST_Error LIBCALL BlastWordFinderClose PROTO((BLAST_WordFinderPtr));
BLAST_Error LIBCALL	BlastWordFinderComplete PROTO((BLAST_WordFinderPtr));
BLAST_WordFinderPtr LIBCALL	BlastWordFinderLink PROTO((BLAST_WordFinderPtr));
BLAST_Error LIBCALL	BlastWordFinderUnlink PROTO((BLAST_WordFinderPtr));
BLAST_Error LIBCALL BlastWordFinderDiagInit PROTO((BLAST_WordFinderPtr));
BLAST_Error LIBCALL BlastWordFinderDiagDestruct PROTO((BLAST_WordFinderPtr));
BLAST_Error LIBCALL	BlastWordFinderDiagResize PROTO((BLAST_WordFinderPtr wfp, size_t maxlen));
BLAST_Error LIBCALL BlastWordFinderSearchEnter PROTO((BLAST_WordFinderPtr));
BLAST_Error LIBCALL BlastWordFinderSearchExit PROTO((BLAST_WordFinderPtr));
BLAST_Error LIBCALL BlastWordFinderFilterSet PROTO((BLAST_WordFinderPtr, BLAST_FilterPtr));
BLAST_Error LIBCALL BlastWordFinderSubjectSet PROTO((BLAST_WordFinderPtr, BLAST_StrPtr));
BLAST_Error LIBCALL BlastWordFinderExtendParamSet PROTO((BLAST_WordFinderPtr wfp, BLAST_Score X, BLAST_Score cutoff));
BLAST_Error LIBCALL BlastWFContextExtendParamSet PROTO((BLAST_WFContextPtr wfcp, BLAST_Score X, BLAST_Score cutoff));

BLAST_Error LIBCALL	BlastWFSearchStatsMerge PROTO((BLAST_WFSearchStatsPtr dest, BLAST_WFSearchStatsPtr src));
BLAST_Error LIBCALL	BlastWFSearchStatsSum PROTO((BLAST_WFSearchStatsPtr dest, BLAST_WFSearchStatsPtr src));

/****  Typedefs  ****/
#define WFContextPtr		BLAST_WFContextPtr
#define WFType			BLAST_WFType
#define WFTypePtr		BLAST_WFTypePtr
#define WordFinderPtr	BLAST_WordFinderPtr

/****  Function names  ****/
#define WordFinderNew	BlastWordFinderNew
#define WordFinderDup	BlastWordFinderDup
#define WordFinderDestruct	BlastWordFinderDestruct
#define WordFinderAddStr	BlastWordFinderAddStr
#define WFContextAddWord	BlastWFContextAddWord
#define WFDiagDestruct	BlastWFDiagDestruct
#define WordFinderSubjectSet	BlastWordFinderSubjectSet

#ifdef __cplusplus
}
#endif
#endif /* !__BLAST_WORDFINDER__ */

