/*
* ===========================================================================
*
*                            PUBLIC DOMAIN NOTICE
*            National Center for Biotechnology Information (NCBI)
*
*  This software/database is a "United States Government Work" under the
*  terms of the United States Copyright Act.  It was written as part of
*  the author's official duties as a United States Government employee and
*  thus cannot be copyrighted.  This software/database is freely available
*  to the public for use. The National Library of Medicine and the U.S.
*  Government do not place any restriction on its use or reproduction.
*  We would, however, appreciate having the NCBI and the author cited in
*  any work or product based on this material
*
*  Although all reasonable efforts have been taken to ensure the accuracy
*  and reliability of the software and data, the NLM and the U.S.
*  Government do not and cannot warrant the performance or results that
*  may be obtained by using this software or data. The NLM and the U.S.
*  Government disclaim all warranties, express or implied, including
*  warranties of performance, merchantability or fitness for any particular
*  purpose.
*
* ===========================================================================
*
* File Name:  gather.c
*
* Author:  Jim Ostell, Jinghui Zhang, Jonathan Kans
*
* Version Creation Date:   10/7/94
*
* $Revision: 6.36 $
*
* File Description: 
*
* Modifications:  
* --------------------------------------------------------------------------
* Date     Name        Description of modification
* -------  ----------  -----------------------------------------------------
*
* $Log: gather.c,v $
* Revision 6.36  2001/11/15 18:47:13  kans
* fix to unindexed get next descriptor
*
* Revision 6.35  2001/11/15 18:34:52  kans
* added GetNextDescriptorUnindexed, requires AssignIDsInEntity be called first
*
* Revision 6.34  2001/07/06 17:27:38  kans
* AssignIDs does not clear deleteme flag
*
* Revision 6.33  2000/12/18 14:48:07  tatiana
* turn off reordering
*
* Revision 6.32  2000/02/07 16:48:34  kans
* fixed setting of context->index in SeqMgrGetNextFeatureByID
*
* Revision 6.31  2000/02/01 22:25:44  kans
* indexed speedup now returns features in itemID order, not position order, to allow simple diff of e2index
*
* Revision 6.30  2000/01/07 03:01:42  kans
* indexed speedup only if raw bioseq not part of segmented bioseq
*
* Revision 6.29  2000/01/07 02:48:13  kans
* useSeqMgrIndexes now works with get_feats_location and get_feats_product, should be suitable for e2index speedup
*
* Revision 6.28  2000/01/07 00:56:02  kans
* targeted bioseq presents features right after bioseq is visited
*
* Revision 6.27  2000/01/07 00:18:25  kans
* targeted bioseq gather visits each seqannot, presents features in seqannot index
*
* Revision 6.26  2000/01/06 23:32:13  kans
* targeted bioseq gather visits each seqfeat, checks against feature/bioseq index
*
* Revision 6.25  1999/11/30 17:07:51  egorov
* Protect against dividing by zero.
*
* Revision 6.24  1999/10/29 18:06:26  kans
* added GetPointerForIDs (with SW)
*
* Revision 6.23  1999/09/30 18:33:09  kans
* delete marked objects corrects gatherindex.prevlink on remaining objects
*
* Revision 6.22  1999/09/29 21:10:53  kans
* delete marked seqannot also frees seqannot if it has no remaining sap->data components
*
* Revision 6.21  1999/09/29 18:24:53  kans
* added DeleteMarkedObjects
*
* Revision 6.20  1999/09/28 18:10:15  kans
* added DeleteMarkedObjectsProc callback - not yet tested
*
* Revision 6.19  1999/09/28 12:10:24  kans
* finished implementing lightweight GatherObjectsInEntity
*
* Revision 6.18  1999/09/27 22:02:45  kans
* further implementation of lightweight gather replacement
*
* Revision 6.17  1999/09/27 17:46:59  kans
* uses GatherIndex structure
*
* Revision 6.16  1999/09/26 20:44:25  kans
* implemented most of VisitProc callbacks
*
* Revision 6.15  1999/09/26 00:17:14  kans
* VisitObjectsInEntity prototype added
*
* Revision 6.14  1999/09/25 01:46:08  kans
* AssignIDsInEntity split into internal function that can also call callback, EXTRA_OBJMGR_FIELDS values assigned to some objects
*
* Revision 6.13  1999/09/07 17:59:52  kans
* AssignIDsInEntity takes datatype and dataptr for when entityID is 0, allowing unlinked components to be updated
*
* Revision 6.12  1999/09/07 17:13:09  kans
* added AssignIDsInEntity
*
* Revision 6.11  1999/09/01 14:41:26  shavirin
* Adjusted functions gather_align_data() and get_align_ends() to accept
* discontinuous alignment type.
*
* Revision 6.10  1999/07/26 20:55:52  ostell
* added recursive support for SAS_DISC SeqAlign
*
* Revision 6.9  1999/03/16 13:17:28  ostell
* changes in SeqLocOffset() to deal with multi-interval seqloc which is
* a subset of a feature.
*
* Revision 6.8  1999/01/13 23:34:19  kans
* added GatherSpecificProcLaunch
*
* Revision 6.7  1998/08/24 18:27:07  kans
* removed solaris -v -fd warnings
*
* Revision 6.6  1998/06/23 16:53:37  zjing
* modify function check_reverse_strand
*
* Revision 6.5  1998/03/10 20:43:28  kans
* IGCCBuild now handles delta seqs
*
* Revision 6.4  1998/03/02 22:15:35  zjing
* fix gap collection in the minus strand in function gather_align_data
*
* Revision 6.3  1997/11/19 22:14:48  ostell
* added support for multithreaded programs
*
* Revision 6.2  1997/10/10 17:01:37  kans
* support for individual elements of OBJ_BIOSEQ_DELTA
*
* Revision 6.1  1997/09/30 19:59:35  zjing
* bug fixes in gather_align_data
*
* Revision 6.0  1997/08/25 18:05:46  madden
* Revision changed to 6.0
*
* Revision 5.15  1997/08/13 18:43:46  zjing
* correct errors in gather_align_data for tblastn and tblastx
*
* Revision 5.14  1997/07/01 15:16:33  zjing
* fix the strand in gathering continous std-seg
*
* Revision 5.13  1997/06/19 18:37:47  vakatov
* [WIN32,MSVC++]  Adopted for the "NCBIOBJ.LIB" DLL'ization
*
* Revision 5.12  1997/04/23 12:44:49  zjing
* correct a bug for tblastn display
*
 * Revision 5.10  1997/03/17  21:22:00  kans
 * detach bioseq/bioseq set didn't unlink gcp->sep->next
 *
 * Revision 5.9  1997/01/15  17:25:45  zjing
 * a kludge fix for ck_extreme to display the features across zero properly
 *
 * Revision 5.8  1996/12/16  19:43:37  ostell
 * added an attachment/replacement of a Seq-loc to a feature in AttachDataProc
 *
 * Revision 5.7  1996/11/05  18:00:03  zjing
 * fix the problem of integer overflow for gather_align_data and speed up the process
 *
 * Revision 5.6  1996/08/29  01:18:34  ostell
 * added GatherAddExtraLoc for codebreak and trna.atncodon mapping
 *
 * Revision 5.5  1996/08/09  20:28:55  epstein
 * eliminate update_seq_loc()
 *
 * Revision 5.4  1996/08/06  19:56:03  kans
 * for SEQLOC_WHOLE, must call SeqIdFindBest on bsp->id
 *
 * Revision 5.3  1996/06/17  21:49:42  zjing
 * fix in gather_align_data for multiple alignments
 *
 * Revision 5.2  1996/06/10  18:35:36  zjing
 * fix in get_end_diag_val
 *
 * Revision 5.1  1996/06/10  15:08:53  epstein
 * replace make_seq_loc() with SeqLocIntNew() and make_pnt_loc with SeqLocPntNew()
 *
 * Revision 5.0  1996/05/28  13:23:23  ostell
 * Set to revision 5.0
 *
 * Revision 4.30  1996/05/22  20:35:25  ostell
 * changed GatherProcLaunch to cycle through proceedures in priority
 * order looking for OM_MSG_RET_DONE return, instead of just launching
 * the first one found.
 *
 * Revision 4.29  1996/05/06  14:49:12  zjing
 * fix a strand in load_align_data
 *
 * Revision 4.28  1996/04/24  20:12:13  ostell
 * removed an uncessary variable
 *
 * Revision 4.27  1996/04/08  15:44:02  kans
 * IGCC build scopes on omdp->choice or scope->scope
 *
 * Revision 4.26  1996/03/08  18:12:38  zjing
 * fix in check_reverse_strand for gather_align_data
 *
 * Revision 4.25  1996/02/28  04:53:06  ostell
 * added ObjMgrHold suport
 *
 * Revision 4.23  1996/01/22  13:28:11  kans
 * cast first parameter of MemSet to (Pointer) for SunOS compiler
 *
 * Revision 4.22  1996/01/03  23:01:04  ostell
 * added GatherOverWrite() to support find/replace external to Gather
 *
 * Revision 4.21  1995/12/22  20:12:01  ostell
 * added protection for NULL pointer on scope in IGCCBuild
 *
 * Revision 4.20  1995/12/22  14:42:30  ostell
 * added do_not_reload_from_cache to GatherScope
 * modified calls to support it
 * changed default behavior of gather to load and reclock entities
 *
 * Revision 4.19  1995/12/20  22:55:36  kans
 * bsp added to FocusSeqEntry, and MemSet (OBJ_MAX+1) bug fixed (JZ)
 *
 * Revision 4.18  1995/12/20  19:19:39  ostell
 * added GatherContext.igccp field
 * added FocusSeqEntry() function
 *
 * Revision 4.17  1995/12/20  15:05:15  zjing
 * Fix gather_align_data to get the end gaps in master sequence
 *
 * Revision 4.16  1995/12/15  15:17:07  kans
 * bsp is now initialized in IGCCBuild
 *
 * Revision 4.15  1995/12/15  02:47:01  ostell
 * fix to scoping for multiple records with same SeqId
 *
 * Revision 4.14  1995/12/14  21:43:04  ostell
 * added scope protection to IGCCBuild to protect against mulitple copies
 *
 * Revision 4.13  1995/12/13  19:28:13  ostell
 * more support for OBJ_SEQHIST_ALIGN
 *
 * Revision 4.12  1995/12/13  18:50:42  ostell
 * added support for OBJ_SEQHIST_ALIGN
 *
 * Revision 4.11  1995/11/21  23:08:38  ostell
 * added support in GatherContext for gatherstack
 *
 * Revision 4.10  1995/11/06  21:29:03  ostell
 * added newid and convert_loc to GatherScope, and new_loc to GatherContext
 * added functions ReMapIntFuzz and SeqLocReMap to support them
 * This allows SeqLocs on features to be copied into a remapped form by gather
 *
 * Revision 4.9  1995/10/06  19:25:24  ostell
 * added fields "ignore_top" and "stop_on_annot" to GatherScope
 * if "ignore_top" is TRUE, features on seglevel 0 are ignored
 * if "stop_on_annot" is TRUE, segments are traversed to a maximum depth
 * of gsp->seglevel, but traversing is stopped as soon as an annotation is
 * found.
 *
 * Revision 4.8  1995/10/01  20:51:28  kans
 * made GatherItemByDataProc static
 *
 * Revision 4.7  1995/09/30  03:38:31  ostell
 * Changed ObjMgrMessage functions to pass a structure
 * Added support for selecting regions
 * Added ability to remove entity when no more views on it
 *
 * Revision 4.6  1995/09/27  19:50:09  zjing
 * .
 *
 * Revision 4.1  1995/08/16  17:48:34  kans
 * add a chain parameter for gather Seq-align (jz)
 *
 * Revision 4.0  1995/07/26  13:49:01  ostell
 * force revision to 4.0
 *
 * Revision 1.38  1995/07/10  15:51:59  kans
 * changes in gather_align_data (zjing)
 *
 * Revision 1.37  1995/07/08  15:22:09  ostell
 * Set ObjMgrDirtyFlag on Attach..,Detach..,ReplaceDataForProc
 *
 * Revision 1.36  1995/06/02  17:53:17  kans
 * add gather range to gather bioseq
 *
 * Revision 1.35  1995/06/01  21:53:55  kans
 * support for Seq-align (zjing)
 *
 * Revision 1.34  1995/05/19  15:49:37  kans
 * fixed bug in mapping minus strand intervals
 *
 * Revision 1.33  1995/05/15  21:46:05  ostell
 * added Log line
 *
*
*
*
* ==========================================================================
*/

#include <gather.h>
#include <edutil.h>
#include <subutil.h>
#include <objfdef.h>
#include <explore.h>

static Boolean NEAR GatherSeqEntryFunc PROTO((SeqEntryPtr sep, InternalGCCPtr igccp, Pointer parent, Uint2 parenttype, SeqEntryPtr prev, Boolean in_scope, Pointer PNTR prevlink));
static Boolean NEAR GatherItemFunc PROTO((Uint2 entityID, Uint2 itemID, Uint2 itemtype,
                                   Pointer userdata, GatherItemProc userfunc, Pointer dataptr,
								   Boolean do_not_reload_from_cache));
static Boolean NEAR GatherAddToStack PROTO((GatherContextPtr gcp));
static void NEAR GatherAddExtraLoc PROTO((GatherContextPtr gcp, SeqLocPtr slp));

static void NEAR GatherAddExtraLoc (GatherContextPtr gcp, SeqLocPtr slp)
{
	SeqLocPtr PNTR tmp;

	gcp->extra_loc_cnt++;
	if (gcp->extra_loc_cnt > gcp->extra_loc_total)
	{
		tmp = gcp->extra_loc;
		gcp->extra_loc = MemNew((size_t)(sizeof(SeqLocPtr) *(gcp->extra_loc_total + 5)));
		MemMove (gcp->extra_loc, tmp,(size_t)(sizeof(SeqLocPtr) *
			(gcp->extra_loc_total)));
		MemFree(tmp);
		gcp->extra_loc_total += 5;
	}
	gcp->extra_loc[gcp->extra_loc_cnt - 1] = slp;
	return;
}

static Boolean NEAR GatherAddToStack (GatherContextPtr gcp)
{
	GatherElementPtr tmp;
	Int2 oldsize;
		
	if (gcp == NULL)
		return FALSE;

	if (gcp->numstack <= gcp->indent)  /* expand stack */
	{
		oldsize = gcp->numstack;
		tmp = gcp->gatherstack;
		gcp->numstack = oldsize + 20;
		gcp->gatherstack = MemNew((size_t)(sizeof(GatherElement) * (gcp->numstack)));
		if (oldsize)
		{
			MemCopy(gcp->gatherstack, tmp, 	(size_t)(sizeof(GatherElement) * (oldsize)));
			MemFree(tmp);
		}
	}

	tmp = gcp->gatherstack + gcp->indent;
	tmp->itemID = gcp->itemID;
	tmp->itemtype = gcp->thistype;
	tmp->tempload = gcp->tempload;
	tmp->thisitem = gcp->thisitem;

	return TRUE;
}

static Boolean ck_extreme(SeqLocPtr slp, BoolPtr across_zero)
{
	SeqLocPtr one_loc;
	SeqIdPtr sip;
	Boolean has_prev;

	*across_zero = FALSE;
	switch(slp->choice)
	{
		case SEQLOC_MIX:
		case SEQLOC_PACKED_PNT:
		case SEQLOC_PACKED_INT:
		   sip = SeqLocId(slp);
		   if(sip == NULL)
			return FALSE;
		   one_loc = NULL;
		   has_prev = FALSE;
		   while((one_loc = SeqLocFindNext(slp, one_loc))!=NULL)
		   {
			if(SeqLocStart(one_loc) == 0)
			{
				if(has_prev && SeqLocStrand(one_loc) != Seq_strand_minus)
					*across_zero = TRUE;
				else if(!has_prev && SeqLocStrand(one_loc) == Seq_strand_minus)
					*across_zero = TRUE;
			}
			if(one_loc->choice == SEQLOC_NULL)
				return FALSE;
			has_prev = TRUE;
		   }
		   return TRUE;

		default:
			return FALSE;
	}
}

static Boolean ck_parts_overlap(SeqLocPtr slp, SeqLocPtr seq_loc)
{
	SeqLocPtr one_loc;

	one_loc = NULL;
	while((one_loc = SeqLocFindNext(slp, one_loc))!=NULL)
	{
		if(one_loc->choice != SEQLOC_NULL)
		{
			if(SeqLocCompare(one_loc, seq_loc) != SLC_NO_MATCH)
				return TRUE;
		}
	}

	return FALSE;
}
	

/*****************************************************************************
*
*   SeqLocOffset(seq_loc, sfp_loc, range, offset)
*   	returns FALSE if seq_loc does not overlap sfp_loc
*   	else fills in range structure mapping sfp_loc to seq_loc
*       adds offset to final values
*       if (ends) will assure that left is always <= right
*
*****************************************************************************/
NLM_EXTERN Boolean SeqLocOffset (SeqLocPtr seq_loc, SeqLocPtr sfp_loc, GatherRangePtr range, Int4 offset)
{
  Uint1    strand_loc, strand_sfp;
  Int4 temp;
  SeqLoc sl;
  SeqInt si;
  Boolean across_zero;
  Int4 toffset, l, r, t;
  Boolean ltrunc, rtrunc;
  SeqLocPtr tslp;

  if (seq_loc == NULL || sfp_loc == NULL || range == NULL) {
    return FALSE;
  }


  if(ck_extreme(sfp_loc, &across_zero))
  {
	if(!across_zero)
	{
		si.from = SeqLocStart(sfp_loc);
		si.to = SeqLocStop(sfp_loc);
		si.strand = SeqLocStrand(sfp_loc);
		si.id = SeqLocId(sfp_loc);
		sl.choice = SEQLOC_INT;
		sl.data.ptrvalue = &si;
		sfp_loc = &sl;
	}
	else if(!ck_parts_overlap(sfp_loc, seq_loc))
		return FALSE;
		
  }

  strand_sfp = SeqLocStrand(sfp_loc);

  toffset = 0;
  l = INT4_MAX;
  r = -1;
  tslp = NULL;

  while ((tslp = SeqLocFindNext(seq_loc, tslp)) != NULL)
  {
	if (SeqLocCompare(tslp, sfp_loc)) {

		strand_loc = SeqLocStrand(tslp);

		t = GetOffsetInLoc(sfp_loc, tslp, SEQLOC_LEFT_END);
		if (t == -1) { /* truncated */
			if (strand_loc == Seq_strand_minus)
				t = toffset + SeqLocLen(tslp) - 1;
			else
				t = toffset;
			
			if (t < l)
			{
				l = t;
				ltrunc = TRUE;
			}
		}
		else if ((t + toffset) < l)
		{
			l = t + toffset;
			ltrunc = FALSE;
		}

		t = GetOffsetInLoc(sfp_loc, tslp, SEQLOC_RIGHT_END);
		if (t == -1)
		{
			if (strand_loc == Seq_strand_minus)
				t = toffset;
			else
				t = toffset + SeqLocLen (tslp) - 1;
			if (t > r) {
				r = t;
				rtrunc = TRUE;
			}

		}
		else if ((t + toffset) > r)
		{
			rtrunc = FALSE;
			r = t + toffset;
		}

	}
	toffset += SeqLocLen(tslp);
  }

  if (r == -1) /* didn't find it */
	return FALSE;

  range->l_trunc = ltrunc;
  range->r_trunc = rtrunc;
  range->left = l + offset;
  range->right = r + offset;

  strand_loc = SeqLocStrand(seq_loc);

  if (strand_loc == Seq_strand_minus)
	range->strand = StrandCmp(strand_sfp);
  else
  {
	if(strand_sfp == Seq_strand_unknown)
		strand_sfp = Seq_strand_plus;
	range->strand = strand_sfp;
  }

  if(range->left > range->right)
  {
	temp = range->left;
	range->left = range->right;
	range->right = temp;
  }

  return TRUE;
}


/*****************************************************************************
*
*   ReMapIntFuzz()
*
*****************************************************************************/
NLM_EXTERN IntFuzzPtr ReMapIntFuzz(IntFuzzPtr ifp, Boolean rev, SeqLocPtr seq_loc, SeqLocPtr sfp_loc, Int4 offset)
{
	IntFuzzPtr newfuzz=NULL;
	SeqInt si;
	SeqPnt sp;
	ValNode vn;
	GatherRange range;
	Int4 i;

	if (ifp == NULL) return newfuzz;

	newfuzz = MemNew(sizeof(IntFuzz));
	MemCopy(newfuzz, ifp, sizeof(IntFuzz));

	switch (ifp->choice)
	{
		case 1:      /* plus/minus - no changes */
		case 3:      /* percent - no changes */
			break;
		case 2:      /* range */
			vn.choice = SEQLOC_INT;
			vn.next = NULL;
			vn.data.ptrvalue = &si;
			MemSet((Pointer)(&si), 0, sizeof(SeqInt));
			si.id = SeqLocId(sfp_loc);
			if (si.id == NULL)
			{
				newfuzz = MemFree(newfuzz);
				break;
			}
			si.strand = SeqLocStrand(sfp_loc);
			if (! SeqLocOffset(seq_loc, &vn, &range, offset))
			{
				newfuzz = MemFree(newfuzz);
				break;
			}

			newfuzz->a = range.right;  /* max */
			newfuzz->b = range.left;	/* min */
			break;
		case 4:     /* lim */
			if (rev)  /* reverse/complement */
			{
				switch (newfuzz->a)
				{
					case 1:    /* greater than */
						newfuzz->a = 2;
						break;
					case 2:    /* less than */
						newfuzz->a = 1;
						break;
					case 3:    /* to right of residue */
						newfuzz->a = 4;
						break;
					case 4:    /* to left of residue */
						newfuzz->a = 3;
						break;
					default:
						break;
				}
			}
			break;
		case 5:      /* alternate positions */
			vn.choice = SEQLOC_PNT;
			vn.next = NULL;
			vn.data.ptrvalue = &sp;
			MemSet((Pointer)(&si), 0, sizeof(SeqPnt));
			sp.id = SeqLocId(sfp_loc);
			if (sp.id == NULL)
			{
				newfuzz = MemFree(newfuzz);
				break;
			}
			sp.strand = SeqLocStrand(sfp_loc);

			newfuzz->alt = MemNew((size_t)(sizeof(Int4) * ifp->b));
			newfuzz->a = 0;

			for (i = 0; i < ifp->a; i++)
			{
				sp.point = ifp->alt[i];

				if (SeqLocOffset(seq_loc, &vn, &range, offset))
				{
					newfuzz->alt[newfuzz->a] = range.left;
					newfuzz->a++;
				}
			}

			if (newfuzz->a == 0)
				newfuzz = IntFuzzFree(newfuzz);

			break;
		default:
			newfuzz = MemFree(newfuzz);
			break;

	}
	return newfuzz;
}


NLM_EXTERN SeqLocPtr SeqLocReMap (SeqIdPtr newid, SeqLocPtr seq_loc, SeqLocPtr head, Int4 offset, Boolean rev)
{
	GatherRange range;
	Uint1 the_strand;

	SeqLocPtr newhead = NULL, last=NULL, tmp, slp, prev, next, thead;
	SeqIntPtr sip, sip2;
	SeqPntPtr spp, spp2;
	PackSeqPntPtr pspp, pspp2;
	SeqBondPtr sbp, sbp2;
	Int4 numpnt, i, tpos, intcnt, othercnt;
	Pointer ptr = NULL;
	Boolean dropped_first, dropped_last, was_equiv = FALSE;
	IntFuzzPtr ifp, ifp1, ifp2;
	ValNode vn;
	SeqPnt sp;
	
	if ((head == NULL) || (seq_loc == NULL) || (newid == NULL)) return NULL;

	if (! SeqLocOffset(seq_loc, head, &range, offset))
		return NULL;

	switch (head->choice)
	{
		case SEQLOC_PACKED_PNT:
			pspp = (PackSeqPntPtr)(head->data.ptrvalue);
			numpnt = PackSeqPntNum(pspp);

			sp.id = pspp->id;
			sp.strand = pspp->strand;
			sp.fuzz = NULL;
			vn.next = NULL;
			vn.choice = SEQLOC_PNT;
			vn.data.ptrvalue = &sp;

			pspp2 = PackSeqPntNew();
			the_strand = range.strand;
			intcnt = 0;	     /* use for included points */
			othercnt = 0;	 /* use for exclued points */
			for (i = 0; i < numpnt; i++)
			{
				sp.point = PackSeqPntGet(pspp, i);

				if (SeqLocOffset(seq_loc, &vn, &range, offset))
				{
					intcnt++;
					PackSeqPntPut(pspp2, range.left);
				}
				else
					othercnt++;
			}
			if (! intcnt)  /* no points in region */
			{
				PackSeqPntFree(pspp2);
				break;
			}

			if (rev)  /* rev comp */
			{
				pspp = pspp2;
				pspp2 = PackSeqPntNew();
				numpnt = PackSeqPntNum(pspp);
				numpnt--;
				for (i = numpnt; i >= 0; i--)	 /* reverse order */
				{
					tpos = PackSeqPntGet(pspp, i);
					PackSeqPntPut(pspp2, tpos);
				}
				PackSeqPntFree(pspp);
			}
			pspp2->id = SeqIdDup(newid);
			pspp2->strand = the_strand;
			pspp2->fuzz = ReMapIntFuzz(pspp->fuzz, rev, seq_loc, head, offset);

			newhead = ValNodeNew(NULL);
			newhead->choice = SEQLOC_PACKED_PNT;
			newhead->data.ptrvalue = (Pointer)pspp2;
            break;
        case SEQLOC_WHOLE:    /* whole */
			newhead = ValNodeNew(NULL);
			sip2 = SeqIntNew();
			sip2->id = SeqIdDup(newid);
			sip2->from = range.left;
			sip2->to = range.right;
			sip2->strand = range.strand;
			if (range.r_trunc)
			{
				ifp = IntFuzzNew();
				ifp->choice = 4;   /* lim */
				ifp->a = 1;        /* greater than */
				sip2->if_to = ifp;
			}

			if (range.l_trunc)
			{
				ifp = IntFuzzNew();
				ifp->choice = 4;   /* lim */
				ifp->a = 2;        /* less than */
				sip2->if_from = ifp;
			}

			newhead->choice = SEQLOC_INT;
			newhead->data.ptrvalue = (Pointer)sip2;
			break;
        case SEQLOC_PNT:    /* pnt */
			spp = (SeqPntPtr)(head->data.ptrvalue);

			spp2 = SeqPntNew();
			spp2->id = SeqIdDup(newid);
			spp2->point = range.left;
			spp2->strand = range.strand;
			spp2->fuzz = ReMapIntFuzz(spp->fuzz, rev, seq_loc, head, offset);

			newhead = ValNodeNew(NULL);
			newhead->choice = SEQLOC_PNT;
			newhead->data.ptrvalue = (Pointer)spp2;
            break;
        case SEQLOC_INT:    /* int */
			sip = (SeqIntPtr)(head->data.ptrvalue);

			sip2 = SeqIntNew();
			sip2->id = SeqIdDup(newid);
			sip2->strand = range.strand;
			sip2->from = range.left;
			sip2->to = range.right;

			if (rev)  /* reverse ends if seq_loc on complement */
			{
				ifp1 = sip->if_to;
				ifp2 = sip->if_from;
			}
			else
			{
				ifp1 = sip->if_from;
				ifp2 = sip->if_to;
			}


			if (range.r_trunc)
			{
				ifp = IntFuzzNew();
				ifp->choice = 4;   /* lim */
				ifp->a = 1;        /* greater than */
				sip2->if_to = ifp;
			}
			else
			{
				sip2->if_to = ReMapIntFuzz(ifp2, rev, seq_loc, head, offset);
			}

			if (range.l_trunc)
			{
				ifp = IntFuzzNew();
				ifp->choice = 4;   /* lim */
				ifp->a = 2;        /* less than */
				sip2->if_from = ifp;
			}
			else
			{
				sip2->if_from = ReMapIntFuzz(ifp1, rev, seq_loc, head, offset);
			}

			newhead = ValNodeNew(NULL);
			newhead->choice = SEQLOC_INT;
			newhead->data.ptrvalue = (Pointer)sip2;
            break;
        case SEQLOC_BOND:   /* bond -- 2 seqs */
			sbp2 = NULL;
			sbp = (SeqBondPtr)(head->data.ptrvalue);
			vn.choice = SEQLOC_PNT;
			vn.data.ptrvalue = sbp->a;
			vn.next = NULL;
			tmp = SeqLocReMap (newid, seq_loc, (SeqLocPtr)(&vn), offset, rev);
			if (tmp != NULL)
			{
			 	sbp2 = SeqBondNew();
				sbp2->a = (SeqPntPtr)(tmp->data.ptrvalue);
				MemFree(tmp);
			}
			if (sbp->b != NULL)
			{
				vn.data.ptrvalue = sbp->b;
				tmp = SeqLocReMap (newid, seq_loc, (SeqLocPtr)(&vn), offset, rev);
				if (tmp != NULL)
				{
					if (sbp2 == NULL)
					{
					 	sbp2 = SeqBondNew();
						sbp2->a = (SeqPntPtr)(tmp->data.ptrvalue);
					}
					else
						sbp2->b = (SeqPntPtr)(tmp->data.ptrvalue);
					MemFree(tmp);
				}
			}
			if (sbp2 != NULL)
			{
				newhead = ValNodeNew(NULL);
				newhead->choice = SEQLOC_BOND;
				newhead->data.ptrvalue = sbp2;
			}
			break;
        case SEQLOC_FEAT:   /* feat -- can't track yet */
        case SEQLOC_NULL:    /* NULL */
        case SEQLOC_EMPTY:    /* empty */
			break;
        case SEQLOC_EQUIV:    /* does it stay equiv? */
		    was_equiv = TRUE;
        case SEQLOC_MIX:    /* mix -- more than one seq */
        case SEQLOC_PACKED_INT:    /* packed int */
			prev = NULL;
			thead = NULL;
			dropped_first = FALSE;
			dropped_last = FALSE;
			for (slp = (SeqLocPtr)(head->data.ptrvalue); slp != NULL; slp = next)
			{
				next = slp->next;
				if (slp->choice == SEQLOC_NULL)   /* special case */
				{
					tmp = NULL;
					if ((prev != NULL) && (next != NULL))
					{
						if (prev->choice != SEQLOC_NULL)
						{
							tmp = ValNodeNew(NULL);
							tmp->choice = SEQLOC_NULL;
						}
					}
				}
				else
					tmp = SeqLocReMap (newid, seq_loc, slp, offset, rev);
				if (tmp != NULL)
				{
					dropped_last = FALSE;
					if (prev != NULL)
					{
						if ((prev->choice == SEQLOC_INT) && (tmp->choice == SEQLOC_INT))
						{
							sip = (SeqIntPtr)(prev->data.ptrvalue);
							sip2 = (SeqIntPtr)(tmp->data.ptrvalue);

							if ((sip->strand == Seq_strand_minus) &&
								(sip2->strand == Seq_strand_minus))
							{
								if (sip->from == (sip2->to + 1))
								{
									sip->from = sip2->from;
									sip->if_from = sip2->if_from;
									sip2->if_from = NULL;
									tmp = SeqLocFree(tmp);
								}
							}
							else if((sip->strand != Seq_strand_minus) &&
								(sip2->strand != Seq_strand_minus))
							{
								if (sip->to == (sip2->from - 1))
								{
									sip->to = sip2->to;
									sip->if_to = sip2->if_to;
									sip2->if_to = NULL;
									tmp = SeqLocFree(tmp);
								}
							}
						}
						else if ((prev->choice == SEQLOC_NULL) && (tmp->choice == SEQLOC_NULL))
						{
							tmp = SeqLocFree(tmp);
						}
					}
					else if (tmp->choice == SEQLOC_NULL)
					{
						tmp = SeqLocFree(tmp);
					}

					if (tmp != NULL)   /* still have one? */
					{
						if (prev != NULL)
							prev->next = tmp;
						else
							thead = tmp;
						prev = tmp;
					}
				}
				else
				{
					if (prev == NULL)
						dropped_first = TRUE;
					else
						dropped_last = TRUE;
				}
			}
			if (prev != NULL)
			{
				if (prev->choice == SEQLOC_NULL)  /* ends with NULL */
				{
					prev = NULL;
					for (slp = thead; slp->next != NULL; slp = slp->next)
						prev = slp;
					if (prev != NULL)
					{
						prev->next = NULL;
						SeqLocFree(slp);
					}
					else
					{
						thead = SeqLocFree(thead);
					}
				}
			}
			if (thead != NULL)
			{
				intcnt = 0;
				othercnt = 0;
				for (slp = thead; slp != NULL; slp = slp->next)
				{
					if (slp->choice == SEQLOC_INT)
						intcnt++;
					else
						othercnt++;
				}
				if ((intcnt + othercnt) > 1)
				{
					newhead = ValNodeNew(NULL);
					if (head->choice == SEQLOC_EQUIV)
						newhead->choice = SEQLOC_EQUIV;
					else
					{
						if (othercnt == 0)
							newhead->choice = SEQLOC_PACKED_INT;
						else
							newhead->choice = SEQLOC_MIX;
					}

					rev = FALSE; /* KLUDGE: turn off reordering */
					if (! rev)
						newhead->data.ptrvalue = (Pointer)thead;
					else                            /* reverse order */
					{
						tmp = NULL;
						while (thead != NULL)
						{
							prev = NULL;
							for (slp = thead; slp->next != NULL; slp = slp->next)
								prev = slp;
							if (prev != NULL)
								prev->next = NULL;
							else
								thead = NULL;
							if (tmp != NULL)
								tmp->next = slp;
							else
								newhead->data.ptrvalue = (Pointer)slp;
							slp->next = NULL;
							tmp = slp;
						}

					}
				}
				else                 /* only one SeqLoc left */
					newhead = thead;

				if ((! was_equiv) && ((dropped_first) || (dropped_last)))
				{                       /* add Int_fuzz when intervals are dropped */
					if (rev)
					{
						was_equiv = dropped_first;
						dropped_first = dropped_last;
						dropped_last = was_equiv;
					}

					slp = NULL;
					tmp = NULL;
					while ((slp = SeqLocFindNext(newhead, slp)) != NULL)
					{
						if ((tmp == NULL) && (dropped_first))   /* first one */
						{
							switch (slp->choice)
							{
								case SEQLOC_INT:
									ifp = IntFuzzNew();
									ifp->choice = 4;   /* lim */
									ifp->a = 2;        /* assume lt */
									sip = (SeqIntPtr)(slp->data.ptrvalue);
									if (sip->strand != Seq_strand_minus)
									{
										sip->if_from = IntFuzzFree(sip->if_from);
										sip->if_from = ifp;
									}
									else
									{
										sip->if_to = IntFuzzFree(sip->if_to);
										sip->if_to = ifp;
										ifp->a = 1;   /* gt */
									}
									break;
								default:
									break;
							}
						}
						tmp = slp;
					}

					if ((tmp != NULL) && (dropped_last))
					{
						switch (tmp->choice)
						{
							case SEQLOC_INT:
								ifp = IntFuzzNew();
								ifp->choice = 4;   /* lim */
								ifp->a = 1;        /* assume gt */
								sip = (SeqIntPtr)(tmp->data.ptrvalue);
								if (sip->strand != Seq_strand_minus)
								{
									sip->if_from = IntFuzzFree(sip->if_from);
									sip->if_from = ifp;
								}
								else
								{
									sip->if_to = IntFuzzFree(sip->if_to);
									sip->if_to = ifp;
									ifp->a = 2;   /* lt */
								}
								break;
							default:
								break;
						}
					}
				}

			}
            break;
        default:
            break;

	}
	return newhead;
}

	/** citttype is currently 0, or 1=OBJ_SEQFEAT_CIT **/

static Boolean NEAR GatherPub(InternalGCCPtr gccp, ValNodePtr vnp,
        Uint1 cittype, Uint1 ttype, Pointer tparent, Pointer PNTR prevlink, Boolean in_scope)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp;
	Boolean takeit;
	Int2 LocateItem = 0;
	Pointer LocateData = NULL;
	Uint1 thistype;

	if (vnp == NULL) return TRUE;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	if (cittype)
		thistype = OBJ_SEQFEAT_CIT;
	else
		thistype = OBJ_PUB;

	if (gsp->ignore[thistype])
		return TRUE;

	takeit = in_scope;

	if (gccp->locatetype == thistype)
	{
		LocateItem = gccp->locateID;
		LocateData = gccp->locatePtr;
	}

	gcp->parentitem = tparent;
	gcp->parenttype = ttype;

	gccp->itemIDs[thistype]++;

	if (LocateItem == gccp->itemIDs[thistype])
		takeit = TRUE;
	if (LocateData == (Pointer)vnp)
		takeit = TRUE;
	if (takeit)
	{
		gcp->itemID = gccp->itemIDs[thistype];
		gcp->thisitem = (Pointer)vnp;
		gcp->thistype = thistype;
		gcp->prevlink = prevlink;
		GatherAddToStack(gcp);
		if (! (*(gccp->userfunc))(gcp))
			return FALSE;
		if (LocateItem) return FALSE;
		if (LocateData != NULL) return FALSE;
	}

	return TRUE;
}

static Boolean NEAR GatherPubSet(InternalGCCPtr gccp, ValNodePtr vnp,
        Uint1 cittype, Uint1 ttype, Pointer tparent, Pointer PNTR prevlink, Boolean in_scope)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp;
	Boolean takeit;
	Int2 LocateItem = 0;
	Pointer LocateData = NULL;
	Uint1 thistype;
	ValNodePtr vnp2;

	if (vnp == NULL) return TRUE;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	if (gsp->ignore[OBJ_PUB_SET])
		return TRUE;

	takeit = in_scope;

	if (gccp->locatetype == OBJ_PUB_SET)
 	{
		LocateItem = gccp->locateID;
		LocateData = gccp->locatePtr;
	}

	gcp->previtem = NULL;
	gcp->prevtype = OBJ_PUB_SET;
	gcp->parentitem = tparent;
	gcp->parenttype = ttype;
	thistype = OBJ_PUB_SET;

	gccp->itemIDs[OBJ_PUB_SET]++;
	if (LocateItem == gccp->itemIDs[OBJ_PUB_SET])
		takeit = TRUE;
	if (LocateData == (Pointer)vnp)
		takeit = TRUE;

	gcp->itemID = gccp->itemIDs[OBJ_PUB_SET];
	gcp->thisitem = (Pointer)vnp;
	gcp->thistype = thistype;
	GatherAddToStack(gcp);

	if (takeit)
	{
		gcp->prevlink = prevlink;
		if (! (*(gccp->userfunc))(gcp))
			return FALSE;
		if (LocateItem) return FALSE;
		if (LocateData != NULL) return FALSE;
	}

	gcp->indent++;
	prevlink = &(vnp->data.ptrvalue);
	gcp->previtem = NULL;
	gcp->prevtype = OBJ_PUB;

	for (vnp2 = (ValNodePtr)(vnp->data.ptrvalue); vnp2 != NULL; vnp2 = vnp2->next)
	{
		if (! GatherPub(gccp, vnp2, cittype, thistype, (Pointer)vnp,
						    prevlink, in_scope))
			return FALSE;
		prevlink = (Pointer PNTR)&(vnp2->next);
		gcp->previtem = (Pointer)vnp2;
	
	}
	gcp->indent--;

	return TRUE;
}

static Boolean NEAR GatherSeqIds(InternalGCCPtr gccp, SeqIdPtr sip,
        Uint1 ttype, Pointer tparent, Pointer PNTR prevlink)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp;
	Boolean takeit;
	Int2 LocateItem = 0;
	Pointer LocateData = NULL;
	Uint1 thistype;

	if (sip == NULL) return TRUE;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	if (gsp->ignore[OBJ_SEQID])
		return TRUE;

	if (gccp->locatetype == OBJ_SEQID)
 	{
		LocateItem = gccp->locateID;
		LocateData = gccp->locatePtr;
	}
	else
		takeit = TRUE;

	gcp->previtem = NULL;
	gcp->prevtype = OBJ_SEQID;
	gcp->parentitem = tparent;
	gcp->parenttype = ttype;
	thistype = OBJ_SEQID;

	while (sip != NULL)
	{
		gccp->itemIDs[OBJ_SEQID]++;
		if (LocateItem == gccp->itemIDs[OBJ_SEQID])
			takeit = TRUE;
		if (LocateData == (Pointer)sip)
			takeit = TRUE;
		if (takeit)
		{
			gcp->itemID = gccp->itemIDs[OBJ_SEQID];
			gcp->thisitem = (Pointer)sip;
			gcp->thistype = thistype;
			gcp->prevlink = prevlink;
			GatherAddToStack(gcp);
			if (! (*(gccp->userfunc))(gcp))
				return FALSE;
			if (LocateItem) return FALSE;
			if (LocateData != NULL) return FALSE;
		}

		gcp->previtem = (Pointer)sip;
		prevlink = (Pointer PNTR)&(sip->next);
		sip = sip->next;
	}

	return TRUE;
}

static Boolean NEAR GatherSeqDescr(InternalGCCPtr gccp, ValNodePtr vnp,
       Uint1 ttype, Pointer tparent, Pointer PNTR prevlink, Boolean in_scope)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp;
	Boolean takeit;
	Int2 LocateItem = 0;
	Pointer LocateData = NULL;
	Uint1 thistype;

	if (vnp == NULL) return TRUE;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	if (gsp->ignore[OBJ_SEQDESC])
		return TRUE;

	if (gccp->locatetype == OBJ_SEQDESC)
 	{
		LocateItem = gccp->locateID;
		LocateData = gccp->locatePtr;
	}

	if ((LocateItem) || (LocateData != NULL))   /* fetching an item */
	{
		takeit = FALSE;
	}
	else
	{
		takeit = in_scope;       /* if ! in_scope don't take it */
		if (gccp->bsp != NULL)   /* gsp->target set a Bioseq */
		{
			if (tparent != (Pointer)(gccp->bsp))
			{
				if (! ObjMgrIsChild(tparent, (Pointer)(gccp->bsp)))
					takeit = FALSE;   /* not in propagation path */
				else
					gcp->propagated = TRUE;
			}
		}
	}

	gcp->previtem = NULL;
	gcp->prevtype = OBJ_SEQDESC;
	gcp->parentitem = tparent;
	gcp->parenttype = ttype;
	thistype = OBJ_SEQDESC;

	while (vnp != NULL)
	{
		gccp->itemIDs[OBJ_SEQDESC]++;
		if (LocateItem == gccp->itemIDs[OBJ_SEQDESC])
			takeit = TRUE;
		if (LocateData == (Pointer)vnp)
			takeit = TRUE;
		if (takeit)
		{
			gcp->itemID = gccp->itemIDs[OBJ_SEQDESC];
			gcp->thisitem = (Pointer)vnp;
			gcp->thistype = thistype;
			gcp->prevlink = prevlink;
			GatherAddToStack(gcp);
			if (! (*(gccp->userfunc))(gcp))
				return FALSE;
			if (LocateItem) return FALSE;
			if (LocateData != NULL) return FALSE;
		}

		gcp->previtem = (Pointer)vnp;
		prevlink = (Pointer PNTR)&(vnp->next);
		vnp = vnp->next;
	}
	gcp->propagated = FALSE;   /* reset propagated flag */

	return TRUE;
}


static Int4 get_site_offset(SeqLocPtr slp, SeqLocPtr head, Int4 r_len)
{
	Uint1 m_strand, s_strand;

	m_strand = SeqLocStrand(slp);
	s_strand = SeqLocStrand(slp);

	if(m_strand == 0 || s_strand ==0)
		return 0;
	if(m_strand == 3 || s_strand == 3)
		return 0;

	if(m_strand == s_strand)
		return 0;

	if(m_strand == Seq_strand_plus && s_strand == Seq_strand_minus)
		return (-r_len);
	else
		return r_len;
}


static Boolean process_packed_pnt(SeqLocPtr slp, SeqLocPtr head, Int4 r_len, Int4 offset, GatherContextPtr gcp, Int2Ptr max_interval)
{
        PackSeqPntPtr pspp;
	Int4 site;
	Int4 site_offset;	/*for treating restriction site as an interval*/
	Int2 index;
	Int4 m_start, m_stop;
	Uint1 m_strand;
	Int4 min, max;
	Boolean rev;
	Int4 pos, ctr, i;
	GatherRangePtr trdp, lrdp;
	GatherRange trange;
	Boolean is_end = FALSE;

	if(head->choice !=SEQLOC_PACKED_PNT)
		return FALSE;

	if(!SeqIdForSameBioseq(SeqLocId(slp), SeqLocId(head)))
		return FALSE;
	m_strand = SeqLocStrand(slp);
	site_offset = get_site_offset(slp, head, (r_len-1));
	rev = (SeqLocStrand(slp) == Seq_strand_minus);
	lrdp = gcp->rdp;


	m_start = SeqLocStart(slp);
	m_stop = SeqLocStop(slp);
	pspp = head->data.ptrvalue;
        site =0;
        index =0;
	min = -1;
	max = -1;
	ctr = 0;
        while( !is_end && ((site = PackSeqPntGet(pspp, index))!= -1))
        {
                ++index;
		if (ctr >= (*max_interval))
		{
			trdp = lrdp;
			lrdp = (GatherRangePtr)MemNew((size_t)((*max_interval + 20) * sizeof(GatherRange)));
			MemCopy(lrdp, trdp, (size_t)(*max_interval * sizeof(GatherRange)));
			MemFree(trdp);
			*max_interval += 20;
			gcp->rdp = lrdp;
		}
		is_end = (site > m_stop);
                if(site >= m_start && site <=m_stop)
                {
			site += site_offset;
                        if(rev)
				pos = offset + (m_stop - site);
			else
				pos = offset + (site - m_start);
			if(max == -1)
			{
				max = pos;
				min = pos;
			}
			else
			{
				max = MAX(pos, max);
				min = MIN(pos, min);
			}
			lrdp[ctr].left = pos;
			lrdp[ctr].right = pos;
			lrdp[ctr].l_trunc = FALSE;
			lrdp[ctr].r_trunc = FALSE;
			lrdp[ctr].strand = m_strand;
			++ctr;
		}
	}

	if (ctr)     /* got some */
	{
		gcp->extremes.left = min;
		gcp->extremes.right = max;
		gcp->extremes.l_trunc = FALSE;
		gcp->extremes.r_trunc = FALSE;
		gcp->extremes.strand = m_strand;

		gcp->num_interval = (Int2)ctr;
		if (rev)    /* reverse order on rev location */
		{
			i = 0;
			ctr--;
			while (i < ctr)
			{
				MemCopy(&trange, &(lrdp[i]), sizeof(GatherRange));
				MemCopy(&(lrdp[i]), &(lrdp[ctr]), sizeof(GatherRange));
				MemCopy(&(lrdp[ctr]), &trange, sizeof(GatherRange));
				i++; ctr++;
			}
		}
		return TRUE;
	}
	else
		return FALSE;
}

/* functions to speed up targeted feature gather by using seqmgr explore index */

static ObjMgrDataPtr GatherGetOmdpForBioseq (BioseqPtr bsp)

{
  ObjMgrDataPtr  omdp;
  ObjMgrPtr      omp;

  if (bsp == NULL) return NULL;
  omdp = (ObjMgrDataPtr) bsp->omdp;
  if (omdp != NULL) return omdp;
  omp = ObjMgrWriteLock ();
  omdp = ObjMgrFindByData (omp, bsp);
  ObjMgrUnlock ();
  bsp->omdp = (Pointer) omdp;
  return omdp;
}

static SeqFeatPtr LIBCALL SeqMgrGetNextFeatureByID (BioseqPtr bsp, SeqFeatPtr curr,
                                                    Uint1 seqFeatChoice, Uint1 featDefChoice,
                                                    SeqMgrFeatContext PNTR context)

{
  BioseqExtraPtr      bspextra;
  Uint2               entityID;
  SMFeatItemPtr PNTR  featsByID;
  Uint2               i;
  SMFeatItemPtr       item;
  ObjMgrDataPtr       omdp;
  Uint1               seqfeattype;

  if (context == NULL) return NULL;

  if (curr == NULL) {
    if (bsp == NULL) return NULL;
    omdp = GatherGetOmdpForBioseq (bsp);
    if (omdp == NULL || omdp->datatype != OBJ_BIOSEQ) return NULL;

    context->omdp = (Pointer) omdp;
    context->index = 0;
  }

  omdp = (ObjMgrDataPtr) context->omdp;
  if (omdp == NULL) return NULL;
  bspextra = (BioseqExtraPtr) omdp->extradata;
  if (bspextra == NULL) return NULL;
  featsByID = bspextra->featsByID;
  if (featsByID == NULL || bspextra->numfeats < 1) return NULL;

  entityID = ObjMgrGetEntityIDForPointer (omdp->dataptr);

  i = context->index;

  while (i < bspextra->numfeats) {
    item = featsByID [i];
    if (item != NULL) {
      curr = item->sfp;
      i++;
      if (curr != NULL) {
        seqfeattype = curr->data.choice;
        if ((seqFeatChoice == 0 || seqfeattype == seqFeatChoice) &&
            (featDefChoice == 0 || item->subtype == featDefChoice) &&
            (! item->ignore)) {
          context->entityID = entityID;
          context->itemID = item->itemID;
          context->sfp = curr;
          context->sap = item->sap;
          context->bsp = item->bsp;
          context->label = item->label;
          context->left = item->left;
          context->right = item->right;
          context->dnaStop = item->dnaStop;
          context->partialL = item->partialL;
          context->partialR = item->partialR;
          context->farloc = item->farloc;
          context->strand = item->strand;
          context->seqfeattype = seqfeattype;
          context->featdeftype = item->subtype;
          context->numivals = item->numivals;
          context->ivals = item->ivals;
          context->userdata = NULL;
          context->omdp = (Pointer) omdp;
          context->index = i;
          return curr;
        }
      }
    }
  }

  return NULL;
}

static Boolean NEAR ExploreSeqFeat (
  InternalGCCPtr gccp,
  BioseqPtr bsp,
  Boolean in_scope
)

{
  SeqMgrFeatContext  fcontext;
  GatherContextPtr   gcp;
  GatherScopePtr     gsp;
  SeqFeatPtr         sfp;
  Boolean            takecit;
  ValNodePtr         vnp;

  /* gccp->locatetype is known to be NULL if target used */

  if (gccp == NULL || bsp == NULL) return TRUE;

  gcp = &(gccp->gc);
  gsp = &(gccp->scope);

  if (gsp->ignore [OBJ_SEQFEAT]) return TRUE;
  if (gsp->ignore [OBJ_SEQFEAT_CIT]) {
    takecit = FALSE;
  } else {
    takecit = TRUE;
  }

  gcp->num_interval = 0;

  if (gsp->get_feats_location) {
    sfp = SeqMgrGetNextFeatureByID (bsp, NULL, 0, 0, &fcontext);
    while (sfp != NULL) {

      gcp->previtem = NULL;
      gcp->prevtype = OBJ_SEQFEAT;

      gcp->parentitem = sfp->idx.parentptr;
      gcp->parenttype = sfp->idx.parenttype;

      gcp->itemID = sfp->idx.itemID;
      gcp->thisitem = (Pointer) sfp;
      gcp->thistype = OBJ_SEQFEAT;
      gcp->prevlink = sfp->idx.prevlink;

      gcp->product = FALSE;

      GatherAddToStack (gcp);
      if (! (*(gccp->userfunc)) (gcp)) return FALSE;

      if (sfp->cit != NULL && takecit) {
        if (! GatherPubSet (gccp, sfp->cit, 1, OBJ_SEQFEAT, (Pointer) sfp,
                            (Pointer PNTR) &(sfp->cit), in_scope))
          return FALSE;
      }

      sfp = SeqMgrGetNextFeatureByID (bsp, sfp, 0, 0, &fcontext);
    }
  }

  if (gsp->get_feats_product) {
    for (vnp = SeqMgrGetSfpProductList (bsp); vnp != NULL; vnp = vnp->next) {
      sfp = (SeqFeatPtr) vnp->data.ptrvalue;
      if (sfp != NULL) {

        gcp->previtem = NULL;
        gcp->prevtype = OBJ_SEQFEAT;

        gcp->parentitem = sfp->idx.parentptr;
        gcp->parenttype = sfp->idx.parenttype;

        gcp->itemID = sfp->idx.itemID;
        gcp->thisitem = (Pointer) sfp;
        gcp->thistype = OBJ_SEQFEAT;
        gcp->prevlink = sfp->idx.prevlink;

        gcp->product = TRUE;

        GatherAddToStack (gcp);
        if (! (*(gccp->userfunc)) (gcp)) return FALSE;

        if (sfp->cit != NULL && takecit) {
          if (! GatherPubSet (gccp, sfp->cit, 1, OBJ_SEQFEAT, (Pointer) sfp,
                              (Pointer PNTR) &(sfp->cit), in_scope))
            return FALSE;
        }
      }
    }
  }

  /* ignoring sfp->cit on non-targeted records, not keeping counter in synch */

  return TRUE;
}

static Boolean NEAR GatherSeqFeat(InternalGCCPtr gccp, SeqFeatPtr sfp,
           Uint1 ttype, Pointer tparent, Pointer PNTR prevlink, Boolean in_scope, Uint1 sfptype)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp;
	Boolean takeit=TRUE,
		takecit, checkseq=FALSE;
	SeqLocPtr slp, head, tslp, target[2];
	GatherRangePtr rdp, trdp, lrdp;
	Int4 offset, totlen, left_end;
	Boolean rev, revs[2];
	Int2 ctr, max_interval, i, numcheck, j;
	GatherRange trange;
	Int2 LocateItem = 0;
	Pointer LocateData = NULL;
	Uint1 thistype;
	Boolean is_packed_pnt = FALSE;	/*is the seq-loc a packed point?*/
	Boolean stop_now, convert_loc = FALSE;
	SeqIdPtr newid;
	CdRegionPtr cdr;
	CodeBreakPtr cbp;
	RnaRefPtr rrp;
	tRNAPtr trp;


	SeqFeatPtr prevsfp = NULL;

	if (sfp == NULL) return TRUE;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	if (gsp->ignore[sfptype])
		return TRUE;

	if (gccp->locatetype == sfptype)
 	{
		LocateItem = gccp->locateID;
		LocateData = gccp->locatePtr;
	}
	else
		LocateItem = 0;

	if (gsp->target != NULL)
	{
		checkseq = TRUE;
		numcheck = 1;
		target[0] = gsp->target;
		revs[0] = gccp->rev;
		if (gccp->segloc != NULL)
		{
			numcheck = 2;
			target[1] = gccp->segloc;
			revs[1] = FALSE;
		}
		rdp = &(gcp->extremes);
		offset = gsp->offset;
		max_interval = gccp->max_interval;
		lrdp = gcp->rdp;

		convert_loc = gsp->convert_loc;
		newid = gsp->newid;
	}

	if (gsp->ignore[OBJ_SEQFEAT_CIT])
		takecit = FALSE;
	else
		takecit = TRUE;

	gcp->prevtype = sfptype;
	gcp->parentitem = tparent;
	gcp->parenttype = ttype;
	gcp->num_interval = 0;
	thistype = sfptype;

	while (sfp != NULL)
	{
		gcp->previtem = (Pointer) prevsfp;
		gccp->itemIDs[sfptype]++;
		if (LocateItem == gccp->itemIDs[sfptype])
			in_scope = TRUE;
		if (LocateData == (Pointer)sfp)
			in_scope = TRUE;

		gcp->itemID = gccp->itemIDs[sfptype];
		takeit = TRUE;
		stop_now = FALSE;

		if (in_scope)
		{
			gcp->thisitem = (Pointer)sfp;
			gcp->thistype = thistype;
			gcp->prevlink = prevlink;
			gcp->product = FALSE;
			head = sfp->location;
			if (checkseq)    /* find by SeqLoc overlap */
			{
				takeit = FALSE;
				is_packed_pnt = (head->choice == SEQLOC_PACKED_PNT);
				for (j = 0; ((j < numcheck) && (! takeit) && (!stop_now)); j++)
				{
					slp = target[j];
					rev = revs[j];
					if (gsp->get_feats_location)
					{
						if(is_packed_pnt)
						{
							if(process_packed_pnt(slp, head, 0, offset, gcp, &(gccp->max_interval)))
							{
								takeit = TRUE;
								stop_now= TRUE;
							}
						}
						else
							takeit = SeqLocOffset(slp, head, rdp, offset);
					}

					if ((! takeit) && (gsp->get_feats_product))
					{
						head = sfp->product;
						takeit = SeqLocOffset(slp, head, rdp, offset);
						if (takeit)
							gcp->product = TRUE;
					}

					if ((takeit) && (! gsp->nointervals) && (!stop_now))  /* map intervals in loc */
					{
						tslp = NULL;
						ctr = 0;
						while ((tslp = SeqLocFindNext(head, tslp)) != NULL)
						{
							if (ctr >= max_interval)
							{
								trdp = lrdp;
								lrdp = (GatherRangePtr)MemNew((size_t)((max_interval + 20) * sizeof(GatherRange)));
								MemCopy(lrdp, trdp, (size_t)(max_interval * sizeof(GatherRange)));
								MemFree(trdp);
								max_interval += 20;
								gccp->max_interval = max_interval;
								gcp->rdp = lrdp;
							}
							if (SeqLocOffset(slp, tslp, &(lrdp[ctr]), offset))
								ctr++;
						}
						if (ctr)     /* got some */
						{
							gcp->num_interval = ctr;
							if (rev)    /* reverse order on rev location */
							{
								i = 0;
								ctr--;
								while (i < ctr)
								{
									MemCopy(&trange, &(lrdp[i]), sizeof(GatherRange));
									MemCopy(&(lrdp[i]), &(lrdp[ctr]), sizeof(GatherRange));
									MemCopy(&(lrdp[ctr]), &trange, sizeof(GatherRange));
									i++; ctr--;
								}
							}
						}
					}

					if ((takeit) && (convert_loc) && (! stop_now)) /* convert SeqLoc */
					{
						gcp->new_loc = SeqLocReMap(newid, slp, head, offset, rev);
						if (gsp->get_feats_location)
						{
							gcp->extra_loc_cnt = 0;
							if (sfp->data.choice == SEQFEAT_CDREGION)
							{
								cdr = (CdRegionPtr)(sfp->data.value.ptrvalue);
								for (cbp = cdr->code_break; cbp != NULL;
										cbp = cbp->next)
								{
									tslp = SeqLocReMap(newid, slp, cbp->loc, offset, rev);
									GatherAddExtraLoc(gcp, tslp);
								}
							}
							else if (sfp->data.choice == SEQFEAT_RNA)
							{
								rrp = (RnaRefPtr)(sfp->data.value.ptrvalue);
								if ((rrp->ext.choice == 2) && 
									(rrp->ext.value.ptrvalue != NULL)) /* tRNA */
								{
									trp = (tRNAPtr)(rrp->ext.value.ptrvalue);
									if (trp->anticodon != NULL)
									{
										tslp = SeqLocReMap(newid, slp, trp->anticodon,
											offset, rev);
										GatherAddExtraLoc(gcp, tslp);
									}
								}
							}
						}
					}
				}
			}

			if (takeit)
			{
				if (gccp->segcnt)    /* which segment was it in? */
				{
					left_end = offset;
					for (i = 0; i < gccp->segcnt; i++)
					{
						totlen = left_end + gccp->seglens[i];
						if ((rdp->left >= left_end) && (rdp->left < totlen))
							gccp->found_annot[i] = TRUE;
						else if ((rdp->right >= left_end) && (rdp->right < totlen))
							gccp->found_annot[i] = TRUE;
						left_end = totlen;
					}	
				}

				GatherAddToStack(gcp);
				if (! (*(gccp->userfunc))(gcp))
					return FALSE;
				if (LocateItem) return FALSE;
				if (LocateData != NULL) return FALSE;

				if ((sfp->cit != NULL) && (takecit))
				{
					if (! GatherPubSet(gccp, sfp->cit, 1, thistype, (Pointer)sfp,
						                                (Pointer PNTR)&(sfp->cit), in_scope))
						return FALSE;

					gcp->prevtype = thistype;
					gcp->parentitem = tparent;
					gcp->parenttype = ttype;
				}
			}
		}
		else /* out of scope */
		{

			if (sfp->cit != NULL)  /* just run the counter */
			{
				if (! GatherPubSet(gccp, sfp->cit, 1, thistype, (Pointer)sfp,
					                                (Pointer PNTR)&(sfp->cit), in_scope))
					return FALSE;

				gcp->prevtype = thistype;
				gcp->parentitem = tparent;
				gcp->parenttype = ttype;
			}
		}

		prevsfp = sfp;
		prevlink = (Pointer PNTR)&(sfp->next);
		sfp = sfp->next;
	}
	return TRUE;
}

static Uint1 align_strand_get(Uint1Ptr strands, Int2 order)
{
        if(strands == NULL)
                return 0;
        else
                return strands[order];
}

static Boolean check_reverse_strand(Uint1 loc_strand, Uint1 a_strand)
{
	if(loc_strand == Seq_strand_minus || a_strand == Seq_strand_minus)
		return (loc_strand != a_strand);
	return FALSE;

}

/****************************************************************************
***
*       get_align_ends(): map the two ends of the alignment
*
*****************************************************************************
***/

static void load_start_stop(Int4Ptr start, Int4Ptr stop, Int4 c_start, Int4 c_stop)
{
	if(*start == -1)
	{
		*start = c_start;
		*stop = c_stop;
	}
	else
	{
		*start = MIN(*start, c_start);
		*stop = MAX(*stop, c_stop);
	}
}

static Int2 get_master_order(SeqIdPtr ids, SeqIdPtr sip)
{
	Int2 i;
	
	for(i =0; ids!=NULL; ids = ids->next, ++i)
	{
		if(SeqIdForSameBioseq(ids, sip))
			return i;
	}
	return -1;
}

NLM_EXTERN Boolean get_align_ends(SeqAlignPtr align, SeqIdPtr id, 
                                  Int4Ptr start, Int4Ptr stop, Uint1Ptr strand)
{
    Int2 i, n;
    Boolean is_found;
    Int4 c_start, c_stop;
    DenseSegPtr dsp;
    DenseDiagPtr ddp;
    StdSegPtr ssp;
    SeqLocPtr loc;
    SeqAlignPtr sap;

    *start = -1;
    *stop = -1;
    switch(align->segtype) {
    case 5: /* Discontinuous alignment */
        
        sap = (SeqAlignPtr)(align->segs);
        
        for(; sap != NULL; sap = sap->next) {
            if(!get_align_ends(sap, id, &c_start, &c_stop, strand))
                return FALSE;
            load_start_stop(start, stop, c_start, c_stop);
        }
        return (*start != -1);
        
    case 2:         /*DenseSeg*/
        dsp = (DenseSegPtr)(align->segs);
        if(id == NULL)
            i =0;
        else {
            i = get_master_order(dsp->ids, id);
            if( i == -1)
                return FALSE;
        }
        
        for(n =0; n<dsp->numseg; ++n) {
            c_start = dsp->starts[n*(dsp->dim) +i];
            if(c_start != -1) { /*check for a non-gapped region*/
                c_stop = c_start + dsp->lens[n] -1;
                load_start_stop(start, stop, c_start, c_stop);
            }
        }
        *strand = align_strand_get(dsp->strands, i);
        return (*start != -1);
        
    case 3:
        ssp = (StdSegPtr)(align->segs);
        while(ssp) {
            is_found = FALSE;
            for (loc = ssp->loc; loc!=NULL && !is_found; loc=loc->next) {
                if(loc->choice != SEQLOC_EMPTY) {
                    if(id == NULL)
                        is_found = TRUE;
                    else
                        
                        is_found=SeqIdForSameBioseq(SeqLocId(loc), id);
                    if(is_found) {
                        load_start_stop(start, stop, SeqLocStart(loc), SeqLocStop(loc));
                        *strand = SeqLocStrand(loc);
                    }
                }
            }
            ssp = ssp->next;
        }
        return (*start != -1);
        
    case 1:
        ddp = (DenseDiagPtr)(align->segs);
        while(ddp) {
            if(id == NULL)
                i =0;
            else
                i = get_master_order(ddp->id, id);
            if(i != -1) {
                c_start = ddp->starts[i];
                c_stop = ddp->starts[i] + ddp->len -1;
                *strand = align_strand_get(ddp->strands, i);
                load_start_stop(start, stop, c_start, c_stop);
            }
            ddp = ddp->next;
        }			
        return (*start != -1);
        
    default:
        return FALSE;
    }
}
	
				
static void LinkAlignData(AlignDataPtr PNTR head, AlignDataPtr adp)
{
	AlignDataPtr curr;
	
	if(*head == NULL)
		*head = adp;
	else
	{
		curr = *head;
		while(curr->next != NULL)
			curr = curr->next;
		curr->next = adp;
	}
}

static void LinkAlignRangeToAlignData(AlignDataPtr adp, AlignRangePtr arp)
{
	
	if(arp == NULL)
		return;
	if(adp->arp  == NULL)
		adp->arp = arp;
	else
		adp->last->next = arp;
	adp->last = arp;
}

static AlignDataPtr get_adp_node(AlignDataPtr head, Int2 order, Uint2 chain)
{
	if(head == NULL)
		return NULL;
	while(head)
	{
		if(head->order == order && head->chain == chain)
			return head;
		head = head->next;
	}
	return NULL;
}



static void load_align_data(AlignDataPtr PNTR head, Int4 start, Int4 stop, Uint1 strand, SeqIdPtr sip, Boolean rev, Int2 seg_type, GatherRange t_range, Boolean ck_interval, Int2 order, Uint2 chain)
{
	AlignDataPtr adp;
	AlignRangePtr arp;
	Int4 left, right;
	
	adp = get_adp_node(*head, order, chain);
	if(rev)
	{
		if(strand == Seq_strand_minus)
			strand = Seq_strand_plus;
		else
			strand = Seq_strand_minus;
	}
	if(adp == NULL)
	{
		adp = MemNew(sizeof(AlignData));
		adp->chain= chain;
		adp->order = order;
		adp->sip = sip;
		MemCopy((&adp->extremes), &t_range, sizeof(GatherRange));
		adp->extremes.strand = strand;
		if(seg_type != GAP_SEG)
		{
			adp->seqends.start = start;
			adp->seqends.stop = stop;
		}
		else
		{
			adp->seqends.start = -1;
			adp->seqends.stop = -1;
		}
		adp->seqends.strand = strand;
		adp->arp = NULL;
		adp->next = NULL;
		LinkAlignData(head, adp);
	}
	else
	{
	    left = adp->extremes.left;
	    right = adp->extremes.right;
	    if(t_range.left < left)
	    {
	    	adp->extremes.left = t_range.left;
		adp->extremes.l_trunc = t_range.l_trunc;
	    }
	    if(t_range.right > right)
	    {
	    	adp->extremes.right = t_range.right;
		adp->extremes.r_trunc = t_range.r_trunc;
	    }
	    if(seg_type != GAP_SEG)
	    {
		if(adp->seqends.start == -1)
		{
			adp->seqends.start = start;
			adp->seqends.stop = stop;
		}
		else
		{
			adp->seqends.start = MIN(start, adp->seqends.start);
			adp->seqends.stop = MAX(stop, adp->seqends.stop);
		}
	    }
	}	
		
		
	if(ck_interval)
	{
		arp = MemNew(sizeof(AlignRange));
		arp->segtype = (Uint1)seg_type;
		MemCopy(&(arp->gr), &t_range, sizeof(GatherRange));
		arp->sr.start = start;
		arp->sr.stop = stop;
		arp->sr.strand = strand;
		LinkAlignRangeToAlignData(adp, arp);
	}
}


static Boolean get_end_diag_val(DenseSegPtr dsp, Int2 m_order, Int2 k_seg, Int4Ptr start, Int4Ptr stop, Boolean first)
{
	Int2 i, k;
	Int2 dim;
	Boolean increase = TRUE;

	dim = dsp->dim;
	if(first)
		k = k_seg;
	else
		k = dsp->numseg-1 -k_seg;

	increase = (k ==0);
		
	for(i =0; i<dsp->numseg; ++i)
	{
		if(dsp->starts[dim*k+m_order] != -1)
		{
			*start = dsp->starts[dim*k+m_order];
			*stop = *start + dsp->lens[k] -1;
			return TRUE;
		}
		if(increase)
			++k;
		else
			--k;
	}
	return FALSE;
}

static void load_trunc_info(SeqLocPtr slp, GatherRangePtr grp)
{
	SeqIntPtr sint;
	Boolean f_trunc = FALSE, t_trunc = FALSE;
	IntFuzzPtr ifp;

	if(slp == NULL || grp == NULL)
		return;
	if(slp->choice != SEQLOC_INT)
		return;
	sint = slp->data.ptrvalue;
	if(sint != NULL)
	{
		ifp = sint->if_from;
		if(ifp)
		{
			if(ifp->choice == 4 && ifp->a == 2)
				f_trunc = TRUE;
		}
		ifp = sint->if_to;
		if(ifp)
		{
			if(ifp->choice == 4 && ifp->a == 1)
				t_trunc = TRUE;
		}
	}
	
	grp->l_trunc = f_trunc;
	grp->r_trunc = t_trunc;
	if(grp->strand != sint->strand)
	{
		if(grp->strand == Seq_strand_minus || sint->strand == Seq_strand_minus)
		{
			grp->l_trunc = t_trunc;
			grp->r_trunc = f_trunc;
		}
	}
}

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

static Boolean is_end_gaps_for_master(DenseSegPtr dsp, Int2 m_order, Int2 k_seg, Int2 j_seg, Boolean left)
{
	Int2 i, k;
	Boolean is_gap = FALSE;
	Boolean increase;

	/*get the first non-gap segment*/
	if(left)
		k = k_seg;
	else
		k = dsp->numseg-1 - k_seg;
	increase = (k ==0);
	for(i = 0; i<dsp->numseg; ++i)
	{
		if(dsp->starts[(dsp->dim)*k+m_order] != -1)
			return FALSE;
		else
		{
			if(j_seg == k)
				return TRUE;
		}
		if(increase)
			++k;
		else
			--k;
	}

	return FALSE;
}

static Uint1 get_master_strand_for_continous_ssp (StdSegPtr ssp, SeqIdPtr m_sip)
{
	SeqLocPtr loc;

	while(ssp)
	{
		for(loc= ssp->loc; loc!=NULL; loc = loc->next)
		{
			if(SeqIdMatch(SeqLocId(loc), m_sip))
			{
				if(loc->choice != SEQLOC_EMPTY)
					return SeqLocStrand(loc);
			}
		}

		ssp = ssp->next;
	}

	return 0;
}

static Int2 get_ssp_numseg (StdSegPtr ssp)
{
	Int2 i = 0;

	while(ssp)
	{
		++i;
		ssp = ssp->next;
	}

	return i;
}

static StdSegPtr get_nth_ssp (StdSegPtr ssp, Int2 order)
{
	Int2 i;

	i = 0;
	while(ssp)
	{
		if(i == order)
			return ssp;
		++i;
		ssp = ssp->next;
	}

	return NULL;
}

static Boolean is_fuzz_loc (SeqLocPtr slp)
{
	SeqLocPtr t_slp;
	SeqIntPtr sint;
	SeqPntPtr spp;

	t_slp = NULL;
	while((t_slp = SeqLocFindNext(slp, t_slp)) != NULL)
	{
		if(t_slp->choice == SEQLOC_INT)
		{
			sint = t_slp->data.ptrvalue;
			if(sint->if_from || sint->if_to)
				return TRUE;
		}
		else if(t_slp->choice == SEQLOC_PNT)
		{
			spp = t_slp->data.ptrvalue;
			if(spp->fuzz)
				return TRUE;
		}
	}

	return FALSE;
}
			
static Int4 calculate_mag_val (StdSegPtr ssp, SeqIdPtr m_sip, BoolPtr inverse)
{
	SeqLocPtr m_slp, s_slp;
	SeqLocPtr slp;
	Int4 mag_val;

	while(ssp)
	{
		m_slp = NULL;
		s_slp = NULL;
		for(slp = ssp->loc; slp != NULL; slp = slp->next)
		{
			if(SeqIdMatch(SeqLocId(slp), m_sip))
				m_slp = slp;
			else
				s_slp = slp;
		}

		if(m_slp && s_slp && SeqLocLen(m_slp) && SeqLocLen(s_slp))
		{
			if(!is_fuzz_loc(m_slp) && !is_fuzz_loc(s_slp))
			{
				if(SeqLocLen(m_slp) > SeqLocLen(s_slp))
				{
					mag_val = SeqLocLen(m_slp)/SeqLocLen(s_slp);
					if(SeqLocLen(m_slp)%SeqLocLen(s_slp) == 0)
					{
						*inverse = FALSE;
						return mag_val;
					}
				}
				else
				{
					mag_val = SeqLocLen(s_slp)/SeqLocLen(m_slp);
					if(SeqLocLen(s_slp)%SeqLocLen(m_slp) == 0)
					{
						*inverse = TRUE;
						return mag_val;
					}
				}
			}
		}

		ssp = ssp->next;
	}


	return -1;
}

static Int4 modify_offset (SeqLocPtr m_loc, SeqLocPtr s_loc, Int4 m_offset, Int4Ptr left_over)
{
	Int4 m_len, s_len;

	*left_over = 0;
	if(m_offset == 0)
		return 0;
	else
	{
		m_len = SeqLocLen(m_loc);
		s_len = SeqLocLen(s_loc);
		if(m_len == s_len)
			return m_offset;
		else
		{
			if(m_len/s_len == 3)
			{
				*left_over = m_offset%3;
				if(*left_over > 0)
					*left_over = 3 - (*left_over);
			}
			if(*left_over > 0)
				return ((m_offset * s_len) /m_len + 1);
			else
				return ((m_offset * s_len) /m_len);
		}
	}
}

static Uint1 get_DenseSeg_strand(DenseSegPtr dsp, Int2 order)
{
	Int2 i, dim;

	if(dsp == NULL || dsp->strands == NULL)
		return 0;
	dim = dsp->dim;
	for(i = 0; i<dsp->numseg; ++i)
	{
		if(dsp->starts[dim * i + order] != -1)
			return (dsp->strands[dim*i + order]);
	}

	return 0;
}

NLM_EXTERN AlignDataPtr gather_align_data(SeqLocPtr m_slp, SeqAlignPtr align, 
                                          Int4 offset, Boolean ck_interval, 
                                          Boolean map)
{
    SeqIdPtr m_sip, sip;
    Uint1 m_strand, strand, c_strand;
    DenseSegPtr dsp;
    StdSegPtr ssp;
    DenseDiagPtr ddp;
    Int2 i, m_order, k, numseg, t_numseg;
    Int4 s1;
    Uint1 seg_type;
    Boolean is_found = FALSE;
    Int4 start, stop, c_start, c_stop;
    Int4 m_start, m_stop;
    Int4 master_pos;	/*position of the master sequence*/
    Int4 off_start, off_stop;
    Boolean rev;
    GatherRange gr, t_range;
    SeqLocPtr a_slp, loc;
    AlignDataPtr head = NULL, curr;
    Uint2 chain;
    Int4 h_start, h_stop;
    Boolean inc_left_mgap;	/*include the left gaps on the master sequence*/
    Boolean inc_right_mgap;	/*include the right gaps on the master sequence*/
    Boolean left_end_gap, right_end_gap;
    Int2 k_seg;
    Boolean collect;
    Boolean load;
    Boolean cont;	/*is it a continous segment ? */
    Int4 len;
    Int4 mag_val;	/*the magnification value */
    SeqLocPtr master_loc, m_loc;
    Boolean inverse;
    Int4 leftover;
    Int4 left, right;
    Boolean use_stop;
    Uint1 ma_strand;
    SeqAlignPtr sap;

    strand = 0;
    m_sip = SeqLocId(m_slp);
    if(!get_align_ends(align, m_sip, &start, &stop, &c_strand))
        return NULL;
    
    a_slp = SeqLocIntNew(start, stop, c_strand, m_sip);
    if(!SeqLocOffset(m_slp, a_slp, &gr, offset)) {
        SeqLocFree(a_slp);
        return NULL;
    }
    cont = FALSE;
    if(align->segtype == 2)
        cont = TRUE;
    else if(align->segtype == 3) {
        cont = (align->type == 3);
        /* cont = TRUE; */
        ssp = align->segs;
        mag_val = calculate_mag_val (ssp, m_sip, &inverse);
        if(mag_val == -1) {
            mag_val = 1;
            inverse = FALSE;
        }
    }
    
    m_strand = SeqLocStrand(m_slp);
    m_start = SeqLocStart(m_slp);
    m_stop = SeqLocStop(m_slp);
    c_start = -1;
    c_stop =-1;

    switch(align->segtype) {

    case 5: /* Discontinuous alignment */
        for(sap = (SeqAlignPtr) align->segs; sap != NULL; sap = sap->next) {
            curr =  gather_align_data(m_slp, sap, offset, ck_interval, map);
            LinkAlignData(&head, curr);
        }
        break;

    case 2: /*for DenseSegs*/
        dsp = (DenseSegPtr)(align->segs);
        m_order = get_master_order(dsp->ids, m_sip);
        ma_strand = get_DenseSeg_strand(dsp, m_order);
        rev = check_reverse_strand(m_strand, c_strand);
        if(rev)
            k = dsp->numseg -1;
        else
            k =0;
        k_seg = k;
        
        get_end_diag_val(dsp, m_order, k, &h_start, &h_stop, TRUE);
        if(!(h_stop < m_start || h_start > m_stop))	/*it is within the range*/
            inc_left_mgap = TRUE;
        else
            inc_left_mgap = FALSE;
        
        get_end_diag_val(dsp, m_order, k, &h_start, &h_stop, FALSE);
        if(!(h_stop < m_start || h_start > m_stop))	/*it is within the range*/
            inc_right_mgap = TRUE;
        else
            inc_right_mgap = FALSE;
        
        for(numseg = 0; numseg<dsp->numseg; ++numseg) {
            if(dsp->lens[k] >0) {
                s1 = (Int4)k*(Int4)(dsp->dim)+(Int4)m_order;
                master_pos = dsp->starts[s1];
                collect = FALSE;
                if(master_pos == -1) {	/*gap in the master sequence. It is an insertion*/
                    strand = ma_strand;
                    left_end_gap = is_end_gaps_for_master(dsp, m_order, k_seg, k, TRUE);
                    right_end_gap = is_end_gaps_for_master(dsp, m_order, k_seg, k, FALSE);
                    if(left_end_gap && inc_left_mgap && !map) {
                        collect = TRUE;
                        t_range.left = offset;
                        t_range.right = offset + dsp->lens[k] -1;
                        offset += dsp->lens[k];
                    }
                    if(right_end_gap && inc_right_mgap && !map) {
                        collect = TRUE;
                        t_range.left = t_range.right +1;
                        t_range.right = t_range.left + dsp->lens[k] -1;
                    }
                    if(!left_end_gap && !right_end_gap) {
                        use_stop = TRUE;
                        if((strand != Seq_strand_minus && rev) || (strand == Seq_strand_minus && rev == FALSE))
                            use_stop = FALSE;
                        if(use_stop)
                            update_seq_loc(c_stop, c_stop, 0, a_slp);
                        else
                            update_seq_loc(c_start, c_start, 0, a_slp);
                        collect = SeqLocOffset(m_slp, a_slp, &t_range, offset);
                        if(collect) {
                            ++(t_range.left);
                            if(!map) {
                                t_range.right = t_range.left+dsp->lens[k]-1;
                                offset += dsp->lens[k];
                            }
                        }
                    }
                    off_start = 0;
                    off_stop = 0;
                } else {/*master is not a gap*/
                    c_start = dsp->starts[s1];
                    c_stop = c_start + dsp->lens[k] -1;
                    update_seq_loc(c_start, c_stop, 0, a_slp);
                    collect = SeqLocOffset(m_slp, a_slp, &t_range, offset);
                    if(collect) {
                            off_start = MAX(0, (m_start - c_start));
                            off_stop = MAX(0, (c_stop - m_stop));
                    }
                }
                if(collect) {
                    for(sip = dsp->ids, i=0; sip!=NULL; sip = sip->next, ++i) {
                        load = TRUE;
                        start = dsp->starts[k*(dsp->dim) +i];
                        if(map) {
                            /*multiple pairwise, ignore the master and the gap in the master*/
                            if(i == m_order)
                                load = FALSE;
                            else if(master_pos == -1 && start == -1)
                                load= FALSE;
                        }
                        if(load)
                            {
                                strand = align_strand_get(dsp->strands, i);
                                if(start != -1) {
                                    stop = start + dsp->lens[k] -1;
                                    if(master_pos == -1 && map) { /*master sequence*/
                                        
                                        seg_type = INS_SEG;
                                        t_range.right = dsp->lens[k];
                                    } else {
                                        if(check_reverse_strand(c_strand, strand)) {
                                            start += off_stop;
                                            stop -= off_start;
                                        } else {
                                            start += off_start;
                                            stop -= off_stop;
                                        }
                                        seg_type = REG_SEG;
                                    }
                                } else {
                                    seg_type = GAP_SEG;
                                    start = -1;
                                    stop = dsp->lens[k];
                                } 
                                load_align_data(&head, start, stop, strand, sip, rev, seg_type, t_range, ck_interval, i, 1);
                            }
                    }
                }
            }
            if(rev)
                --k;
            else
                ++k;
        }
        break;
        
    case 3:
        ssp = (StdSegPtr)(align->segs);
        if(cont) {
            c_strand = get_master_strand_for_continous_ssp (ssp, m_sip);
            rev = check_reverse_strand(m_strand, c_strand);
            numseg = get_ssp_numseg (ssp);
            if(rev)
                k = numseg - 1;
            else
                k = 0;
            for(t_numseg = 0; t_numseg <numseg; ++t_numseg) {
                ssp = get_nth_ssp ((StdSegPtr)(align->segs), k);
                is_found = FALSE;
                for(loc= ssp->loc, i=0; loc!=NULL && !is_found; ++i, loc = loc->next) {
                    if(SeqIdMatch(SeqLocId(loc), m_sip)) {
                        master_loc = loc;
                        m_order = i;
                        if(loc->choice == SEQLOC_EMPTY)
                            master_pos = -1;
                        else {
                            master_pos = SeqLocStart(loc);
                            is_found = SeqLocOffset(m_slp, loc, &t_range, offset);
                        }
                        break;
                    }
                }
                len = -1;
                for(loc= ssp->loc, i = 0; loc!=NULL; ++i, loc = loc->next) {
                    if(i != m_order) {
                        if(loc->choice != SEQLOC_EMPTY)
                            len = SeqLocLen(loc);
                        break;
                    }
                }
				/*both segments are gaps */
                if(is_found) {
                    if(len == -1 && master_pos == -1)
                        is_found = FALSE;
                }
                if(loc != NULL && (is_found || master_pos == -1)) {
                    collect = FALSE;
                    if(master_pos == -1) {/*the master is a gap, it is an insertion*/
                        if(m_strand == Seq_strand_minus)
                            update_seq_loc(c_start, c_start, 0, a_slp);
                        else
                            update_seq_loc(c_stop, c_stop, 0, a_slp);
                        collect = SeqLocOffset(m_slp, a_slp, &t_range, offset);
                        if(collect) {
                            ++(t_range.left);
                            if(!map) {
                                if(!inverse) {
                                    t_range.right = t_range.left+len * mag_val -1;
                                    offset += len * mag_val;
                                } else {
                                    t_range.right = t_range.left+len / mag_val -1;
                                    offset += len / mag_val;
                                }
                            }
                        }
                        off_start = 0;
                        off_stop = 0;
                    } else {
                        c_start = SeqLocStart(master_loc);
                        c_stop = SeqLocStop(master_loc);
                        collect = TRUE;
                        off_start = MAX(0, (m_start - c_start));
                        off_stop = MAX(0, (c_stop - m_stop));
                    }
                    
                    if(collect) {
                        for(loc = ssp->loc, i= 0; loc != NULL; loc = loc->next, ++i) {
                            load = TRUE;
                            if(map && i == m_order)
                                load = FALSE;
                            if(load) {
                                left = t_range.left;
                                right = t_range.right;
                                if(loc->choice == SEQLOC_EMPTY) {/*it is a gap */
                                    strand = 0;
                                    start = -1;
                                    if(i == m_order)
                                        stop = inverse ? (len /mag_val) : (len * mag_val);
                                    else
                                        stop = inverse ? SeqLocLen(master_loc) * mag_val : SeqLocLen(master_loc)/mag_val;
                                    seg_type = GAP_SEG;
                                } else {
                                    start = SeqLocStart(loc);
                                    stop = SeqLocStop(loc);
                                    strand = SeqLocStrand(loc);
                                    if(master_pos == -1 && map) {
                                        seg_type = INS_SEG;
                                        t_range.right = SeqLocLen(loc);
                                    } else {
                                        if(check_reverse_strand(strand, c_strand)) {
                                            start += modify_offset(master_loc, loc, off_stop, &leftover);
                                            t_range.left += leftover;
                                            stop -= modify_offset(master_loc, loc, off_start, &leftover);
                                            t_range.right += leftover;
                                        } else {
                                            start += modify_offset(master_loc, loc, off_start, &leftover);
                                            t_range.left += leftover;
                                            stop -= modify_offset(master_loc, loc, off_stop, &leftover);
                                            t_range.right += leftover;
                                        }
                                        /* if(check_reverse_strand(c_strand, strand))
                                           {
                                           start += off_stop;
                                           stop -= off_start;
                                           }
                                           else
                                           {
                                           start += off_start;
                                           stop -= off_stop;
                                           } */
                                        seg_type = STD_SEG;
                                    }
                                }
                                load_align_data(&head, start, stop, strand, SeqLocId(loc), rev, seg_type, t_range, ck_interval, i, 1);
                                t_range.left = left;
                                t_range.right = right;
                                
                            }
                        }
                    }
                }
                if(rev)
                    --k;
                else
                    ++k;
            }
        } else {	/*end of if (count) */
            chain = 0;
            while(ssp) {
                ++chain;
                is_found = FALSE;
                curr = NULL;
                for(loc= ssp->loc, i=0; loc!=NULL && !is_found;) {
                    if(SeqLocOffset(m_slp, loc, &t_range, offset)) {
                        m_loc = loc;
                        is_found = TRUE;
                        break;
                    } else {
                        ++i;
                        loc = loc->next;
                    }
                }
                if(is_found) {
                    m_order = i;
                    off_start = MAX(0, (m_start - SeqLocStart(loc)));
                    off_stop = MAX(0, (SeqLocStop(loc) - m_stop));
                    c_strand = SeqLocStrand(loc);
                    if(map)
                        rev = check_reverse_strand(c_strand, m_strand);
                    else
                        rev = FALSE;
                    for(loc = ssp->loc,i=0; loc != NULL; loc = loc->next,++i) {
                        sip = SeqLocId(loc);
                        if(!map|| (m_order !=i)) {
                            start = SeqLocStart(loc);
                            stop = SeqLocStop(loc);
                            strand = SeqLocStrand(loc);
                            left = t_range.left;
                            right = t_range.right;
                            if(check_reverse_strand(strand, c_strand)) {
                                start += modify_offset(m_loc, loc, off_stop, &leftover);
                                t_range.left += leftover;
                                stop -= modify_offset(m_loc, loc, off_start, &leftover);
                                t_range.right += leftover;
                            } else {
                                start += modify_offset(m_loc, loc, off_start, &leftover);
                                t_range.left += leftover;
                                stop -= modify_offset(m_loc, loc, off_stop, &leftover);
                                t_range.right += leftover;
                            }
                            load_trunc_info(loc, &t_range);
                            load_align_data(&curr, start, stop, strand, sip, rev, STD_SEG, t_range, ck_interval, i, chain);
                            t_range.left = left;
                            t_range.right = right;
                        }
                    }
                }
                LinkAlignData(&head, curr);
                ssp = ssp->next;
            }
        }
        break;
        
    case 1:
        ddp = (DenseDiagPtr)(align->segs);
        chain = 0;
        while(ddp) {
            ++chain;
            curr = NULL;
            m_order = get_master_order(ddp->id, m_sip);
            if(m_order != -1) {
                c_strand = align_strand_get(ddp->strands, m_order);
                c_start = ddp->starts[m_order];
                c_stop = c_start + ddp->len -1;
                update_seq_loc(c_start, c_stop, 0, a_slp);
                if(SeqLocOffset(m_slp, a_slp, &t_range, offset)) {
                    rev = check_reverse_strand(m_strand, c_strand);
                    off_start = MAX(0, (m_start-c_start));
                    off_stop = MAX(0, (c_stop - m_stop));
                    for(sip = ddp->id, i=0; sip!=NULL; sip = sip->next, ++i) {
                        if(!map|| i != m_order) {
                            start = ddp->starts[i];
                            stop = start + ddp->len -1;
                            strand = align_strand_get(ddp->strands, i);
                            if(check_reverse_strand(strand, c_strand)) {
                                start += off_stop;
                                stop -= off_start;
                            } else {
                                start += off_start;
                                stop -= off_stop;
                            }
                            load_align_data(&curr, start, stop, strand, sip, rev, DIAG_SEG, t_range, ck_interval, i, chain);
                        }
                    }
                }
            }
            LinkAlignData(&head, curr);
            ddp = ddp->next;
        }
        break;
    default:
        break;
    }
    
    SeqLocFree(a_slp);
    return head;
}

					

static Boolean NEAR GatherSeqAlign(InternalGCCPtr gccp, SeqAlignPtr sap,
        Uint1 ttype, Pointer tparent, Pointer PNTR prevlink, Boolean in_scope, Boolean check, Uint1 obj_type)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp;
	Int2 LocateItem = 0;
	Pointer LocateData = NULL;
	Uint1 thistype;
        SeqLocPtr slp, target[2];
        Boolean takeit=TRUE, checkseq = FALSE;
	Int2 j, numcheck=0;
        Int4 offset = 0;
	Boolean check_interval;
	AlignDataPtr adp;
	SeqAlignPtr prevsap = NULL;

	if (sap == NULL) return TRUE;

	if(obj_type != OBJ_SEQALIGN && obj_type != OBJ_SEQHIST_ALIGN)
		return TRUE;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	if (gsp->ignore[obj_type])
		return TRUE; 

	if (gccp->locatetype == obj_type)
 	{
		LocateItem = gccp->locateID;
		LocateData = gccp->locatePtr;
	}

	thistype = obj_type;


        if (gsp->target != NULL && check)
        {
                numcheck = 1;
                target[0] = gsp->target;
                if (gccp->segloc != NULL)
                {
                        numcheck = 2;
                        target[1] = gccp->segloc;
                }
                offset = gsp->offset;
		checkseq = TRUE;
	}

	check_interval = (gsp->nointervals == FALSE);
	while (sap != NULL)
	{
		gccp->itemIDs[obj_type]++;
		if (LocateItem == gccp->itemIDs[obj_type])
			in_scope = TRUE;
		if (LocateData == (Pointer)sap)
			in_scope = TRUE;

		if (in_scope)
		{
			gcp->previtem = (Pointer)prevsap;
			gcp->prevtype = thistype;
			gcp->parentitem = tparent;
			gcp->parenttype = ttype;
			gcp->itemID = gccp->itemIDs[obj_type];
			gcp->prevlink = prevlink;
			gcp->thisitem = (Pointer)sap;
			gcp->thistype = thistype;
			GatherAddToStack(gcp);
			if (checkseq)
			{
				takeit = FALSE;
				for (j =0; ((j<numcheck) && (!takeit)); j++)
				{
					slp = target[j];
					FreeAlignData(gcp->adp);
					gcp->adp = NULL;
					adp = gather_align_data(slp, sap, offset, check_interval, gsp->mapinsert);
					if(adp == NULL)
						takeit = FALSE;
					else
					{
						takeit = TRUE;
						gcp->adp = adp;
					}
					
				}
				if(takeit)
				{
					if (! (*(gccp->userfunc))(gcp))
						return FALSE;
				}
			}
			else
			{
				if(takeit && check)
					if (! (*(gccp->userfunc))(gcp))
						return FALSE;
			}
			if (LocateItem) return FALSE;
			if (LocateData) return FALSE;
		}

		if (sap->segtype == SAS_DISC)
		{
			gcp->indent++;
			if (! GatherSeqAlign(gccp, (SeqAlignPtr)(sap->segs),
			       thistype, (Pointer)sap, &(sap->segs),
			       in_scope, check, OBJ_SEQALIGN))
			{
			   return FALSE;
			}
			gcp->indent--;
		}
		             

		prevsap = sap;
		prevlink = (Pointer PNTR)&(sap->next);
		sap = sap->next;
	}
	return TRUE;
}

static Boolean NEAR GatherSeqGraph(InternalGCCPtr gccp, SeqGraphPtr sgp,
        Uint1 ttype, Pointer tparent, Pointer PNTR prevlink, Boolean in_scope)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp;
	Int2 LocateItem = 0;
	Pointer LocateData = NULL;
	Uint1 thistype;

	if (sgp == NULL) return TRUE;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	if (gsp->ignore[OBJ_SEQGRAPH])
		return TRUE;

	LocateItem = gccp->locateID;
	LocateData = gccp->locatePtr;

	thistype = OBJ_SEQGRAPH;
	gcp->previtem = NULL;
	gcp->prevtype = thistype;
	gcp->parentitem = tparent;
	gcp->parenttype = ttype;

	while (sgp != NULL)
	{
		gccp->itemIDs[OBJ_SEQGRAPH]++;
		if (LocateItem == gccp->itemIDs[OBJ_SEQGRAPH])
			in_scope = TRUE;
		if (LocateData == (Pointer)sgp)
			in_scope = TRUE;

		if (in_scope)
		{
			gcp->itemID = gccp->itemIDs[OBJ_SEQGRAPH];
			gcp->thisitem = (Pointer)sgp;
			gcp->thistype = thistype;
			GatherAddToStack(gcp);
			gcp->prevlink = prevlink;
			if (! (*(gccp->userfunc))(gcp))
				return FALSE;
			if (LocateItem) return FALSE;
			if (LocateData != NULL) return FALSE;
		}

		gcp->previtem = (Pointer)sgp;
		prevlink = (Pointer PNTR)&(sgp->next);
		sgp = sgp->next;
	}
	return TRUE;
}

static Boolean NEAR GatherSeqAnnot(InternalGCCPtr gccp, SeqAnnotPtr sap,
        Uint1 ttype, Pointer tparent, Pointer PNTR prevlink, Boolean in_scope)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp;
	SeqAnnotPtr prevsap = NULL;
	Int2 LocateItem = 0;
	Pointer LocateData = NULL;
	Uint1 thistype;

	if (sap == NULL) return TRUE;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	if (gsp->ignore[OBJ_SEQANNOT])
		return TRUE;

	if ((! gsp->currlevel) && (gsp->ignore_top))
		return TRUE;

	if (gccp->locatetype == OBJ_SEQANNOT)
 	{
		LocateItem = gccp->locateID;
		LocateData = gccp->locatePtr;
	}
	else
		LocateItem = 0;

	while (sap != NULL)
	{
		thistype = OBJ_SEQANNOT;
		gccp->itemIDs[OBJ_SEQANNOT]++;
		if (LocateItem == gccp->itemIDs[OBJ_SEQANNOT])
			in_scope = TRUE;
 		if (LocateData == (Pointer)sap)
			in_scope = TRUE;

		gcp->thisitem = (Pointer)sap;
		gcp->thistype = thistype;
		gcp->itemID = gccp->itemIDs[OBJ_SEQANNOT];
 		GatherAddToStack(gcp);

		if (in_scope)
		{
			gcp->previtem = (Pointer) prevsap;
			gcp->prevtype = thistype;
			gcp->parentitem = tparent;
			gcp->parenttype = ttype;
			gcp->prevlink = prevlink;
			if (! (*(gccp->userfunc))(gcp))
				return FALSE;
			if (LocateItem) return FALSE;
			if (LocateData != NULL) return FALSE;
		}

		gcp->indent++;
		switch (sap->type)
		{
		
			case 1:     /* feature table */
				if (gccp->useSeqMgrIndexes) {
					/* now sending targeted features all at once regardless of packaging - so do nothing here */
				} else {
					if (! GatherSeqFeat(gccp, (SeqFeatPtr)(sap->data), thistype, (Pointer)sap, &(sap->data), in_scope, OBJ_SEQFEAT))
						return FALSE;
				}
				break;
			case 2:     /* alignments */
				if (! GatherSeqAlign(gccp, (SeqAlignPtr)(sap->data), thistype, (Pointer)sap, &(sap->data), in_scope, TRUE, OBJ_SEQALIGN))
					return FALSE;
				break;
			case 3:     /* graphs */
				if (! GatherSeqGraph(gccp, (SeqGraphPtr)(sap->data), thistype, (Pointer)sap, &(sap->data), in_scope))
					return FALSE;
				break;

		}
		gcp->indent--;

		prevsap = sap;
		prevlink = (Pointer PNTR)&(sap->next);
		sap = sap->next;
	}
	return TRUE;
}



static Boolean NEAR GatherSeqHist(InternalGCCPtr gccp, SeqHistPtr hist,
	Uint1 ttype, Pointer tparent, Pointer PNTR prevlink, Boolean in_scope, Boolean check_seq)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp;
	Int2 LocateItem = 0;
	Pointer LocateData = NULL;
	Uint1 thistype;

	if(hist == NULL) return TRUE;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	if(gsp->ignore[OBJ_SEQHIST])
		return TRUE;

	if (gccp->locatetype == OBJ_SEQHIST)
 	{
		LocateItem = gccp->locateID;
		LocateData = gccp->locatePtr;
	}
	else
		LocateItem = 0;

	gccp->itemIDs[OBJ_SEQHIST]++;
	thistype = OBJ_SEQHIST;
	if (LocateItem == gccp->itemIDs[OBJ_SEQHIST])
		in_scope = TRUE;
	if (LocateData == (Pointer)(hist))
		in_scope = TRUE;

	gcp->thistype = thistype;
	gcp->thisitem = (Pointer)(hist);
	gcp->itemID = gccp->itemIDs[OBJ_SEQHIST];
	GatherAddToStack(gcp);

	if (in_scope)
	{
		gcp->previtem = NULL;
		gcp->prevtype = 0;
		gcp->parentitem = (Pointer)tparent;
		gcp->parenttype = ttype;
		gcp->prevlink = prevlink;

		if (! (*(gccp->userfunc))(gcp))
			return FALSE;
		if (LocateItem) return FALSE;
		if (LocateData != NULL) return FALSE;
	}
	if((hist->assembly!=NULL) && (!gsp->ignore[OBJ_SEQHIST_ALIGN]))
		GatherSeqAlign(gccp,(SeqAlignPtr)(hist->assembly), thistype, 
	          (Pointer)(hist),(Pointer PNTR)&(hist->assembly),
		  in_scope, check_seq, OBJ_SEQHIST_ALIGN);
	return TRUE;

}





static Boolean NEAR GatherBioseqFunc (InternalGCCPtr gccp, BioseqPtr bsp,
         Pointer parent, Uint2 parenttype, SeqEntryPtr prev,
	     Pointer PNTR prevlink, SeqEntryPtr curr, Boolean in_scope)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp;
	Boolean takeit, in_range=TRUE, rev, free_seg, trunc_l, trunc_r;
	Int2 LocateItem = 0, segctr, first_seg, last_seg;
	Pointer LocateData = NULL;
	ValNode vn;
	SeqLocPtr head, slp, target=NULL, tslp, segloc;
	SeqLocPtr targets[2];
	Int4 offset, toffset, seglen, tlen;
	GatherRangePtr rdp;
	Uint1 thistype, segtype;
	Int2 j, numcheck;
	Boolean match_target = TRUE, do_seg, is_delta;
	DeltaSeqPtr dsp;
	Pointer dataptr;  /* used for OBJ_BIOSEQ_SEG and OBJ_BIOSEQ_DELTA */

	if (bsp == NULL)
		return TRUE;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	takeit = in_scope;
	head = NULL;      
	if (gsp->ignore[OBJ_BIOSEQ])
		takeit = FALSE;
	else if ((takeit) && (gsp->target != NULL))
	{
		if (bsp != gccp->bsp)
			takeit = FALSE;
	}

	gccp->itemIDs[OBJ_BIOSEQ]++;
	gcp->itemID = gccp->itemIDs[OBJ_BIOSEQ];
	if (gccp->locatetype == OBJ_BIOSEQ)
	{
		LocateItem = gccp->locateID;
		LocateData = gccp->locatePtr;
		if (LocateItem == gccp->itemIDs[OBJ_BIOSEQ])
			takeit = TRUE;
		if (LocateData == (Pointer)bsp)
			takeit = TRUE;
	}

	thistype = OBJ_BIOSEQ;
	gcp->thistype = thistype;
	gcp->thisitem = (Pointer)bsp;
	GatherAddToStack(gcp);

        if (gsp->target != NULL)
        {
		match_target = FALSE;
		vn.choice = SEQLOC_WHOLE;
		vn.data.ptrvalue = SeqIdFindBest (bsp->id, 0);
                numcheck = 1;
                targets[0] = gsp->target;
                if (gccp->segloc != NULL)
                {
                       	numcheck = 2;
                       	targets[1] = gccp->segloc;
                }
		for (j =0; !match_target && j<numcheck; j++)
		{
			if(SeqLocOffset(targets[j], &vn, &(gcp->extremes), gsp->offset))
				match_target = TRUE;
		}
	}

	if (takeit)
	{
		gcp->sep = curr;
		gcp->previtem = prev;
		gcp->prevtype = OBJ_SEQENTRY;
		gcp->parentitem = parent;
		gcp->parenttype = parenttype;
		gcp->thistype = thistype;
		gcp->thisitem = (Pointer)bsp;
		gcp->prevlink = prevlink;

        	/*if (gsp->target != NULL)
        	{
			takeit = FALSE;
			vn.choice = SEQLOC_WHOLE;
			vn.data.ptrvalue = bsp->id;
                	numcheck = 1;
                	targets[0] = gsp->target;
                	if (gccp->segloc != NULL)
                	{
                        	numcheck = 2;
                        	targets[1] = gccp->segloc;
                	}
			for (j =0; !takeit && j<numcheck; j++)
			{
				if(SeqLocOffset(targets[j], &vn, &(gcp->extremes), gsp->offset))
					takeit = TRUE;
			}
		}*/
		takeit = match_target;

		if(!takeit)
			return FALSE;
		if (! (*(gccp->userfunc))(gcp))
			return FALSE;
		if (LocateItem) return FALSE;
		if (LocateData != NULL) return FALSE;
	}


	gcp->indent++;

	if ((bsp->repr == Seq_repr_map) && (! gsp->ignore[OBJ_BIOSEQ_MAPFEAT]))
	{
		if (! GatherSeqFeat(gccp, (SeqFeatPtr)(bsp->seq_ext), thistype, (Pointer)bsp, &(bsp->seq_ext), in_scope, OBJ_BIOSEQ_MAPFEAT))
			return FALSE;
	}

    do_seg = FALSE;   /* assume no pointer processing */

	if (! gsp->ignore[OBJ_BIOSEQ_SEG])
	{
		if ((bsp->repr == Seq_repr_seg) ||
			(bsp->repr == Seq_repr_ref))
		{
			do_seg = TRUE;
			is_delta = FALSE;
			segtype = OBJ_BIOSEQ_SEG;
		}
	}

	if (! gsp->ignore[OBJ_BIOSEQ_DELTA])
	{
		if (bsp->repr == Seq_repr_delta)
		{
			do_seg = TRUE;
			is_delta = TRUE;
			segtype = OBJ_BIOSEQ_DELTA;
		}
	}

	if (do_seg)   /* process segment, ref, delta sequence .ext */
	{
		if (bsp->repr == Seq_repr_seg)
		{
			vn.next = NULL;
			vn.choice = SEQLOC_MIX;
			vn.data.ptrvalue = bsp->seq_ext;
			head = &vn;
		}
		else if (bsp->repr == Seq_repr_ref)
			head = (SeqLocPtr)(bsp->seq_ext);
		else
		{
			dsp = (DeltaSeqPtr)(bsp->seq_ext);  /* real data is here */
			head = DeltaSeqsToSeqLocs(dsp);  /* this for mapping only */
		}

		if (head != NULL)
		{
			segloc = NULL;
			segctr = 0;
			rev = gccp->rev;
			free_seg = FALSE;
			rdp = &(gcp->extremes);

			if (gsp->target != NULL)   /* may have to map */
			{
				if (gccp->segloc != NULL)
				{
					segloc = gccp->segloc;
					first_seg = gccp->first_seg;
					last_seg = gccp->last_seg;
				}
				else
				{
					segloc = SeqLocCopyPart(head, SeqLocStart(gsp->target),
					SeqLocStop(gsp->target), SeqLocStrand(gsp->target),
					TRUE, &(first_seg), &(last_seg));
				    free_seg = TRUE;
				}

				toffset = SeqLocStart(gsp->target); /* partial first seg */
				if (toffset)
					trunc_l = TRUE;
				else
					trunc_l = FALSE;
				if ((toffset + SeqLocLen(gsp->target)) < BioseqGetLen(bsp))
					trunc_r = TRUE;
				else
					trunc_r = FALSE;

				tlen = SeqLocLen(segloc);

				if (rev)
				{
					segctr = first_seg;
					last_seg = first_seg;
					first_seg = segctr;
					segctr = 0;
				}

			}

			if (gccp->locatetype == segtype)
 			{
				LocateItem = gccp->locateID;
				LocateData = gccp->locatePtr;
			}

			gcp->previtem = NULL;
			gcp->prevtype = 0;
			gcp->parentitem = (Pointer)bsp;
			gcp->parenttype = thistype;
			gcp->thistype = segtype;
			gcp->prevlink = (Pointer PNTR)&(bsp->seq_ext);
			offset = gsp->offset;

			slp = NULL;
			tslp = NULL;
			rdp->l_trunc = FALSE;
			rdp->r_trunc = FALSE;
			while ((slp = SeqLocFindNext(head, slp)) != NULL)
			{
				if ((is_delta) && (segctr))  /* not first one */
				{
					dsp = dsp->next;         /* move up dsp */
					if (dsp == NULL)
						ErrPostEx(SEV_FATAL,0,0,"GatherDeltaSeq: dsp is NULL");
				}

				seglen = SeqLocLen (slp);
				segctr++;
				if (is_delta)
					dataptr = (Pointer)dsp;
				else
					dataptr = (Pointer)slp;

				gccp->itemIDs[segtype]++;
				if (gccp->locatetype == segtype)
				{
					if (LocateItem == gccp->itemIDs[segtype])
						takeit = TRUE;
					if (LocateData == dataptr)
						takeit = TRUE;
				}

				if (takeit)
				{
					if (segloc != NULL)	   /* adjust to target? */
					{
						if ((first_seg > segctr) || (last_seg < segctr))
							in_range = FALSE;
						else
						{
							in_range = TRUE;
							tslp = SeqLocFindNext(segloc, tslp);

							rdp->l_trunc = FALSE;
							rdp->r_trunc = FALSE;

							if (segctr == first_seg)
							{
								offset = gsp->offset; /* allow for partial */
								if (rev)
								{
								   if (trunc_r)
									rdp->l_trunc = TRUE;
								}
								else
								{
									if (trunc_l)
										rdp->l_trunc = TRUE;
								}
							}
							else if (segctr == last_seg)
							{
								if (rev)
								{
								   if (trunc_l)
									rdp->r_trunc = TRUE;
								}
								else
								{
									if (trunc_r)
										rdp->r_trunc = TRUE;
								}
							}

							seglen = SeqLocLen(tslp);

							if (rev)
							{
								rdp->right = offset + tlen - 1;
								rdp->left = rdp->right - seglen + 1;
							}
							else
							{
								rdp->left = offset;
								rdp->right = offset + seglen - 1;
							}
							rdp->strand = SeqLocStrand(tslp);
							tlen -= seglen;
						}
					}
					else
					{
						rdp->left = offset;
						rdp->right = offset + seglen - 1;
						rdp->strand = SeqLocStrand(slp);
					}

					if (in_range)  /* always in_range if no target */
					{
						gcp->thisitem = dataptr;
						gcp->itemID = gccp->itemIDs[segtype];
						GatherAddToStack(gcp);

		
						if ((! (*(gccp->userfunc))(gcp)) || (LocateItem) ||
							(LocateData != NULL))
						{
							if (free_seg)
								SeqLocFree(segloc);
							if (is_delta)
								SeqLocFree(head);
							return FALSE;
						}
					}
				}
				gcp->prevlink = (Pointer PNTR)&(((ValNodePtr)(dataptr))->next);
				gcp->previtem = dataptr;
				gcp->prevtype = segtype;
				offset += seglen;
			}

			if (free_seg)
				SeqLocFree(segloc);
			if (is_delta)
				SeqLocFree(head);
		}
	}

	if(!GatherSeqHist(gccp, bsp->hist, thistype, (Pointer)bsp, (Pointer PNTR)&(bsp->hist), in_scope, match_target))
			return FALSE;

	if (! GatherSeqDescr(gccp, bsp->descr, thistype, (Pointer)bsp,
		                   (Pointer PNTR)&(bsp->descr), in_scope))
		return FALSE;

	if (! GatherSeqAnnot(gccp, bsp->annot, thistype, (Pointer)bsp,
		                   (Pointer PNTR)&(bsp->annot), in_scope))
		return FALSE;

	/* now send targeted features all at once regardless of packaging */
	if (gccp->useSeqMgrIndexes && bsp == gccp->bsp) {
		if (! ExploreSeqFeat (gccp, bsp, in_scope)) {
			return FALSE;
		}
	}

	gcp->indent--;

	return TRUE;
}

static Boolean NEAR GatherBioseqSetFunc (InternalGCCPtr gccp, BioseqSetPtr bsp,
           Pointer parent, Uint2 parenttype, SeqEntryPtr prev, Boolean in_scope,
		   Pointer PNTR prevlink, SeqEntryPtr curr)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp;
	Boolean takeit=TRUE, tscope, checkscope;
	SeqEntryPtr sep, prevsep = NULL, scope = NULL;
	Int2 LocateItem = 0;
	Pointer LocateData = NULL;
	Uint1 thistype;

	if (bsp == NULL)
		return TRUE;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	if (gsp->ignore[OBJ_BIOSEQSET])
		takeit = FALSE;
	else if (! in_scope)
		takeit = FALSE;

	scope = gsp->scope;
	if ((scope != NULL) && (! in_scope))
		checkscope = TRUE;
	else
		checkscope = FALSE;
		
	gccp->itemIDs[OBJ_BIOSEQSET]++;
	gcp->itemID = gccp->itemIDs[OBJ_BIOSEQSET];

	if (gccp->locatetype == OBJ_BIOSEQSET)
	{
		if ((gccp->locateID == gccp->itemIDs[OBJ_BIOSEQSET]) ||
			((Pointer)bsp == gccp->locatePtr))
		{
			takeit = TRUE;
			LocateItem = gccp->locateID;
			LocateData = gccp->locatePtr;
		}
	}

	thistype = OBJ_BIOSEQSET;
	gcp->thistype = thistype;
	gcp->thisitem = (Pointer)bsp;
	GatherAddToStack(gcp);

	if (takeit)
	{
		gcp->sep = curr;
		gcp->previtem = prev;
		gcp->prevtype = OBJ_SEQENTRY;
		gcp->parentitem = parent;
		gcp->parenttype = parenttype;
		gcp->prevlink = prevlink;


		if (! (*(gccp->userfunc))(gcp))
			return FALSE;
		if (LocateItem) return FALSE;
		if (LocateData != NULL) return FALSE;
	}
	gcp->indent++;
	if (! GatherSeqDescr(gccp, bsp->descr, thistype, (Pointer)bsp,
		               (Pointer PNTR)&(bsp->descr), in_scope))
		return FALSE;

	if (! GatherSeqAnnot(gccp, bsp->annot, thistype, (Pointer)bsp,
	               (Pointer PNTR)&(bsp->annot), in_scope))
		return FALSE;

	tscope = in_scope;
	prevlink = (Pointer PNTR)&(bsp->seq_set);
	for (sep = bsp->seq_set; sep != NULL; sep = sep->next)
	{
		gcp->previtem = prevsep;
		gcp->prevtype = OBJ_SEQENTRY;
		gcp->parentitem = (Pointer)bsp;
		gcp->parenttype = thistype;
		gcp->prevlink = prevlink;

		if (checkscope)
		{
			if (sep == scope)
				tscope = TRUE;
			else
				tscope = FALSE;
		}

		if (! GatherSeqEntryFunc(sep, gccp, (Pointer)bsp, OBJ_BIOSEQSET, prevsep, tscope, prevlink))
			return FALSE;

		if (checkscope)
		{
			if (tscope == TRUE)  /* just found it */
			{
				checkscope = FALSE;   /* don't look anymore */
				tscope = FALSE;       /* the siblings not in scope */
				gsp->scope = NULL;    /* no more to look */
			}
			else if (gsp->scope == NULL)   /* found lower down */
			{
				checkscope = FALSE;
				tscope = FALSE;
			}
		}

		prevsep = sep;
		prevlink = (Pointer PNTR)&(sep->next);
	}

	gcp->indent--;  /* reset to original indent level */
	return TRUE;
}

static Boolean NEAR GatherSeqEntryFunc (SeqEntryPtr sep, InternalGCCPtr igccp,
           Pointer parent, Uint2 parenttype, SeqEntryPtr prev, Boolean in_scope,
		   Pointer PNTR prevlink)
{
	if (sep == NULL)
		return TRUE;

	if (IS_Bioseq(sep))
	{
		if (! GatherBioseqFunc(igccp, (BioseqPtr)(sep->data.ptrvalue), parent, parenttype, prev, prevlink, sep, in_scope))
			return FALSE;
	}
	else
	{
		if (! GatherBioseqSetFunc(igccp, (BioseqSetPtr)(sep->data.ptrvalue), parent, parenttype, prev, in_scope, prevlink, sep))
			return FALSE;
	}

	return TRUE;
}

static Boolean NEAR GatherSeqSubCit(InternalGCCPtr gccp, CitSubPtr csp,
        Uint1 ttype, Pointer tparent, Pointer PNTR prevlink)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp;
	Boolean doit = TRUE;
	Int2 LocateItem = 0;
	Pointer LocateData = NULL;

	if (csp == NULL) return TRUE;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	if (gsp->ignore[OBJ_SEQSUB_CIT])
		return TRUE;

	gccp->itemIDs[OBJ_SEQSUB_CIT]++;

	if (gccp->locatetype == OBJ_SEQSUB_CIT)
	{
		LocateItem = gccp->locateID;
		LocateData = gccp->locatePtr;
		if ((gccp->itemIDs[OBJ_SEQSUB_CIT] != LocateItem) &&
			(LocateData != (Pointer)csp))
			doit = FALSE;
	}

	gcp->previtem = NULL;
	gcp->prevtype = 0;
	gcp->parentitem = tparent;
	gcp->parenttype = ttype;
	gcp->thisitem = (Pointer)csp;
	gcp->thistype = OBJ_SEQSUB_CIT;
	gcp->prevlink = prevlink;
	gcp->itemID = gccp->itemIDs[OBJ_SEQSUB_CIT];
	GatherAddToStack(gcp);


	if (doit)
	{
		if (! (*(gccp->userfunc))(gcp))
			return FALSE;
		if (LocateItem) return FALSE;
		if (LocateData) return FALSE;
	}

	return TRUE;
}

static Boolean NEAR GatherSeqSubContact(InternalGCCPtr gccp, ContactInfoPtr cip,
        Uint1 ttype, Pointer tparent, Pointer PNTR prevlink)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp;
	Int2 LocateItem = 0;
	Pointer LocateData = NULL;
	Boolean doit = TRUE;

	if (cip == NULL) return TRUE;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	if (gsp->ignore[OBJ_SEQSUB_CONTACT])
		return TRUE;

	gccp->itemIDs[OBJ_SEQSUB_CONTACT]++;

	if (gccp->locatetype == OBJ_SEQSUB_CONTACT)
	{
		LocateItem = gccp->locateID;
		LocateData = gccp->locatePtr;
		if ((gccp->itemIDs[OBJ_SEQSUB_CONTACT] != LocateItem) &&
			((Pointer)cip != LocateData))
			doit = FALSE;
	}

	gcp->previtem = NULL;
	gcp->prevtype = 0;
	gcp->parentitem = tparent;
	gcp->parenttype = ttype;
	gcp->thisitem = (Pointer)cip;
	gcp->thistype = OBJ_SEQSUB_CONTACT;
	gcp->prevlink = prevlink;
	gcp->itemID = gccp->itemIDs[OBJ_SEQSUB_CONTACT];
	GatherAddToStack(gcp);

	if (doit)
	{
		if (! (*(gccp->userfunc))(gcp))
			return FALSE;
		if (LocateItem) return FALSE;
		if (LocateData != NULL) return FALSE;
	}

	return TRUE;
}

static Boolean NEAR GatherSubBlock(InternalGCCPtr gccp, SubmitBlockPtr sbp,
        Uint1 ttype, Pointer tparent, Pointer PNTR prevlink)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp;
	Int2 LocateItem = 0;
	Pointer LocateData = NULL;
	Boolean doit = TRUE;

	if (sbp == NULL) return TRUE;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	if (gsp->ignore[OBJ_SUBMIT_BLOCK])
		return TRUE;

	gccp->itemIDs[OBJ_SUBMIT_BLOCK]++;

	if (gccp->locatetype != 0) {
		doit = FALSE;
		if (gccp->locatetype == OBJ_SUBMIT_BLOCK)
		{
			LocateItem = gccp->locateID;
			LocateData = gccp->locatePtr;
			if (gccp->itemIDs[OBJ_SUBMIT_BLOCK] == LocateItem)
				doit = TRUE;
			if (LocateData == (Pointer)sbp)
				doit = TRUE;
		}
	}

	gcp->previtem = NULL;
	gcp->prevtype = 0;
	gcp->parentitem = tparent;
	gcp->parenttype = ttype;
	gcp->thisitem = (Pointer)sbp;
	gcp->thistype = OBJ_SUBMIT_BLOCK;
	gcp->prevlink = prevlink;
	gcp->itemID = gccp->itemIDs[OBJ_SUBMIT_BLOCK];
 	GatherAddToStack(gcp);

	if (doit)
	{
		if (! (*(gccp->userfunc))(gcp))
			return FALSE;
		if (LocateItem) return FALSE;
		if (LocateData != NULL) return FALSE;
	}

	gcp->indent++;

	if (! GatherSeqSubContact(gccp, sbp->contact, OBJ_SUBMIT_BLOCK,
										(Pointer)sbp, (Pointer PNTR)&(sbp->contact)))
		return FALSE;

	if (! GatherSeqSubCit(gccp, sbp->cit, OBJ_SUBMIT_BLOCK,
										(Pointer)sbp, (Pointer PNTR)&(sbp->cit)))
		return FALSE;

    gcp->indent--;
	return TRUE;
}


static Boolean NEAR GatherSeqSubmit (InternalGCCPtr gccp, SeqSubmitPtr ssp, Boolean in_scope)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp;
	Boolean takeit=TRUE, tscope, checkscope;
	SeqEntryPtr sep, prevsep = NULL, scope = NULL;
	Int2 LocateItem = 0;
	Pointer LocateData = NULL;
	Uint1 thistype;
	Pointer PNTR prevlink;

	if (ssp == NULL)
		return TRUE;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	if (gsp->ignore[OBJ_SEQSUB])
		takeit = FALSE;
	else if (! in_scope)
		takeit = FALSE;

	scope = gsp->scope;
	if ((scope != NULL) && (! in_scope))
		checkscope = TRUE;
	else
		checkscope = FALSE;
		
	gccp->itemIDs[OBJ_SEQSUB]++;
	gcp->itemID = gccp->itemIDs[OBJ_SEQSUB];

	if (gccp->locatetype == OBJ_SEQSUB)
	{
		if ((gccp->locateID == gccp->itemIDs[OBJ_SEQSUB]) ||
			(gccp->locatePtr == (Pointer)ssp))
		{
			takeit = TRUE;
			LocateItem = gccp->locateID;
			LocateData = gccp->locatePtr;
		}
	}

	thistype = OBJ_SEQSUB;
	gcp->thistype = thistype;
	gcp->thisitem = (Pointer)ssp;
	GatherAddToStack(gcp);

	if (takeit)
	{
		gcp->sep = NULL;
		gcp->previtem = NULL;
		gcp->prevtype = 0;
		gcp->parentitem = NULL;
		gcp->parenttype = 0;
		gcp->thisitem = (Pointer)ssp;
		gcp->thistype = thistype;
		gcp->prevlink = NULL;


		if (! (*(gccp->userfunc))(gcp))
			return FALSE;
		if (LocateItem) return FALSE;
		if (LocateData != NULL) return FALSE;
	}
    
    gcp->indent++;
	if (! GatherSubBlock(gccp, ssp->sub, thistype, (Pointer)ssp,
		               (Pointer PNTR)&(ssp->sub)))
		return FALSE;
    
	tscope = in_scope;
	prevlink = (Pointer PNTR)&(ssp->data);

	switch(ssp->datatype)
	{
		case 1:    /* Seq-entrys */
			prevsep = NULL;
			for (sep = (SeqEntryPtr)(ssp->data); sep != NULL; sep = sep->next)
			{
				gcp->previtem = prevsep;
				gcp->prevtype = OBJ_SEQENTRY;
				gcp->parentitem = (Pointer)ssp;
				gcp->parenttype = thistype;
				gcp->prevlink = prevlink;

				if (checkscope)
				{
					if (sep == scope)
						tscope = TRUE;
					else
						tscope = FALSE;
				}

				if (! GatherSeqEntryFunc(sep, gccp, (Pointer)ssp, OBJ_SEQSUB, prevsep, tscope, prevlink))
					return FALSE;

				if (checkscope)
				{
					if (tscope == TRUE)  /* just found it */
					{
						checkscope = FALSE;   /* don't look anymore */
						tscope = FALSE;       /* the siblings not in scope */
						gsp->scope = NULL;    /* no more to look */
					}
					else if (gsp->scope == NULL)   /* found lower down */
					{
						checkscope = FALSE;
						tscope = FALSE;
					}
				}

				prevsep = sep;
				prevlink = (Pointer PNTR)&(sep->next);
			}
			break;
		case 2:    /* Seq-annots */
			if (! GatherSeqAnnot(gccp, (SeqAnnotPtr)(ssp->data), thistype,
						(Pointer)ssp,(Pointer PNTR)&(ssp->data), in_scope))
				return FALSE;

			break;
		case 3:    /* SeqIds */
			if (! GatherSeqIds(gccp, (SeqIdPtr)(ssp->data), thistype,
						(Pointer)ssp,(Pointer PNTR)&(ssp->data)))
				return FALSE;

			break;
		default:
			break;
	}
	gcp->indent--;  /* reset to original indent level */
	return TRUE;
}

/*****************************************************************************
*
*   GatherBioseqPartsFunc(gccp, top)
*      gets parts not contained in "top" for segmented entry
*
*****************************************************************************/
static Boolean NEAR GatherBioseqPartsFunc (InternalGCCPtr gccp, Pointer top)
{
	GatherContextPtr gcp;
	GatherScopePtr gsp, tgsp;
	GatherScope scopebuf;
	SeqLocPtr slp, head;
	SeqIdPtr sip;
	Boolean retval;
	BioseqPtr tbsp;
	SeqEntryPtr sep;
	Int4 len;
	Int2 ctr;
	Boolean doit;

	gcp = &(gccp->gc);
	gsp = &(gccp->scope);

	if (gsp->seglevels <= gsp->currlevel)
		return TRUE;


	head = gccp->segloc;

	tgsp = &scopebuf;
	MemCopy(tgsp, gsp, sizeof(GatherScope));
	tgsp->seglevels--;
	tgsp->scope = NULL;
	tgsp->currlevel++;
	tgsp->ignore [OBJ_BIOSEQ] = TRUE;

	slp = NULL;
	
	retval = FALSE;	/*??*/
	ctr = 0;
	while ((slp = SeqLocFindNext(head, slp)) != NULL)
	{
		doit = FALSE;
		tgsp->target = slp;
		sip = SeqLocId(slp);
		tbsp = BioseqLockById(sip);
		len = SeqLocLen(slp);

		if (len >= 0 && tbsp != NULL)
		{
			doit = TRUE;
			if ((gsp->stop_on_annot) && (ctr < gccp->segcnt))
			{
				if (gccp->found_annot[ctr])  /* already found annot here */
					doit = FALSE;
			}
		}

		if (doit)
		{
			if (! ObjMgrIsChild(top, (Pointer)tbsp)) /* in set we just did? */
			{
				sep = SeqEntryFind(sip);
				retval = GatherSeqEntry(sep, gcp->userdata, gccp->userfunc, tgsp);
			}
			BioseqUnlock(tbsp);
			if (! retval)
				return FALSE;
		}
		else if (tbsp != NULL)
			BioseqUnlock(tbsp);
		
		tgsp->offset += len;
		ctr++;
	}

	return TRUE;
}

static Boolean WholeLocOnBioseq (BioseqPtr bsp, SeqLocPtr slp)

{
  SeqIntPtr sintp;
  SeqIdPtr  sip;

  if (bsp == NULL || slp == NULL) return FALSE;

  sip = SeqLocId (slp);
  if (sip == NULL) return FALSE;
  if (! SeqIdIn (sip, bsp->id)) return FALSE;

  if (slp->choice == SEQLOC_WHOLE) return TRUE;
  if (slp->choice == SEQLOC_INT) {
    sintp = (SeqIntPtr) slp->data.ptrvalue;
    if (sintp != NULL &&
        sintp->from == 0 &&
        sintp->to == bsp->length - 1) return TRUE;
  }

  return FALSE;
}

static Boolean NEAR IGCCBuild (InternalGCCPtr ip, ObjMgrDataPtr omdp, Pointer userdata, GatherItemProc userfunc, GatherScopePtr scope)
{
	Boolean in_scope = TRUE;
	SeqIdPtr sip;
	BioseqPtr bsp = NULL;
	ValNode fake;
	SeqLocPtr slp;
	Int2 ctr;
	SeqEntryPtr oldsep;
	ObjMgrDataPtr newomdp = NULL;
	Boolean reload_from_cache = TRUE;   /* default behavior */
	DeltaSeqPtr dsp;
	SeqLocPtr loc = NULL;
	Uint2 entityID;

	if ((omdp == NULL) || (userfunc == NULL)) return FALSE;

	MemSet((Pointer)(ip), 0, sizeof(InternalGCC));


	if (scope != NULL)  /* check for turning off reload from cache */
	{
		if (scope->do_not_reload_from_cache)
			reload_from_cache = FALSE;
	}

	if ((omdp->tempload == TL_CACHED) && (reload_from_cache))  /* must reload from cache */
	{
		newomdp = BioseqReload(omdp, TRUE);
		if (newomdp == NULL)
		{
			ErrPostEx(SEV_ERROR,0,0,"IGCCBuild: Couldn't reload data from cache.");
			return FALSE;
		}
		ip->reloaded = TRUE;
		omdp = newomdp;

		if (scope != NULL)
		{
			if(scope->scope != NULL)
			{
				ErrPostEx(SEV_ERROR,0,0,"IGCCBuild: Scope invalid, data reloaded from cache.");
				ObjMgrLock(omdp->datatype, omdp->dataptr, FALSE);
				return FALSE;
			}
		}
	}
	else
		ObjMgrLock(omdp->datatype, omdp->dataptr, TRUE);  /* just lock it */

	ip->omdp = omdp;
	ip->gc.userdata = userdata;
	ip->userfunc = userfunc;
	if (scope != NULL)
		MemCopy(&(ip->scope), scope, sizeof(GatherScope));
	ip->gc.entityID = omdp->EntityID;
	ip->gc.tempload = omdp->tempload;
	ip->gc.seglevel = ip->scope.currlevel;
	ip->gc.igccp = (Pointer)ip;
	if (ObjMgrCheckHold())
		ip->gc.hold = TRUE;

	if (ip->scope.target != NULL)
	{
		sip = SeqLocId(ip->scope.target);

		/* first check if target in the SeqEntry -- necessary if multiple versions with same id */
		if ((omdp->choicetype == OBJ_SEQENTRY && omdp->choice != NULL) ||
		    (scope != NULL && scope->scope != NULL))
		{
			oldsep = SeqEntryGetScope();  /* save any current scope */
			if (omdp->choicetype == OBJ_SEQENTRY) {
				SeqEntrySetScope(omdp->choice);
			} else {
				SeqEntrySetScope(scope->scope);
			}
			bsp = BioseqFindCore(sip);
			if (bsp != NULL)    /* yes it is in here */
				bsp = BioseqLockById(sip);
			SeqEntrySetScope(oldsep);
		}

		if (bsp == NULL)			  /* out of scope? */
			bsp = BioseqLockById(sip);/* try again */

		ip->bsp = bsp;
		if (SeqLocStrand(ip->scope.target) == Seq_strand_minus)
			ip->rev = TRUE;
		if ((ip->scope.seglevels > ip->scope.currlevel)
			&& (bsp != NULL))     /* get seg parts? */
		{
			slp = NULL;
			loc = NULL;
			if (bsp->repr == Seq_repr_seg)
			{
				fake.choice = SEQLOC_MIX;
				fake.next = NULL;
				fake.data.ptrvalue = bsp->seq_ext;
				slp = &fake;
			} else if (bsp->repr == Seq_repr_delta && bsp->seq_ext_type == 4) {
				dsp = (DeltaSeqPtr) bsp->seq_ext;
				loc = DeltaSeqsToSeqLocs (dsp);
				slp = loc;
			}
			else if (bsp->repr == Seq_repr_ref)
				slp = (SeqLocPtr)(bsp->seq_ext);

			ip->segloc = SeqLocCopyPart(slp, SeqLocStart(ip->scope.target),
				SeqLocStop(ip->scope.target), SeqLocStrand(ip->scope.target),
				TRUE, &(ip->first_seg), &(ip->last_seg));

			if (ip->scope.stop_on_annot)
			{

				slp = NULL; ctr = 0;
				while ((slp = SeqLocFindNext(ip->segloc, slp)) != NULL)
					ctr++;
				if (ctr)
				{
					ip->segcnt = ctr;
					ip->seglens = MemNew((size_t)(sizeof(Int4) * ctr));
					ip->found_annot = MemNew((size_t)(sizeof(Boolean) * ctr));

					slp = NULL; ctr = 0;
					while ((slp = SeqLocFindNext(ip->segloc, slp)) != NULL)
					{
						ip->seglens[ctr] = SeqLocLen(slp);
						if (ip->seglens[ctr] < 0)
							ip->seglens[ctr] = 0;
						ctr++;
					}
				}
			}
			loc = SeqLocFree (loc);
		}

		/* if targeted gather, try to use feature indexing for speed */
		if (bsp != NULL && bsp->repr == Seq_repr_raw &&
			SeqMgrGetParentOfPart (bsp, NULL) == NULL &&
			ip->segloc == NULL && ip->scope.useSeqMgrIndexes &&
			(ip->scope.get_feats_location || ip->scope.get_feats_product) &&
			(! (ip->scope.ignore [OBJ_SEQFEAT]))) {

			/* target must be whole or full length interval on bioseq */
			if (! WholeLocOnBioseq (bsp, ip->scope.target)) return TRUE;

			entityID = ObjMgrGetEntityIDForPointer (bsp);

			/* index features if not already done */
			if (SeqMgrFeaturesAreIndexed (entityID) == 0) {
				SeqMgrIndexFeatures (entityID, NULL);
			}

			if (SeqMgrFeaturesAreIndexed (entityID) != 0) {
				ip->useSeqMgrIndexes = TRUE;
			}
		}
	}

	return TRUE;
}

NLM_EXTERN AlignDataPtr FreeAlignData(AlignDataPtr adp)
{
	AlignDataPtr next;
	AlignRangePtr arp, arp_next;
	
	while(adp)
	{
		arp = adp->arp;
		while(arp)
		{
			arp_next = arp->next;
			arp->next = NULL;
			MemFree(arp);
			arp = arp_next;
		}
		next = adp->next;
		adp->next = NULL;
		MemFree(adp);
		adp = next;
	}
	return NULL;
}
	
	
static Boolean IGCCclear(InternalGCCPtr ip)
{
	if (ip == NULL) return TRUE;

	BioseqUnlock(ip->bsp);
	ObjMgrLock(ip->omdp->datatype, ip->omdp->dataptr, FALSE);  /* unlock the entity */

	MemFree(ip->gc.rdp);
	FreeAlignData(ip->gc.adp);
	ip->gc.adp = NULL;
	SeqLocFree(ip->segloc);
	MemFree(ip->seglens);
	MemFree(ip->found_annot);
	MemFree(ip->gc.gatherstack);
	MemFree(ip->gc.extra_loc);

	return TRUE;
}

static void GatherEntityFunc (ObjMgrDataPtr omdp, InternalGCCPtr gccp, Boolean in_scope)
{
	ValNodePtr vnp;
	Pointer ptr;

	vnp = omdp->choice;
	ptr = omdp->dataptr;

	switch (omdp->choicetype)
	{
		case OBJ_SEQENTRY:
			GatherSeqEntryFunc(vnp, gccp, NULL, 0, NULL, in_scope, NULL);
			break;

		default:
			switch (omdp->datatype)
			{
				case OBJ_BIOSEQ:
					GatherBioseqFunc(gccp, (BioseqPtr)ptr, NULL, 0, NULL, NULL,
						NULL, in_scope);
					break;

				case OBJ_BIOSEQSET:
					GatherBioseqSetFunc(gccp, (BioseqSetPtr)ptr, NULL, 0, NULL,
						in_scope, NULL, NULL);
					break;

				case OBJ_SEQDESC:
					GatherSeqDescr(gccp, (ValNodePtr)ptr, 0, NULL, NULL,in_scope);
					break;

				case OBJ_SEQANNOT:
					GatherSeqAnnot(gccp, (SeqAnnotPtr)ptr, 0,NULL,NULL, in_scope);
					break;

				case OBJ_ANNOTDESC:              /* NOT SUPPORTED YET */
					break;

				case OBJ_SEQFEAT:
					GatherSeqFeat(gccp, (SeqFeatPtr)ptr, 0, NULL, NULL, in_scope, OBJ_SEQFEAT);
					break;

				case OBJ_SEQALIGN:
					GatherSeqAlign(gccp, (SeqAlignPtr)ptr, 0, NULL, NULL, in_scope, TRUE, OBJ_SEQALIGN);
					break;

				case OBJ_SEQHIST_ALIGN:
					GatherSeqAlign(gccp, (SeqAlignPtr)ptr, 0, NULL, NULL, in_scope, TRUE, OBJ_SEQHIST_ALIGN);
					break;

				case OBJ_SEQGRAPH:
					GatherSeqGraph(gccp, (SeqGraphPtr)ptr, 0, NULL, NULL, in_scope);
					break;

				case OBJ_SEQSUB:
					GatherSeqSubmit (gccp, (SeqSubmitPtr) ptr, in_scope);
					break;

				case OBJ_SUBMIT_BLOCK:
					GatherSubBlock(gccp, (SubmitBlockPtr)ptr,0,NULL,NULL);
					break;

				case OBJ_SEQSUB_CONTACT:
					GatherSeqSubContact(gccp, (ContactInfoPtr)ptr,0, NULL, NULL);
					break;

				case OBJ_BIOSEQ_MAPFEAT:        /* NOT SUPPORTED YET */
					break;

				case OBJ_BIOSEQ_SEG:			/* NOT SEPARATELY SUPPORTED */
					break;

				case OBJ_SEQHIST:    			/* NOT SEPARATELY SUPPORTED */
					GatherSeqHist(gccp, (SeqHistPtr)ptr, 0, NULL, NULL, in_scope, TRUE);
					break;

				case OBJ_PUB:
					GatherPub(gccp, (ValNodePtr)ptr, 0, 0, NULL,NULL, in_scope);
					break;

				case OBJ_SEQFEAT_CIT:			/* NOT SEPARATELY SUPPORTED */
					break;

				case OBJ_SEQSUB_CIT:
					GatherSeqSubCit(gccp, (CitSubPtr)ptr,0, NULL, NULL);
					break;

				case OBJ_PUB_SET:
					GatherPubSet(gccp, (ValNodePtr)ptr, 0, 0, NULL,NULL, in_scope);
					break;

				case OBJ_SEQID:
					GatherSeqIds(gccp, (SeqIdPtr)ptr,0,NULL,NULL);
					break;

				default:
					break;
			}
	}


}
/*****************************************************************************
*
*   FocusSeqEntry (sep, scope)
*      zeros out all fields in scope
*      sets scope.target, .scope, .propagate_desciptors appropriately for 
*         SeqEntry
*      if (Bioseq)
*         target is the bioseq
*         entityID is the containing set if any
*         scope.scope is null
*      if (BioseqSet)
*         target is NULL
*         entityID is the containing set if any
*         scope.scope is sep
*         propagate_descriptors is TRUE
*
*      return of FOCUS_INITIALIZED means scope is initialized
*      return of FOCUS_NOT_NEEDED means send NULL for GatherScope.. you
*        don't need to scope for this SeqEntryPtr
*      return of FOCUS_ERROR  means it could not be initialized
*
*****************************************************************************/
NLM_EXTERN Int2 LIBCALL FocusSeqEntry (SeqEntryPtr sep, GatherScopePtr scope)
{
	Int2 retval = FOCUS_ERROR;
	ObjMgrDataPtr omdp;
	ObjMgrPtr omp;
	SeqIdPtr sip;
	SeqLocPtr slp;
	BioseqPtr bsp;

	if ((sep == NULL) || (scope == NULL))
		return retval;

	MemSet((Pointer)scope, 0, sizeof(GatherScope));

	omp = ObjMgrReadLock();
	omdp = ObjMgrFindByData(omp, sep->data.ptrvalue);
	if (omdp == NULL) goto erret;

	if (omdp->parentptr == NULL)
	{
		retval = FOCUS_NOT_NEEDED;
		goto erret;
	}

	if (IS_Bioseq(sep))
	{
		slp = ValNodeNew(NULL);
		slp->choice = SEQLOC_WHOLE;
		bsp = (BioseqPtr) sep->data.ptrvalue;
		sip = SeqIdDup (SeqIdFindBest (bsp->id, 0));
		slp->data.ptrvalue = sip;
		scope->target = slp;
	}
	else
	{
		scope->scope = sep;
		omdp = ObjMgrFindTop(omp, omdp);
		if (omdp->tempload == TL_CACHED)
		{
			ErrPostEx(SEV_ERROR, 0,0, "FocusSeqEntry: Scope to BioseqSet on Cached record");
			goto erret;
		}
	}
	retval = FOCUS_INITIALIZED;
erret:
	ObjMgrUnlock();
	return retval;
}

/*****************************************************************************
*
*   GatherSeqEntry (sep, userdata, userproc, scope)
*
*****************************************************************************/
NLM_EXTERN Boolean LIBCALL GatherSeqEntry (SeqEntryPtr sep, Pointer userdata, GatherItemProc userfunc, GatherScopePtr scope)
{
	Uint2 entityID;

	if ((sep == NULL) || (userfunc == NULL)) return FALSE;

	entityID = ObjMgrGetEntityIDForChoice(sep);
	
	return GatherEntity (entityID, userdata, userfunc, scope);
}

/*****************************************************************************
*
*   GatherEntity (entityID, userdata, userproc, scope)
*
*****************************************************************************/
NLM_EXTERN Boolean LIBCALL GatherEntity (Uint2 entityID, Pointer userdata, GatherItemProc userfunc, GatherScopePtr scope)
{
	InternalGCC igcc;
	Boolean in_scope;
	ObjMgrDataPtr omdp;
	Boolean reloaded_from_cache = FALSE;
	ObjMgrPtr omp;

	if ((! entityID) || (userfunc == NULL)) return FALSE;

	omp = ObjMgrReadLock();
	omdp = ObjMgrGetDataStruct (omp, entityID);
	ObjMgrUnlock();

	if (omdp == NULL) return FALSE;

	if (! IGCCBuild(&igcc, omdp, userdata, userfunc, scope))
		return FALSE;

	omdp = igcc.omdp;   /* could have been reloaded */
	if (igcc.scope.scope != NULL)
	{
			in_scope = ObjMgrIsChild((igcc.scope.scope->data.ptrvalue), (omdp->dataptr));
	}
	else                   /* no scope set.. all in scope */
		in_scope = TRUE;

	GatherEntityFunc(omdp, &igcc, in_scope);

	if ((igcc.segloc != NULL) && (igcc.scope.scope == NULL)) /* get segs first */
		GatherBioseqPartsFunc(&igcc, omdp->dataptr);


	return IGCCclear(&igcc);
}
/**************************************************************************
*
*   callback used by GatherItemIDByData
*
***************************************************************************/
static Boolean GatherItemByDataProc (GatherContextPtr gcp)
{
	Uint2Ptr ptr;

	ptr = (Uint2Ptr)(gcp->userdata);
	*ptr = gcp->itemID;

	return TRUE;
}
 
/*****************************************************************************
*
*   GatherItemIDByData (entityID, itemtype, dataptr)
*      Looks in entityID for an element of itemtype that matches the pointer
*         dataptr.
*      if found, returns the itemID
*      else returns 0
*      itemtype is as defined in objmgr.h for OBJ_
*
*****************************************************************************/
NLM_EXTERN Uint2 LIBCALL GatherItemIDByData (Uint2 entityID, Uint2 itemtype, Pointer dataptr)
{
	Uint2 itemID = 0;

	GatherData(entityID, dataptr, itemtype, (Pointer)(&itemID), GatherItemByDataProc);
	return itemID;
}


/*****************************************************************************
*
*   GatherData (entityID, itemID, itemtype, userdata, userproc)
*      Get an item by entityID, itemtype, and a Pointer of itemtype
*      GatherContext.seglevel and GatherContext.propagated will not be
*        set on the callback.
*   
*      Sets in_scope to FALSE so that the callback is not called
*         Scope is NULL, so in_scope is never TRUE
*      Sets ignore TRUE for everything not needed to find item
*      Sets locatetype and locateID, which are checked in the traversal
*
*****************************************************************************/
NLM_EXTERN Boolean LIBCALL GatherData (Uint2 entityID, Pointer dataptr, Uint2 itemtype,
                                   Pointer userdata, GatherItemProc userfunc)
{
	return GatherItemFunc (entityID, 0, itemtype, userdata, userfunc, dataptr, FALSE);
}

/*****************************************************************************
*
*   GatherItem (entityID, itemID, itemtype, userdata, userproc)
*      Get an item by entityID, itemID, itemtype
*      GatherContext.seglevel and GatherContext.propagated will not be
*        set on the callback.
*   
*      Sets in_scope to FALSE so that the callback is not called
*         Scope is NULL, so in_scope is never TRUE
*      Sets ignore TRUE for everything not needed to find item
*      Sets locatetype and locateID, which are checked in the traversal
*
*****************************************************************************/
NLM_EXTERN Boolean LIBCALL GatherItem (Uint2 entityID, Uint2 itemID, Uint2 itemtype,
                                   Pointer userdata, GatherItemProc userfunc)
{
	return GatherItemFunc (entityID, itemID, itemtype, userdata, userfunc, NULL, FALSE);
}

/*****************************************************************************
*
*   GatherItemFunc (entityID, itemID, itemtype, userdata, userproc, dataptr)
*      Get an item by entityID, itemID, itemtype if dataptr is NULL
*         else it matches entityID, itemtype, dataptr (of type itemtype)
*      GatherContext.seglevel and GatherContext.propagated will not be
*        set on the callback.
*   
*      Sets in_scope to FALSE so that the callback is not called
*         Scope is NULL, so in_scope is never TRUE
*      Sets ignore TRUE for everything not needed to find item
*      Sets locatetype and locateID, which are checked in the traversal
*
*****************************************************************************/
static Boolean NEAR GatherItemFunc (Uint2 entityID, Uint2 itemID, Uint2 itemtype,
                                   Pointer userdata, GatherItemProc userfunc, Pointer dataptr,
								   Boolean do_not_reload_from_cache)

{
	InternalGCC igcc;
	ObjMgrDataPtr omdp;
	GatherScope gs;
	ObjMgrPtr omp;

	if (userfunc == NULL) return FALSE;

	if (itemtype >= OBJ_MAX) return FALSE;

	omp = ObjMgrReadLock();
	omdp = ObjMgrGetDataStruct(omp, entityID);
	ObjMgrUnlock();

	if (omdp == NULL) return FALSE;

	MemSet((Pointer)(&gs), 0, sizeof(GatherScope));
	gs.do_not_reload_from_cache = do_not_reload_from_cache;
	MemSet((Pointer)(gs.ignore), (int)(TRUE), (size_t)((OBJ_MAX)*sizeof(Boolean)));
	gs.ignore[itemtype] = FALSE;
	switch (itemtype)		  /* add higher levels if necessary */
	{
		case OBJ_SEQFEAT_CIT:
			gs.ignore[OBJ_SEQFEAT] = FALSE;
			gs.ignore[OBJ_PUB_SET] = FALSE;
		case OBJ_SEQFEAT:
			gs.ignore[OBJ_SEQANNOT] = FALSE;
			break;
		case OBJ_SEQALIGN:
			gs.ignore[OBJ_SEQANNOT] = FALSE;
			break;
		case OBJ_SEQHIST_ALIGN:
			gs.ignore[OBJ_SEQHIST] = FALSE;
			break;
		case OBJ_SEQGRAPH:
			gs.ignore[OBJ_SEQANNOT] = FALSE;
			break;
		case OBJ_SEQSUB_CONTACT:
		case OBJ_SEQSUB_CIT:
			gs.ignore[OBJ_SUBMIT_BLOCK] = FALSE;
		case OBJ_SUBMIT_BLOCK:
			gs.ignore[OBJ_SEQSUB] = FALSE;
			break;
	}

	if (! IGCCBuild(&igcc, omdp, userdata, userfunc, &gs))
		return FALSE;

	omdp = igcc.omdp;   /* could have been reloaded */

	igcc.locatetype = (Uint1)itemtype;
	igcc.locateID = itemID;
	igcc.locatePtr = dataptr;
    

	GatherEntityFunc(omdp, &igcc, FALSE);

	return IGCCclear(&igcc);
}

typedef struct gatherdatastruct {
	OMProcControlPtr ompcp;
	Boolean succeeded;
} GDS, PNTR GDSPtr;

static Boolean GatherDataProc (GatherContextPtr gcp)
{
	OMProcControlPtr ompcp;
	GDSPtr gdsp;

	gdsp = (GDSPtr)(gcp->userdata);
	ompcp = gdsp->ompcp;
    
    ompcp->input_data = gcp->thisitem;
    
	switch (gcp->thistype)
	{
		case OBJ_BIOSEQSET:
		case OBJ_BIOSEQ:
			if (gcp->sep != NULL)
			{
				ompcp->input_choice = gcp->sep;
				ompcp->input_choicetype = OBJ_SEQENTRY;
			}
			break;
		default:
			break;
	}
	gdsp->succeeded = TRUE;
	return TRUE;
}

static Boolean ReplaceDataProc (GatherContextPtr gcp)
{
	ObjMgrPtr omp;
	ObjMgrTypePtr omtp;
	ObjMgrDataPtr omdp;
	OMProcControlPtr ompcp;
	Pointer oldptr, newptr;
	GDSPtr gdsp;
	SeqEntryPtr sep=NULL;


	gdsp = (GDSPtr)(gcp->userdata);
	ompcp = gdsp->ompcp;
	newptr = ompcp->output_data;

    oldptr = gcp->thisitem;

	omp = ObjMgrReadLock();
	omtp = ObjMgrTypeFind(omp, gcp->thistype, NULL, NULL);
	ObjMgrUnlock();

	if (omtp == NULL)
	{
		ErrPostEx(SEV_ERROR,0,0,"ReplaceDataProc: can't find type [%d]", (int)gcp->thistype);
		return TRUE;
	}

	if (! GatherOverWrite(oldptr, newptr, gcp->thistype))	/* overwrite the old data object */
		return TRUE;

	if (ompcp->output_entityID)   /* remove with objmgr? */
	{
		omp = ObjMgrReadLock();
		omdp = ObjMgrGetDataStruct (omp, ompcp->output_entityID);
		ObjMgrUnlock();

		if (omdp != NULL)
		{
			if ((gcp->thistype == OBJ_BIOSEQ) || (gcp->thistype == OBJ_BIOSEQSET))
				sep = omdp->choice;
			if (ObjMgrWholeEntity(omdp, ompcp->output_itemID, ompcp->output_itemtype))
				ObjMgrDelete(ompcp->output_itemtype, ompcp->output_data);
		}
	}

	if (sep != NULL)
		SeqEntryFree(sep);
	else
		(*(omtp->freefunc))(ompcp->output_data);

	gdsp->succeeded = TRUE;

	return TRUE;
}

static Boolean DetachDataProc (GatherContextPtr gcp)
{
	OMProcControlPtr ompcp;
	Pointer next = NULL, ptr;
	GDSPtr gdsp;

	gdsp = (GDSPtr)(gcp->userdata);
	ompcp = gdsp->ompcp;

    ptr = gcp->thisitem;
    ompcp->input_data = ptr;
    
	switch (gcp->thistype)
	{
		case OBJ_BIOSEQSET:
		case OBJ_BIOSEQ:
			if (gcp->sep != NULL)
			{
				ompcp->input_choice = gcp->sep;
				ompcp->input_choicetype = OBJ_SEQENTRY;
				next = gcp->sep->next;
				gcp->sep->next = NULL;
			}
			break;
		case OBJ_SEQDESC:
		case OBJ_BIOSEQ_SEG:
		case OBJ_PUB:
		case OBJ_SEQFEAT_CIT:
		case OBJ_PUB_SET:
		case OBJ_SEQLOC:
		case OBJ_SEQID:
		case OBJ_SEQENTRY:
			next = (Pointer)(((ValNodePtr)(ptr))->next);
			(((ValNodePtr)(ptr))->next) = NULL;
			break;
		case OBJ_BIOSEQ_MAPFEAT:
		case OBJ_SEQFEAT:
			next = (Pointer)(((SeqFeatPtr)(ptr))->next);
			(((SeqFeatPtr)(ptr))->next) = NULL;
			break;
		case OBJ_SEQANNOT:
			next = (Pointer)(((SeqAnnotPtr)(ptr))->next);
			(((SeqAnnotPtr)(ptr))->next) = NULL;
			break;
		case OBJ_SEQALIGN:
		case OBJ_SEQHIST_ALIGN:
			next = (Pointer)(((SeqAlignPtr)(ptr))->next);
			(((SeqAlignPtr)(ptr))->next) = NULL;
			break;
		case OBJ_SEQGRAPH:
			next = (Pointer)(((SeqGraphPtr)(ptr))->next);
			(((SeqGraphPtr)(ptr))->next) = NULL;
			break;
		default:
			break;
	}
	if (ompcp->whole_entity)  /* nothing to detach from */
		return TRUE;

	if (gcp->prevlink != NULL)
		*(gcp->prevlink) = next;

	ObjMgrDetach(gcp->thistype, ptr);

	gdsp->succeeded = TRUE;

	return TRUE;
}

static void AddAnAnnot(SeqAnnotPtr PNTR head, Pointer ptr)
{
	SeqAnnotPtr prev, sap;

	if (head == NULL) return;
	sap = (SeqAnnotPtr)ptr;

	if (*head == NULL)
	{
		*head = sap;
		return;
	}

	for (prev = (*head); prev->next != NULL; prev = prev->next)
		continue;

	prev->next = sap;
	return;
}

static Boolean AddToSeqAnnot (SeqAnnotPtr sap, Int2 the_type, Pointer addptr)
{
	SeqFeatPtr sfp;
	SeqAlignPtr salp;
	SeqGraphPtr sgp;
	Pointer PNTR prevlink = NULL;

	if (sap == NULL) return FALSE;

	if (sap->type == 0)
		sap->type = (Uint1)the_type;

	if (sap->type != (Uint1)the_type)
		return FALSE;

	if (sap->data == NULL)
		prevlink = &(sap->data);
	else
	{
		switch (the_type)
		{
			case 1:   /* feature table */
				for (sfp = (SeqFeatPtr)(sap->data); sfp->next != NULL; sfp = sfp->next)
					continue;
				prevlink = (Pointer PNTR)&(sfp->next);
				break;
			case 2:   /* alignments */
				for (salp = (SeqAlignPtr)(sap->data); salp->next != NULL; salp = salp->next)
					continue;
				prevlink = (Pointer PNTR)&(salp->next);
				break;
			case 3:   /* Graph */
				for (sgp = (SeqGraphPtr)(sap->data); sgp->next != NULL; sgp = sgp->next)
					continue;
				prevlink = (Pointer PNTR)&(sgp->next);
				break;
		}
	}
	if (prevlink != NULL)
		*prevlink = addptr;

	return TRUE;
}

static void AddToAnnot(SeqAnnotPtr PNTR head, Int2 the_type, Pointer addptr)
{
	SeqAnnotPtr sap, prev=NULL;

	if (head == NULL) return;

	for (sap = *head; sap != NULL; sap = sap->next)
	{
		if (sap->type == the_type)
			break;
		prev = sap;
	}

	if (sap == NULL)
	{
		sap = SeqAnnotNew();
		sap->type = (Uint1)the_type;
		if (prev != NULL)
			prev->next = sap;
		else
			*head = sap;
	}

	AddToSeqAnnot(sap, the_type, addptr);

	return;
}

static ValNodePtr PubFromDescr(ValNodePtr desc)
{
	ValNodePtr vnp2, vnp;
	PubdescPtr pdp;

	if (desc->choice != Seq_descr_pub)
		return NULL;

	pdp = (PubdescPtr)(desc->data.ptrvalue);
	vnp = pdp->pub;
	pdp->pub = NULL;

	SeqDescFree(desc);

	if (vnp == NULL) return vnp;

	if (vnp->next != NULL)
	{
		vnp2 = vnp;
		vnp = ValNodeNew(NULL);
		vnp->choice = PUB_Equiv;
		vnp->data.ptrvalue = vnp2;
	}

	return vnp;
}

static ValNodePtr DescrFromPub(ValNodePtr pub)
{
	ValNodePtr vnp;
	PubdescPtr pdp;

	pdp = PubdescNew();
	if (pub->choice == PUB_Equiv)
	{
		vnp = (ValNodePtr)(pub->data.ptrvalue);
		MemFree(pub);
		pub = vnp;
	}
	pdp->pub = pub;
	vnp = ValNodeNew(NULL);
	vnp->choice = Seq_descr_pub;
	vnp->data.ptrvalue = (Pointer)pdp;
	return vnp;
}

static Boolean AttachDataProc (GatherContextPtr gcp)
{
	OMProcControlPtr ompcp;
	Pointer ptr, newptr;
	Uint2 into, newtype;
	Boolean no_good = FALSE, into_seqentry = FALSE;
	ValNodePtr vnp;
	ObjMgrDataPtr omdp=NULL;
	ObjMgrPtr omp;
	BioseqPtr bsp;
	BioseqSetPtr bssp;
	SeqAnnotPtr sap;
	SeqFeatPtr sfp;
	SeqAlignPtr salp;
	SeqGraphPtr sgp;
	SeqSubmitPtr ssp;
	SubmitBlockPtr sbp;
	GDSPtr gdsp;

	gdsp = (GDSPtr)(gcp->userdata);
	ompcp = gdsp->ompcp;

    ptr = gcp->thisitem;   /* insert before or into this */
    ompcp->input_data = ptr;

    into = gcp->thistype;
	newtype = ompcp->output_itemtype;
	newptr = ompcp->output_data;

	omp = ObjMgrWriteLock();
	omdp = ObjMgrFindByData(omp, newptr);

	switch (into)
	{
		case OBJ_BIOSEQSET:
		case OBJ_BIOSEQ:
			if (gcp->sep != NULL)
			{
				ompcp->input_choice = gcp->sep;
				ompcp->input_choicetype = OBJ_SEQENTRY;
				into_seqentry = TRUE;
			}
			break;
		default:
			break;
	}

	switch (into)
	{
		case OBJ_SEQSUB:
			ssp = (SeqSubmitPtr)(ptr);
			switch (newtype)
			{
				case OBJ_BIOSEQSET:
				case OBJ_BIOSEQ:
					if (omdp == NULL)
					{
						ErrPostEx(SEV_ERROR,0,0,"AttachDataProc: Not entity for Bioseq(Set)");
						return TRUE;
					}
					if (ssp->datatype == 0)
						ssp->datatype = 1;
					if (ssp->datatype != 1)
					{
						no_good = TRUE;
						break;
					}
					if (omdp->choice == NULL)
					{
						omdp->choice = ValNodeNew(NULL);
						omdp->choicetype = OBJ_SEQENTRY;
						omdp->choice->data.ptrvalue = newptr;
						if (newtype == OBJ_BIOSEQ)
							omdp->choice->choice = 1;
						else
							omdp->choice->choice = 2;
					}
					ValNodeLink((ValNodePtr PNTR)&(ssp->data), omdp->choice);
					ObjMgrConnectFunc(omp, newtype, newptr, into, ptr);
					break;
				case OBJ_PUB:
					vnp = (ValNodePtr)newptr;
					no_good = TRUE;
					if (vnp->choice == PUB_Sub)
					{
						if (ssp->sub == NULL)
							ssp->sub = SubmitBlockNew();
						if (ssp->sub->cit == NULL)
						{
							ssp->sub->cit = (CitSubPtr)(vnp->data.ptrvalue);
							ValNodeFree(vnp);
							no_good = FALSE;
						}
					}
					break;
				case OBJ_SEQENTRY:
					if (ssp->datatype == 0)
						ssp->datatype = 1;
					if (ssp->datatype != 1)
					{
						no_good = TRUE;
						break;
					}
					ValNodeLink((ValNodePtr PNTR)&(ssp->data), omdp->choice);
					ObjMgrConnectFunc(omp, newtype, newptr, into, ptr);
					break;
				case OBJ_SEQANNOT:
					if (ssp->datatype == 0)
						ssp->datatype = 2;
					if (ssp->datatype != 2)
					{
						no_good = TRUE;
						break;
					}
					AddAnAnnot((SeqAnnotPtr PNTR)&(ssp->data), newptr);
					break;
				case OBJ_SEQFEAT:
					if (ssp->datatype == 0)
						ssp->datatype = 2;
					if (ssp->datatype != 2)
					{
						no_good = TRUE;
						break;
					}
					AddToAnnot((SeqAnnotPtr PNTR)&(ssp->data), 1, newptr);
					break;
				case OBJ_SEQALIGN:
					if (ssp->datatype == 0)
						ssp->datatype = 2;
					if (ssp->datatype != 2)
					{
						no_good = TRUE;
						break;
					}
					AddToAnnot((SeqAnnotPtr PNTR)&(ssp->data), 2, newptr);
					break;
				case OBJ_SEQGRAPH:
					if (ssp->datatype == 0)
						ssp->datatype = 2;
					if (ssp->datatype != 2)
					{
						no_good = TRUE;
						break;
					}
					AddToAnnot((SeqAnnotPtr PNTR)&(ssp->data), 3, newptr);
					break;
				case OBJ_SUBMIT_BLOCK:
					if (ssp->sub == NULL)
						ssp->sub = (SubmitBlockPtr)newptr;
					else
						no_good = TRUE;
					break;
				case OBJ_SEQSUB_CONTACT:
					if (ssp->sub == NULL)
						ssp->sub = SubmitBlockNew();
					if (ssp->sub->contact == NULL)
						ssp->sub->contact = (ContactInfoPtr)newptr;
					else
						no_good = TRUE;
					break;
				default:
					no_good = TRUE;
					break;
			}
			break;
		case OBJ_SUBMIT_BLOCK:
			sbp = (SubmitBlockPtr)(ptr);
			switch (newtype)
			{
				case OBJ_PUB:
					vnp = (ValNodePtr)newptr;
					no_good = TRUE;
					if (vnp->choice == PUB_Sub)
					{
						if (sbp->cit == NULL)
						{
							sbp->cit = (CitSubPtr)(vnp->data.ptrvalue);
							ValNodeFree(vnp);
							no_good = FALSE;
						}
					}
					break;
				case OBJ_SEQSUB_CONTACT:
					if (sbp->contact == NULL)
						sbp->contact = (ContactInfoPtr)newptr;
					else
						no_good = TRUE;
					break;
				default:
					no_good = TRUE;
					break;
			}
			break;
		case OBJ_BIOSEQSET:
			bssp = (BioseqSetPtr)(ptr);
			switch (newtype)
			{
				case OBJ_BIOSEQSET:
				case OBJ_BIOSEQ:
					if (omdp == NULL)
					{
						ErrPostEx(SEV_ERROR,0,0,"AttachDataProc: Not entity for Bioseq(Set)");
						return TRUE;
					}
					if (omdp->choice == NULL)
					{
						omdp->choice = ValNodeNew(NULL);
						omdp->choicetype = OBJ_SEQENTRY;
						omdp->choice->data.ptrvalue = newptr;
						if (newtype == OBJ_BIOSEQ)
							omdp->choice->choice = 1;
						else
							omdp->choice->choice = 2;
					}
					ValNodeLink(&(bssp->seq_set), omdp->choice);
					ObjMgrConnectFunc(omp, newtype, newptr, into, ptr);
					break;
				case OBJ_SEQDESC:
					ValNodeLink(&(bssp->descr), (ValNodePtr)newptr);
					break;
				case OBJ_PUB:			   /* make a pubdesc */
				case OBJ_SEQFEAT_CIT:
					vnp = DescrFromPub((ValNodePtr)newptr);
					ValNodeLink(&(bssp->descr), vnp);
					break;
				case OBJ_SEQENTRY:
					ValNodeLink(&(bssp->seq_set), newptr);
					break;
				case OBJ_SEQANNOT:
					AddAnAnnot(&(bssp->annot), newptr);
					break;
				case OBJ_SEQFEAT:
					AddToAnnot(&(bssp->annot), 1, newptr);
					break;
				case OBJ_SEQALIGN:
				case OBJ_SEQHIST_ALIGN:
					AddToAnnot(&(bssp->annot), 2, newptr);
					break;
				case OBJ_SEQGRAPH:
					AddToAnnot(&(bssp->annot), 3, newptr);
					break;
				default:
					no_good = TRUE;
					break;
			}
			break;
		case OBJ_BIOSEQ:
			bsp = (BioseqPtr)(ptr);
			switch (newtype)
			{
				case OBJ_BIOSEQSET:
				case OBJ_BIOSEQ:
					if (omdp == NULL)
					{
						ErrPostEx(SEV_ERROR,0,0,"AttachDataProc: Not entity for Bioseq(Set)");
						return TRUE;
					}
					if (omdp->choice == NULL)
					{
						omdp->choice = ValNodeNew(NULL);
						omdp->choicetype = OBJ_SEQENTRY;
						omdp->choice->data.ptrvalue = newptr;
						if (newtype == OBJ_BIOSEQ)
							omdp->choice->choice = 1;
						else
							omdp->choice->choice = 2;
					}
					if ((gcp->parentitem != NULL) && (gcp->prevlink != NULL))
					{
						omdp->choice->next = *(gcp->prevlink);
						*(gcp->prevlink) = omdp->choice;
						ObjMgrConnectFunc(omp, newtype, newptr, gcp->parenttype, gcp->parentitem);
					}
					else
						no_good = TRUE;
					break;
				case OBJ_SEQDESC:
					ValNodeLink(&(bsp->descr), (ValNodePtr)newptr);
					break;
				case OBJ_PUB:			   /* make a pubdesc */
				case OBJ_SEQFEAT_CIT:
					vnp = DescrFromPub((ValNodePtr)newptr);
					ValNodeLink(&(bsp->descr), vnp);
					break;
				case OBJ_SEQENTRY:
					if ((gcp->parentitem != NULL) && (gcp->prevlink != NULL))
					{
						omdp->choice->next = *(gcp->prevlink);
						*(gcp->prevlink) = omdp->choice;
						ObjMgrConnectFunc(omp, newtype, newptr, gcp->parenttype, gcp->parentitem);
					}
					else
						no_good = TRUE;
					break;
				case OBJ_SEQANNOT:
					AddAnAnnot(&(bsp->annot), newptr);
					break;
				case OBJ_SEQFEAT:
					AddToAnnot(&(bsp->annot), 1, newptr);
					break;
				case OBJ_SEQALIGN:
				case OBJ_SEQHIST_ALIGN:
					AddToAnnot(&(bsp->annot), 2, newptr);
					break;
				case OBJ_SEQGRAPH:
					AddToAnnot(&(bsp->annot), 3, newptr);
					break;
				case OBJ_SEQHIST:
					if (bsp->hist == NULL)
					{
						bsp->hist = (SeqHistPtr)newptr;
						break;
					}
				default:
					no_good = TRUE;
					break;
			}
			break;
		case OBJ_SEQDESC:
			vnp = (ValNodePtr)newptr;
			switch (newtype)
			{
				case OBJ_PUB:
					vnp = DescrFromPub(vnp);
				case OBJ_SEQDESC:
					if (gcp->prevlink != NULL)
					{
						vnp->next = *(gcp->prevlink);
						*(gcp->prevlink) = vnp;
					}
					else
						no_good = TRUE;
					break;
				default:
					no_good = TRUE;
					break;
			}
			break;
		case OBJ_SEQFEAT_CIT:
		case OBJ_PUB_SET:
			vnp = (ValNodePtr)newptr;
			switch (newtype)
			{
				case OBJ_SEQDESC:
					vnp = PubFromDescr(vnp);
					if (vnp == NULL)
					{
						no_good = TRUE;
						break;
					}
				case OBJ_PUB:
					if (gcp->prevlink != NULL)
					{
						vnp->next = *(gcp->prevlink);
						*(gcp->prevlink) = vnp;
					}
					else
						no_good = TRUE;
					break;
				default:
					no_good = TRUE;
					break;
			}
			break;
		case OBJ_SEQANNOT:
			sap = (SeqAnnotPtr)ptr;
			switch (newtype)
			{
				case OBJ_SEQFEAT:
					if (! AddToSeqAnnot(sap, 1, newptr))
						no_good = TRUE;
					break;
				case OBJ_SEQALIGN:
				case OBJ_SEQHIST_ALIGN:
					if (! AddToSeqAnnot(sap, 2, newptr))
						no_good = TRUE;
					break;
				case OBJ_SEQGRAPH:
					if (! AddToSeqAnnot(sap, 3, newptr))
						no_good = TRUE;
					break;
				case OBJ_SEQANNOT:
					sap = (SeqAnnotPtr)newptr;
					if (gcp->prevlink != NULL)
					{
						sap->next = *(gcp->prevlink);
						*(gcp->prevlink) = sap;
					}
					else
						no_good = TRUE;
					break;
				default:
					no_good = TRUE;
					break;
			}
			break;
		case OBJ_BIOSEQ_MAPFEAT:
		case OBJ_SEQFEAT:
			sfp = (SeqFeatPtr)ptr;
			switch (newtype)
			{
				case OBJ_SEQDESC:
					newptr = (Pointer)PubFromDescr((ValNodePtr)newptr);
				case OBJ_PUB:
					if (sfp->cit == NULL)
					{
						sfp->cit = ValNodeNew(NULL);
						sfp->cit->choice = 1;
					}
					ValNodeLink((ValNodePtr PNTR)&(sfp->cit->data.ptrvalue), (ValNodePtr)newptr);
					break;
				case OBJ_SEQFEAT:
					sfp = (SeqFeatPtr)newptr;
					if (gcp->prevlink != NULL)
					{
						sfp->next = *(gcp->prevlink);
						*(gcp->prevlink) = sfp;
					}
					else
						no_good = TRUE;
					break;
				case OBJ_SEQLOC:
					SeqLocFree(sfp->location); /* make assumption */
					sfp->location = (ValNodePtr)newptr;
					break;
				default:
					no_good = TRUE;
					break;
			}
			break;
		case OBJ_SEQALIGN:
		case OBJ_SEQHIST_ALIGN:
		case OBJ_SEQHIST:
			switch (newtype)
			{
				case OBJ_SEQALIGN:
				case OBJ_SEQHIST_ALIGN:
					salp = (SeqAlignPtr)newptr;
					if (gcp->prevlink != NULL)
					{
						salp->next = *(gcp->prevlink);
						*(gcp->prevlink) = salp;
					}
					else
						no_good = TRUE;
					break;
				default:
					no_good = TRUE;
					break;
			}
			break;
		case OBJ_SEQGRAPH:
			switch (newtype)
			{
				case OBJ_SEQGRAPH:
					sgp = (SeqGraphPtr)newptr;
					if (gcp->prevlink != NULL)
					{
						sgp->next = *(gcp->prevlink);
						*(gcp->prevlink) = sgp;
					}
					else
						no_good = TRUE;
					break;
				default:
					no_good = TRUE;
					break;
			}
			break;
		case OBJ_SEQLOC:
		case OBJ_SEQID:
		case OBJ_SEQENTRY:
		default:
			no_good = TRUE;
			break;
	}
	
	ObjMgrUnlock();

	if (no_good)
	{
		ErrPostEx(SEV_ERROR,0,0,"AttachDataProc: [%d] into [%d]", (int)newtype, (int)into);
	}
	else
	{
		gdsp->succeeded = TRUE;
		switch (newtype)
		{
			case OBJ_BIOSEQ:
			case OBJ_BIOSEQSET:
				break;
			default:
				if (omdp != NULL)
					ObjMgrDelete(omdp->datatype, omdp->dataptr);
		}
	}

	return TRUE;
}

static Boolean CopyDataProc (GatherContextPtr gcp)
{
	OMProcControlPtr ompcp;
	ObjMgrTypePtr omtp;
	ObjMgrPtr omp;
	Uint2 type;
	Pointer ptr, ptr2;
	Boolean was_choice = FALSE;
	GDSPtr gdsp;

	gdsp = (GDSPtr)(gcp->userdata);
	ompcp = gdsp->ompcp;

    ptr = gcp->thisitem;
	type = gcp->thistype;
    ompcp->input_data = ptr;
    
	switch (gcp->thistype)
	{
		case OBJ_BIOSEQSET:
		case OBJ_BIOSEQ:
			if (gcp->sep != NULL)
			{
				ompcp->input_choice = gcp->sep;
				ptr = (Pointer)(gcp->sep);
				ompcp->input_choicetype = OBJ_SEQENTRY;
				type = OBJ_SEQENTRY;
				was_choice = TRUE;
			}
			break;
		default:
			break;
	}

	omp = ObjMgrReadLock();
	omtp = ObjMgrTypeFind(omp, type, NULL, NULL);
	ObjMgrUnlock();

	if (omtp == NULL)
	{
		ErrPostEx(SEV_ERROR,0,0,"CopyDataProc: can't find type [%d]", (int)type);
		return TRUE;
	}

	ptr2 = AsnIoMemCopy(ptr, omtp->asnread, omtp->asnwrite);
	if (ptr2 != NULL)
	{
		gdsp->succeeded = TRUE;

		if (! was_choice)
		{
			ompcp->output_data = ptr2;
			ompcp->output_itemtype = type;
		}
		else
		{
			ompcp->output_choice = ptr2;
			ompcp->output_choicetype = type;
			ompcp->output_data = ((ValNodePtr)(ptr2))->data.ptrvalue;
			ompcp->output_itemtype = gcp->thistype;
		}
		switch (ompcp->output_itemtype)
		{
			case OBJ_BIOSEQSET:    /* these types Add to the ObjMgr themselves */
			case OBJ_BIOSEQ:
			case OBJ_SEQSUB:
				break;
			default:
				ObjMgrAdd(ompcp->output_itemtype, ompcp->output_data);
				break;
		}
	}
	return TRUE;
}

static Boolean NEAR GenericGatherDataForProc (OMProcControlPtr ompcp, Boolean sel, Int2 func)
{
	ObjMgrDataPtr omdp;
	SelStructPtr ssp;
	Boolean retval = FALSE, data_changed = FALSE;
	static CharPtr funcs [5] = {
		"GatherDataForProc",
		"DetachDataForProc",
		"AttachDataForProc",
		"CopyDataForProc",
		"ReplaceDataForProc" };
	GatherItemProc gip;
	GDS gds;
	ObjMgrPtr omp;

	gds.succeeded = retval;
	gds.ompcp = ompcp;

	if (sel)
	{
		ssp = ObjMgrGetSelected();
		if (ssp == NULL)
		{
			/*
			ErrPostEx(SEV_ERROR,0,0,"%s: Nothing was selected", funcs[func]);
			*/
			return retval;
		}
		ompcp->input_entityID = ssp->entityID;
		ompcp->input_itemID = ssp->itemID;
		ompcp->input_itemtype = ssp->itemtype;
	}

	if (func == 1) /* detach: changes selection */
		ObjMgrDeSelect(ompcp->input_entityID, ompcp->input_itemID, ompcp->input_itemtype, 0, NULL);

	omp = ObjMgrReadLock();
	omdp = ObjMgrGetDataStruct (omp, ompcp->input_entityID);

	if (omdp == NULL)
	{
		ObjMgrUnlock();
		ErrPostEx(SEV_ERROR,0,0,"%s: can't match entityID", funcs[func]);
	 	return retval;
	}
	
	if ((ompcp->input_itemID <= 1) &&
	    ((ompcp->input_itemtype == 0) || (ompcp->input_itemtype == omdp->datatype)))  /* top level */
	{
		ompcp->input_choice = omdp->choice;
		ompcp->input_choicetype = omdp->choicetype;
		ompcp->input_itemtype = omdp->datatype;
		ompcp->input_data = omdp->dataptr;
		ompcp->whole_entity = TRUE;
		if ((func == 0) || (func == 1))  /* gather or detach */
		{
			ObjMgrUnlock();
			return TRUE;
		}
	}

	ObjMgrUnlock();

	if (func == 4)    /* replace */
	{
		if (ompcp->input_itemtype != ompcp->output_itemtype)
		{
			ErrPostEx(SEV_ERROR,0,0,"%s: input type %d != output type %d",
				funcs[func], (int)(ompcp->input_itemtype), (int)(ompcp->output_itemtype));
			return FALSE;
		}

		if (ompcp->output_data == NULL)
		{
			ErrPostEx(SEV_ERROR,0,0,"%s: no output_data", funcs[func]);
			return FALSE;
		}
	}

	switch(func)
	{
		case 0:
			gip = GatherDataProc;
			break;
		case 1:
			gip = DetachDataProc;
			data_changed = TRUE;
			break;
		case 2:
			gip = AttachDataProc;
			data_changed = TRUE;
			break;
		case 3:
			gip = CopyDataProc;
			break;
		case 4:
			gip = ReplaceDataProc;
			data_changed = TRUE;
			break;

	}

	retval = GatherItemFunc (ompcp->input_entityID, ompcp->input_itemID,
                  ompcp->input_itemtype,(Pointer)(&gds), gip, NULL, ompcp->do_not_reload_from_cache);

	if (! retval)
		ErrPostEx(SEV_ERROR,0,0,"%s: can't do the gather", funcs[func]);
	else
		retval = gds.succeeded;

	if ((retval) && (data_changed))   /* set the dirty flag */
	{
		ObjMgrSetDirtyFlag(ompcp->input_entityID, TRUE);
	}
	return retval;
}

/****************************************************************************
*
*   GatherDataForProc(ompcp, sel)
*
*       fills in data, choice, and choictype in OMProcControlPtr
*         sets ompcp->whole_entity TRUE if appropriate
*       returns TRUE if it did it
*       if (sel == TRUE), fills in ompcp with data from ObjMgrGetSelect first.
*          returns FALSE if nothing selected.. Does ErrPostEx() for it
*
****************************************************************************/
NLM_EXTERN Boolean LIBCALL GatherDataForProc (OMProcControlPtr ompcp, Boolean sel)
{
	return GenericGatherDataForProc(ompcp, sel, 0);
}

/****************************************************************************
*
*   DetachDataForProc(ompcp, sel)
*
*       fills in data, choice, and choictype in OMProcControlPtr
*         sets ompcp->whole_entity TRUE if appropriate
*       returns TRUE if it did it
*       if (sel == TRUE), fills in ompcp with data from ObjMgrGetSelect first.
*          returns FALSE if nothing selected.. Does ErrPostEx() for it
*       Detaches data item from surrounding data if necessary
*
****************************************************************************/
NLM_EXTERN Boolean LIBCALL DetachDataForProc (OMProcControlPtr ompcp, Boolean sel)
{
	return GenericGatherDataForProc(ompcp, sel, 1);
}

/****************************************************************************
*
*   AttachDataForProc(ompcp, sel)
*
*       fills in data, choice, and choictype in OMProcControlPtr
*         sets ompcp->whole_entity TRUE if appropriate
*       returns TRUE if it did it
*       if (sel == TRUE), fills in ompcp with data from ObjMgrGetSelect first.
*          returns FALSE if nothing selected.. Does ErrPostEx() for it
*       Attaches data in output section of ompcp into the input section
*
****************************************************************************/
NLM_EXTERN Boolean LIBCALL AttachDataForProc (OMProcControlPtr ompcp, Boolean sel)
{
	return GenericGatherDataForProc(ompcp, sel, 2);
}

/****************************************************************************
*
*   CopyDataForProc(ompcp, sel)
*
*       fills in data, choice, and choictype in OMProcControlPtr
*         sets ompcp->whole_entity TRUE if appropriate
*       returns TRUE if it did it
*       if (sel == TRUE), fills in ompcp with data from ObjMgrGetSelect first.
*          returns FALSE if nothing selected.. Does ErrPostEx() for it
*       Attaches copy of data in output section of ompcp
*
****************************************************************************/
NLM_EXTERN Boolean LIBCALL CopyDataForProc (OMProcControlPtr ompcp, Boolean sel)
{
	return GenericGatherDataForProc(ompcp, sel, 3);
}

/****************************************************************************
*
*   ReplaceDataForProc(ompcp, sel)
*
*       fills in data, choice, and choictype in OMProcControlPtr
*         sets ompcp->whole_entity TRUE if appropriate
*       returns TRUE if it did it
*       if (sel == TRUE), fills in ompcp with data from ObjMgrGetSelect first.
*          returns FALSE if nothing selected.. Does ErrPostEx() for it
*       Replaces data in input section of ompcp with the output section
*       Data in input section is deleted
*
****************************************************************************/
NLM_EXTERN Boolean LIBCALL ReplaceDataForProc (OMProcControlPtr ompcp, Boolean sel)
{
	return GenericGatherDataForProc(ompcp, sel, 4);
}

/*****************************************************************************
*
*   GatherProcLaunch(proctype, sel, entityID, itemID, itemtype,
*        inputtype, subinputtype, outputtype, suboutputtype)
*   	looks for ALL proctype in priority order that
*   		matches inputtype and outputtype
*     if (sel) then fills in entityID,itemID,itemtype with currently selected
*        item
*     else
*        uses the function arguments
*     locates the data pointer, determines the subtype (if any)
*     then finds the process that will return OM_MSG_RET_DONE in priority order
*   	0 on outputtype, inputsubtype, outputsubtype matches any
*     if subtype can be matched on input/output, takes in preference over
*        more general proc
*
*     USAGE:
*     1) To launch an editor for the currently selected item
*      GatherProcLaunch(OMPROC_EDIT,TRUE,0,0,0,0,0,0,0);
*     2) To launch an editor to create a new seq_descr of type pub
*      GatherProcLaunch(OMPROC_EDIT,FALSE,0,0,0,OBJ_SEQDESC,Seq_descr_pub,0,0);
*     3) To launch an editor for a specific seq_descr
*      GatherProcLaunch(OMPROC_EDIT,FALSE,2,1,4,0,0,0,0);
*        (where the 3 numbers identify the seq_descr)
*     4)To launch an editor which will create a new seq_descr and attach it
*        to the currently selected Bioseq
*      GatherProcLaunch(OMPROC_EDIT,TRUE,0,0,0,OBJ_SEQDESC,Seq_descr_pub,0,0)
*        Note in this case ompcp->input_entityid, .input_itemid, input_itemtype
*          well refer to a Bioseq. The editor should check the input_itemtype
*          and decide if it can attach it's output to it, or if it is an
*          input type mismatch error.
*     5) To launch an editor which will create a new seq_descr and attach to
*        a specific Bioseq
*         (Same as (4) but sel=FALSE, and entitid,itemid,itemtype filled in
*          for the Bioseq).
*
*     GENERAL RULES:
*
*     All this means the function will be called with OMProcControlPtr (ompcp)
*      fields filled in (input_entityid, input_itemid, input_itemtype) as:
*       1) Create new one, place in desktop = 0,0,0
*       2) Edit old one, non-zero values, with input_itemtype matching the type
*          of the editor.
*       3) Create a new one, attach it to something else, non-zero values,
*          with input_itemtype not matching the type of the editor.
*
*     Functions to install the returned values are for the cases above:
*       1) ObjMgrRegister()
*       2) GatherReplaceDataForProc()
*       3) GatherAttachDataForProc()
*
*     returns the return from the proc, or OM_MSG_RET_NOPROC if not found
*
*****************************************************************************/
NLM_EXTERN Int2 GatherProcLaunch (Uint2 proctype, Boolean sel, Uint2 entityID, Uint2 itemID,
                    Uint2 itemtype, Uint2 inputtype, Uint2 subinputtype, Uint2 outputtype, Uint2 suboutputtype)
{
	ObjMgrPtr omp;
	OMProcControl ompc;
	ObjMgrProcPtr ompp=NULL;
	ObjMgrTypePtr omtp;
	Boolean retval, do_general_proc = FALSE;
	Uint2 subtype = 0;
	Int2 procval = OM_MSG_RET_NOPROC;

	MemSet((Pointer)(&ompc), 0, sizeof(OMProcControl));

	ompc.input_entityID = entityID;
	ompc.input_itemID = itemID;
	ompc.input_itemtype = itemtype;

	retval = GatherDataForProc(&ompc, sel);

	if (sel && (! retval))
		return OM_MSG_RET_ERROR;

	if (entityID && (! retval))
		return OM_MSG_RET_ERROR;

	if (! inputtype)   /* not set on input */
		inputtype = ompc.input_itemtype;   /* could now be filled in */

	omp = NULL;  /* do all temporary read locks */
	if ((! subinputtype) && (inputtype == ompc.input_itemtype)
		               && (ompc.input_data != NULL))
	{
		omtp = ObjMgrTypeFind(omp, inputtype, NULL, NULL);
		if (omtp != NULL)
			subinputtype = (*(omtp->subtypefunc))(ompc.input_data);
	}

	while ((ompp = ObjMgrProcFindNext(omp, proctype, inputtype, outputtype, ompp)) != NULL)
	{
		if (ompp->subinputtype == subinputtype)
		{
			ompc.proc = ompp;
			procval = (*(ompp->func))((Pointer)&ompc);
			switch (procval)
			{
				case OM_MSG_RET_ERROR:
					ErrShow();
					break;
				case OM_MSG_RET_DEL:
					break;
				case OM_MSG_RET_OK:
					break;
				case OM_MSG_RET_DONE:
					goto all_done;
				default:
					break;
			}
		}
		else if (! ompp->subinputtype)  /* general proc found */
			do_general_proc = TRUE;
	}

	if (do_general_proc)    /* specific proc failed, try a general one */
	{
		while ((ompp = ObjMgrProcFindNext(omp, proctype, inputtype, outputtype, ompp)) != NULL)
		{
			if (! ompp->subinputtype)
			{
				ompc.proc = ompp;
				procval = (*(ompp->func))((Pointer)&ompc);
				switch (procval)
				{
					case OM_MSG_RET_ERROR:
						ErrShow();
						break;
					case OM_MSG_RET_DEL:
						break;
					case OM_MSG_RET_OK:
						break;
					case OM_MSG_RET_DONE:
						goto all_done;
					default:
						break;
				}
			}
		}
	}

all_done:
	return procval;

}

NLM_EXTERN Int2 GatherSpecificProcLaunch (Uint2 procid, CharPtr procname, Uint2 proctype,
                                          Boolean sel, Uint2 entityID, Uint2 itemID, Uint2 itemtype)
{
	ObjMgrPtr omp;
	OMProcControl ompc;
	ObjMgrProcPtr ompp=NULL;
	Boolean retval;
	Int2 procval = OM_MSG_RET_NOPROC;

	omp = ObjMgrGet ();

	MemSet((Pointer)(&ompc), 0, sizeof(OMProcControl));

	ompc.input_entityID = entityID;
	ompc.input_itemID = itemID;
	ompc.input_itemtype = itemtype;

	retval = GatherDataForProc(&ompc, sel);

	if (sel && (! retval))
		return OM_MSG_RET_ERROR;

	if (entityID && (! retval))
		return OM_MSG_RET_ERROR;

	ompp = ObjMgrProcFind (omp, procid, procname, proctype);
	if (ompp == NULL)
		return OM_MSG_RET_ERROR;

	ompc.proc = ompp;
	procval = (*(ompp->func))((Pointer)&ompc);
	switch (procval)
	{
		case OM_MSG_RET_ERROR:
			ErrShow();
			break;
		case OM_MSG_RET_DEL:
			break;
		case OM_MSG_RET_OK:
			break;
		case OM_MSG_RET_DONE:
			goto all_done;
		default:
			break;
	}

all_done:
	return procval;

}
/*****************************************************************
*
*  GatherOverWrite (oldptr, newptr, type)
*      type is OBJ_...
*      overwrites oldptr with contents of newptr
*      sets any "next" pointers contained in newptr to point to the same
*        chain as those in oldptr did
*      this function is used for making a varient copy of an object, then
*        replacing it in another object without changing points to or from
*        this object
*******************************************************************/
NLM_EXTERN Boolean LIBCALL GatherOverWrite (Pointer oldptr, Pointer newptr, Uint2 type)
{
    size_t size = 0;
	Pointer dest, next=NULL, oldsrc;
	ValNodePtr vnp;

	if ((oldptr == NULL) || (newptr == NULL))
		return FALSE;

	oldsrc = oldptr;
	switch (type)
	{
		case OBJ_SEQSUB:
			size = sizeof(SeqSubmit);
			break;
		case OBJ_SUBMIT_BLOCK:
			size = sizeof(SubmitBlock);
			break;
		case OBJ_SEQSUB_CONTACT:
			size = sizeof(ContactInfo);
			break;
		case OBJ_SEQSUB_CIT:
			size = sizeof(CitSub);
			break;
		case OBJ_SEQHIST:
			size = sizeof(SeqHist);
			break;
		case OBJ_BIOSEQSET:
			size = sizeof(BioseqSet);
			break;
		case OBJ_BIOSEQ:
			size = sizeof(Bioseq);
			break;
		case OBJ_SEQDESC:
		case OBJ_BIOSEQ_SEG:
		case OBJ_PUB:
		case OBJ_SEQFEAT_CIT:
		case OBJ_PUB_SET:
		case OBJ_SEQLOC:
		case OBJ_SEQID:
		case OBJ_SEQENTRY:
			vnp = (ValNodePtr)oldptr;
			oldsrc = &(vnp->data);
			size = sizeof(DataVal);
			vnp = (ValNodePtr)newptr;
			newptr = &(vnp->data);
			break;
		case OBJ_BIOSEQ_MAPFEAT:
		case OBJ_SEQFEAT:
			size = sizeof(SeqFeat);
			next = (Pointer)(((SeqFeatPtr)(oldptr))->next);
			(((SeqFeatPtr)(oldptr))->next) = NULL;
			(((SeqFeatPtr)(newptr))->next) = (SeqFeatPtr)next;
			break;
		case OBJ_SEQANNOT:
			size = sizeof(SeqAnnot);
			next = (Pointer)(((SeqAnnotPtr)(oldptr))->next);
			(((SeqAnnotPtr)(oldptr))->next) = NULL;
			(((SeqAnnotPtr)(newptr))->next) = (SeqAnnotPtr)next;
			break;
		case OBJ_SEQALIGN:
		case OBJ_SEQHIST_ALIGN:
			size = sizeof(SeqAlign);
			next = (Pointer)(((SeqAlignPtr)(oldptr))->next);
			(((SeqAlignPtr)(oldptr))->next) = NULL;
			(((SeqAlignPtr)(newptr))->next) = (SeqAlignPtr)next;
			break;
		case OBJ_SEQGRAPH:
			size = sizeof(SeqGraph);
			next = (Pointer)(((SeqGraphPtr)(oldptr))->next);
			(((SeqGraphPtr)(oldptr))->next) = NULL;
			(((SeqGraphPtr)(newptr))->next) = (SeqGraphPtr)next;
			break;
		default:
			ErrPostEx(SEV_ERROR,0,0,"ObjMgrOverWrite: unsupported type %d",
				(int)(type));
			return FALSE;
	}

	if (! size)
		return FALSE;

	dest = MemNew(size);   /* temporary buffer for copies */
	if (dest == NULL)
	{
		ErrPostEx(SEV_ERROR,0,0,"ObjMgrOverWrite: can't allocate buffer");
		return FALSE;
	}
    
	MemCopy(dest, oldsrc, size);    /* replace the contents */
	MemCopy(oldsrc, newptr, size);
	MemCopy(newptr, dest, size);

	MemFree(dest);

	return TRUE;
}



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

/* AssignIDsInEntity/VisitObjectsInEntity section */

typedef struct internalacc {
  Uint2             entityID;
  Int2              itemIDs [OBJ_MAX];
  Boolean           assignIDs;
  GatherObjectProc  callback;
  Pointer           userdata;
  BoolPtr           objMgrFilter;
} InternalACC, PNTR InternalACCPtr;

static void AssignIDs (InternalACCPtr iap, GatherIndexPtr gip, Uint1 itemtype, Uint1 subtype, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  if (iap == NULL || gip == NULL) return;

  if (iap->assignIDs) {
    gip->entityID = iap->entityID;
    gip->itemID = iap->itemIDs [itemtype];
    gip->itemtype = itemtype;
    gip->subtype = subtype;
    /* gip->deleteme = 0; */
    gip->parenttype = parenttype;
    gip->parentptr = parent;
    gip->prevlink = prevlink;
  }
}

static Boolean VisitCallback (InternalACCPtr iap, Pointer dataptr, Uint1 itemtype, Uint1 subtype, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  GatherObject  go;

  if (dataptr == NULL || iap == NULL || itemtype >= OBJ_MAX) return TRUE;

  if (iap->callback != NULL) {
    if (iap->objMgrFilter == NULL || iap->objMgrFilter [itemtype]) {
      go.entityID = iap->entityID;
      go.itemID = iap->itemIDs [itemtype];
      go.itemtype = itemtype;
      go.subtype = subtype;
      go.parenttype = parenttype;
      go.dataptr = dataptr;
      go.parentptr = parent;
      go.prevlink = prevlink;
      go.userdata = iap->userdata;
      if (! iap->callback (&go)) return FALSE;
    }
  }

  return TRUE;
}

static Boolean VisitSeqEntry (InternalACCPtr iap, SeqEntryPtr sep, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink);

static Boolean VisitPub (InternalACCPtr iap, ValNodePtr pub, Uint1 itemtype, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  if (iap == NULL || pub == NULL) return TRUE;
  (iap->itemIDs [itemtype])++;

  if (iap->callback != NULL) {
    if (! VisitCallback (iap, (Pointer) pub, itemtype, 0, parent, parenttype, prevlink)) return FALSE;
  }

  return TRUE;
}

static Boolean VisitPubSet (InternalACCPtr iap, ValNodePtr vnp, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  Uint1       itemtype = OBJ_PUB_SET;
  ValNodePtr  pub;

  if (iap == NULL || vnp == NULL) return TRUE;
  (iap->itemIDs [itemtype])++;

  if (iap->callback != NULL) {
    if (! VisitCallback (iap, (Pointer) vnp, itemtype, 0, parent, parenttype, prevlink)) return FALSE;
  }

  prevlink = (Pointer PNTR) &(vnp->data.ptrvalue);
  for (pub = (ValNodePtr) vnp->data.ptrvalue; pub != NULL; pub = pub->next) {
    if (! VisitPub (iap, pub, OBJ_SEQFEAT_CIT, (Pointer) vnp, itemtype, prevlink)) return FALSE;
    prevlink = (Pointer PNTR) &(pub->next);
  }

  return TRUE;
}

static Boolean VisitSeqFeat (InternalACCPtr iap, SeqFeatPtr sfp, Uint1 itemtype, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  if (iap == NULL || sfp == NULL) return TRUE;

  if ((! iap->assignIDs) && iap->callback != NULL) {
    if (iap->objMgrFilter != NULL && (! iap->objMgrFilter [itemtype])) {
      return TRUE;
    }
  }

  while (sfp != NULL) {
    (iap->itemIDs [itemtype])++;

    if (iap->assignIDs) {
      AssignIDs (iap, &(sfp->idx), itemtype, FindFeatDefType (sfp), parent, parenttype, prevlink);
    }

    if (iap->callback != NULL) {
      if (! VisitCallback (iap, (Pointer) sfp, itemtype, sfp->idx.subtype, parent, parenttype, prevlink)) return FALSE;
    }

    if (sfp->cit != NULL) {
      if (! VisitPubSet (iap, sfp->cit, (Pointer) sfp, itemtype, (Pointer PNTR) &(sfp->cit))) return FALSE;
    }

    prevlink = (Pointer PNTR) &(sfp->next);
    sfp = sfp->next;
  }

  return TRUE;
}

static Uint2 nextAlignID = 0;

static Boolean VisitSeqAlign (InternalACCPtr iap, SeqAlignPtr sap, Uint1 itemtype, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  if (iap == NULL || sap == NULL) return TRUE;

  if ((! iap->assignIDs) && iap->callback != NULL) {
    if (iap->objMgrFilter != NULL && (! iap->objMgrFilter [itemtype])) {
      return TRUE;
    }
  }

  while (sap != NULL) {
    (iap->itemIDs [itemtype])++;

    if (iap->assignIDs) {
      AssignIDs (iap, &(sap->idx), itemtype, sap->type, parent, parenttype, prevlink);
      if (sap->alignID == 0) {
        nextAlignID++;
        sap->alignID = nextAlignID;
      }
    }

    if (iap->callback != NULL) {
      if (! VisitCallback (iap, (Pointer) sap, itemtype, sap->idx.subtype, parent, parenttype, prevlink)) return FALSE;
    }

    if (sap->segtype == SAS_DISC) {
      if (! VisitSeqAlign (iap, (SeqAlignPtr) sap->segs, OBJ_SEQALIGN, (Pointer) sap, itemtype, (Pointer PNTR) &(sap->segs))) return FALSE;
    }

    prevlink = (Pointer PNTR) &(sap->next);
    sap = sap->next;
  }

  return TRUE;
}

static Boolean VisitSeqGraph (InternalACCPtr iap, SeqGraphPtr sgp, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  Uint1  itemtype = OBJ_SEQGRAPH;

  if (iap == NULL || sgp == NULL) return TRUE;

  if ((! iap->assignIDs) && iap->callback != NULL) {
    if (iap->objMgrFilter != NULL && (! iap->objMgrFilter [itemtype])) {
      return TRUE;
    }
  }

  while (sgp != NULL) {
    (iap->itemIDs [itemtype])++;

    if (iap->assignIDs) {
      AssignIDs (iap, &(sgp->idx), itemtype, 0, parent, parenttype, prevlink);
    }

    if (iap->callback != NULL) {
      if (! VisitCallback (iap, (Pointer) sgp, itemtype, sgp->idx.subtype, parent, parenttype, prevlink)) return FALSE;
    }

    prevlink = (Pointer PNTR) &(sgp->next);
    sgp = sgp->next;
  }

  return TRUE;
}

static Boolean VisitSeqAnnot (InternalACCPtr iap, SeqAnnotPtr sap, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  Uint1  itemtype = OBJ_SEQANNOT;

  if (iap == NULL || sap == NULL) return TRUE;

  while (sap != NULL) {
    (iap->itemIDs [itemtype])++;

    if (iap->assignIDs) {
      AssignIDs (iap, &(sap->idx), itemtype, sap->type, parent, parenttype, prevlink);
    }

    if (iap->callback != NULL) {
      if (! VisitCallback (iap, (Pointer) sap, itemtype, sap->idx.subtype, parent, parenttype, prevlink)) return FALSE;
    }

    switch (sap->type) {
      case 1 : /* feature table */
        if (! VisitSeqFeat (iap, (SeqFeatPtr) sap->data, OBJ_SEQFEAT, (Pointer) sap, itemtype, (Pointer PNTR) &(sap->data))) return FALSE;
        break;
      case 2 : /* alignments */
        if (! VisitSeqAlign (iap, (SeqAlignPtr) sap->data, OBJ_SEQALIGN, (Pointer) sap, itemtype, (Pointer PNTR) &(sap->data))) return FALSE;
        break;
      case 3 : /* graphs */
        if (! VisitSeqGraph (iap, (SeqGraphPtr) sap->data, (Pointer) sap, itemtype, (Pointer PNTR) &(sap->data))) return FALSE;
        break;
      default :
        break;
    }

    prevlink = (Pointer PNTR) &(sap->next);
    sap = sap->next;
  }

  return TRUE;
}

static Boolean VisitSeqDescr (InternalACCPtr iap, SeqDescrPtr sdp, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  Uint1          itemtype = OBJ_SEQDESC;
  ObjValNodePtr  ovp;

  if (iap == NULL || sdp == NULL) return TRUE;

  if ((! iap->assignIDs) && iap->callback != NULL) {
    if (iap->objMgrFilter != NULL && (! iap->objMgrFilter [itemtype])) {
      return TRUE;
    }
  }

  while (sdp != NULL) {
    (iap->itemIDs [itemtype])++;

    if (iap->assignIDs) {
      if (sdp->extended != 0) {
        ovp = (ObjValNodePtr) sdp;
        AssignIDs (iap, &(ovp->idx), itemtype, sdp->choice, parent, parenttype, prevlink);
      } else {
        ErrPostEx (SEV_ERROR, 0, 0, "Descriptor item %d is not an ObjValNode",
                   (int) iap->itemIDs [itemtype]);
      }
    }

    if (iap->callback != NULL) {
      if (sdp->extended != 0) {
        ovp = (ObjValNodePtr) sdp;
        if (! VisitCallback (iap, (Pointer) sdp, itemtype, ovp->idx.subtype, parent, parenttype, prevlink)) return FALSE;
      }
    }

    prevlink = (Pointer PNTR) &(sdp->next);
    sdp = sdp->next;
  }

  return TRUE;
}

static Boolean VisitSeqHist (InternalACCPtr iap, SeqHistPtr shp, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  Uint1  itemtype = OBJ_SEQHIST;

  if (iap == NULL || shp == NULL) return TRUE;
  (iap->itemIDs [itemtype])++;

  if (iap->callback != NULL) {
    if (! VisitCallback (iap, (Pointer) shp, itemtype, 0, parent, parenttype, prevlink)) return FALSE;
  }

  VisitSeqAlign (iap, shp->assembly, OBJ_SEQHIST_ALIGN, (Pointer) shp, itemtype, (Pointer PNTR) &(shp->assembly));

  return TRUE;
}

static Boolean VisitSeqIds (InternalACCPtr iap, SeqIdPtr sip, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  Uint1  itemtype = OBJ_SEQID;

  if (iap == NULL || sip == NULL) return TRUE;

  while (sip != NULL) {
    (iap->itemIDs [itemtype])++;

    if (iap->callback != NULL) {
      if (! VisitCallback (iap, (Pointer) sip, itemtype, sip->choice, parent, parenttype, prevlink)) return FALSE;
    }

    prevlink = (Pointer PNTR) &(sip->next);
    sip = sip->next;
  }

  return TRUE;
}

static Boolean VisitDelta (InternalACCPtr iap, DeltaSeqPtr dsp, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  Uint1  itemtype = OBJ_BIOSEQ_DELTA;

  if (iap == NULL || dsp == NULL) return TRUE;

  while (dsp != NULL) {
    (iap->itemIDs [itemtype])++;

    if (iap->callback != NULL) {
      if (! VisitCallback (iap, (Pointer) dsp, itemtype, dsp->choice, parent, parenttype, prevlink)) return FALSE;
    }

    prevlink = (Pointer PNTR) &(dsp->next);
    dsp = dsp->next;
  }

  return TRUE;
}

static Boolean VisitSegment (InternalACCPtr iap, SeqLocPtr head, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  Uint1      itemtype = OBJ_BIOSEQ_SEG;
  SeqLocPtr  slp;

  if (iap == NULL || head == NULL) return TRUE;

  slp = NULL;
  while ((slp = SeqLocFindNext (head, slp)) != NULL) {
    (iap->itemIDs [itemtype])++;

    if (iap->callback != NULL) {
      if (! VisitCallback (iap, (Pointer) slp, itemtype, slp->choice, parent, parenttype, prevlink)) return FALSE;
    }
    prevlink = (Pointer PNTR) &(slp->next);
  }

  return TRUE;
}

static Boolean VisitBioseq (InternalACCPtr iap, BioseqPtr bsp, SeqEntryPtr curr, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  SeqLocPtr  head;
  Uint1      itemtype = OBJ_BIOSEQ;
  ValNode    vn;

  if (iap == NULL || bsp == NULL) return TRUE;
  (iap->itemIDs [itemtype])++;

  if (iap->assignIDs) {
    AssignIDs (iap, &(bsp->idx), itemtype, bsp->repr, parent, parenttype, prevlink);
    bsp->seqentry = curr;
  }

  if (iap->callback != NULL) {
    if (! VisitCallback (iap, (Pointer) bsp, itemtype, bsp->idx.subtype, parent, parenttype, prevlink)) return FALSE;
  }

  switch (bsp->repr) {
    case Seq_repr_map :
      if (iap->objMgrFilter == NULL || iap->objMgrFilter [OBJ_BIOSEQ_MAPFEAT]) {
        if (! VisitSeqFeat (iap, (SeqFeatPtr) bsp->seq_ext, OBJ_BIOSEQ_MAPFEAT, (Pointer) bsp, itemtype, (Pointer PNTR) &(bsp->seq_ext))) return FALSE;
      }
      break;
    case Seq_repr_seg :
      if (iap->objMgrFilter == NULL || iap->objMgrFilter [OBJ_BIOSEQ_SEG]) {
        vn.choice = SEQLOC_MIX;
        vn.extended = 0;
        vn.data.ptrvalue = bsp->seq_ext;
        vn.next = NULL;
        head = &vn;
        if (! VisitSegment (iap, head, (Pointer) bsp, itemtype, (Pointer PNTR) &(bsp->seq_ext))) return FALSE;
      }
      break;
    case Seq_repr_ref :
      if (iap->objMgrFilter == NULL || iap->objMgrFilter [OBJ_BIOSEQ_SEG]) {
        head = (SeqLocPtr) bsp->seq_ext;
        if (! VisitSegment (iap, head, (Pointer) bsp, itemtype, (Pointer PNTR) &(bsp->seq_ext))) return FALSE;
      }
      break;
    case Seq_repr_delta :
      if (iap->objMgrFilter == NULL || iap->objMgrFilter [OBJ_BIOSEQ_DELTA]) {
        if (! VisitDelta (iap, (DeltaSeqPtr) bsp->seq_ext, (Pointer) bsp, itemtype, (Pointer PNTR) &(bsp->seq_ext))) return FALSE;
      }
      break;
    default :
      break;
  }

  if (! VisitSeqHist (iap, bsp->hist, (Pointer) bsp, itemtype, (Pointer PNTR) &(bsp->hist))) return FALSE;

  if (! VisitSeqDescr (iap, bsp->descr, (Pointer) bsp, itemtype, (Pointer PNTR) &(bsp->descr))) return FALSE;

  if (! VisitSeqAnnot (iap, bsp->annot, (Pointer) bsp, itemtype, (Pointer PNTR) &(bsp->annot))) return FALSE;

  return TRUE;
}

static Boolean VisitBioseqSet (InternalACCPtr iap, BioseqSetPtr bssp, SeqEntryPtr curr, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  Uint1        itemtype = OBJ_BIOSEQSET;
  SeqEntryPtr  sep;

  if (iap == NULL || bssp == NULL) return TRUE;
  (iap->itemIDs [itemtype])++;

  if (iap->assignIDs) {
    AssignIDs (iap, &(bssp->idx), itemtype, bssp->_class, parent, parenttype, prevlink);
    bssp->seqentry = curr;
  }

  if (iap->callback != NULL) {
    if (! VisitCallback (iap, (Pointer) bssp, itemtype, bssp->idx.subtype, parent, parenttype, prevlink)) return FALSE;
  }

  if (! VisitSeqDescr (iap, bssp->descr, (Pointer) bssp, itemtype, (Pointer PNTR) &(bssp->descr))) return FALSE;

  if (! VisitSeqAnnot (iap, bssp->annot, (Pointer) bssp, itemtype, (Pointer PNTR) &(bssp->annot))) return FALSE;

  prevlink = (Pointer PNTR) &(bssp->seq_set);
  for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
    if (! VisitSeqEntry (iap, sep, (Pointer) bssp, itemtype, prevlink)) return FALSE;
    prevlink = (Pointer PNTR) &(sep->next);
  }

  return TRUE;
}

static Boolean VisitSeqEntry (InternalACCPtr iap, SeqEntryPtr sep, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  if (iap == NULL || sep == NULL) return TRUE;

  if (IS_Bioseq (sep)) {
    if (! VisitBioseq (iap, (BioseqPtr) sep->data.ptrvalue, sep, parent, parenttype, prevlink)) return FALSE;
  } else if (IS_Bioseq_set (sep)) {
    if (! VisitBioseqSet (iap, (BioseqSetPtr) sep->data.ptrvalue, sep, parent, parenttype, prevlink)) return FALSE;
  }

  return TRUE;
}

static Boolean VisitSeqSubCit (InternalACCPtr iap, CitSubPtr csp, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  Uint1  itemtype = OBJ_SEQSUB_CIT;

  if (iap == NULL || csp == NULL) return TRUE;
  (iap->itemIDs [itemtype])++;

  if (iap->callback != NULL) {
    if (! VisitCallback (iap, (Pointer) csp, itemtype, 0, parent, parenttype, prevlink)) return FALSE;
  }

  return TRUE;
}

static Boolean VisitSeqSubContact (InternalACCPtr iap, ContactInfoPtr cip, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  Uint1  itemtype = OBJ_SEQSUB_CONTACT;


  if (iap == NULL || cip == NULL) return TRUE;
  (iap->itemIDs [itemtype])++;

  if (iap->callback != NULL) {
    if (! VisitCallback (iap, (Pointer) cip, itemtype, 0, parent, parenttype, prevlink)) return FALSE;
  }

  return TRUE;
}

static Boolean VisitSubBlock (InternalACCPtr iap, SubmitBlockPtr sbp, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  Uint1  itemtype = OBJ_SUBMIT_BLOCK;

  if (iap == NULL || sbp == NULL) return TRUE;
  (iap->itemIDs [itemtype])++;

  if (iap->callback != NULL) {
    if (! VisitCallback (iap, (Pointer) sbp, itemtype, 0, parent, parenttype, prevlink)) return FALSE;
  }

  if (! VisitSeqSubContact (iap, sbp->contact, (Pointer) sbp, itemtype, (Pointer PNTR) &(sbp->contact))) return FALSE;

  if (! VisitSeqSubCit (iap, sbp->cit, (Pointer) sbp, itemtype, (Pointer PNTR) &(sbp->cit))) return FALSE;

  return TRUE;
}

static Boolean VisitSeqSubmit (InternalACCPtr iap, SeqSubmitPtr ssp)

{
  Uint1         itemtype = OBJ_SEQSUB;
  Pointer PNTR  prevlink;
  SeqEntryPtr   sep;

  if (iap == NULL || ssp == NULL) return TRUE;
  (iap->itemIDs [itemtype])++;

  if (iap->assignIDs) {
    AssignIDs (iap, &(ssp->idx), itemtype, 0, NULL, 0, NULL);
  }

  if (iap->callback != NULL) {
    if (! VisitCallback (iap, (Pointer) ssp, itemtype, 0, NULL, 0, NULL)) return FALSE;
  }

  if (! VisitSubBlock (iap, ssp->sub, (Pointer) ssp, itemtype, (Pointer PNTR) &(ssp->sub))) return FALSE;

  prevlink = (Pointer PNTR) &(ssp->data);
  switch (ssp->datatype) {
    case 1 : /* Seq-entrys */
      for (sep = (SeqEntryPtr) ssp->data; sep != NULL; sep = sep->next) {
        if (! VisitSeqEntry (iap, sep, (Pointer) ssp, itemtype, prevlink)) return FALSE;
        prevlink = (Pointer PNTR) &(sep->next);
      }
      break;
    case 2 : /* Seq-annots */
      if (! VisitSeqAnnot (iap, (SeqAnnotPtr) ssp->data, (Pointer) ssp, itemtype, prevlink)) return FALSE;
      break;
    case 3 : /* SeqIds */
      if (! VisitSeqIds (iap, (SeqIdPtr) ssp->data, (Pointer) ssp, itemtype, prevlink)) return FALSE;
      break;
    default :
      break;
  }

  return TRUE;
}

/*****************************************************************************
*
*   AssignIDsInEntity (entityID, datatype, dataptr)
*   	Assigns entityID/itemID/itemtype, parent pointer, and prevlink to several
*       data objects.  If entityID is > 0 it looks up the registered datatype and
*       dataptr from the object manager.  Otherwise it uses the remaining parameters,
*       assigning entityID 0 to the unregistered components.
*
*   GatherObjectsInEntity (entityID, datatype, dataptr, callback, userdata, objMgrFilter)
*   	Calls callback for objects within entity.  If the objMgrFilter parameter is NULL,
*       every object type is visited, otherwise the array length should be OBJ_MAX, and
*       the elements are from the OBJ_ list.
*
*****************************************************************************/

static Boolean VisitEntity (Uint2 entityID, Uint2 datatype, Pointer dataptr,
                            Boolean assignIDs, GatherObjectProc callback,
                            Pointer userdata, BoolPtr objMgrFilter)

{
  InternalACC    iac;
  ObjMgrDataPtr  omdp;
  ObjMgrPtr      omp;

  MemSet ((Pointer) &iac, 0, sizeof (InternalACC));
  iac.entityID = entityID;
  iac.assignIDs = assignIDs;
  iac.callback = callback;
  iac.userdata = userdata;
  iac.objMgrFilter = objMgrFilter;

  if (entityID > 0) {
    omp = ObjMgrReadLock ();
    omdp = ObjMgrGetDataStruct (omp, entityID);
    ObjMgrUnlock();
    if (omdp == NULL) return FALSE;
    if (omdp->choicetype == OBJ_SEQENTRY) {
      datatype = omdp->choicetype;
      dataptr = omdp->choice;
    } else {
      datatype = omdp->datatype;
      dataptr = omdp->dataptr;
    }
  }

  if (datatype == 0 || dataptr == NULL) return FALSE;

  switch (datatype) {
    case OBJ_SEQENTRY :
      VisitSeqEntry (&iac, (SeqEntryPtr) dataptr, NULL, 0, NULL);
      break;
    case OBJ_BIOSEQ :
      VisitBioseq (&iac, (BioseqPtr) dataptr, NULL, NULL, 0, NULL);
      break;
    case OBJ_BIOSEQSET :
      VisitBioseqSet (&iac, (BioseqSetPtr) dataptr, NULL, NULL, 0, NULL);
      break;
    case OBJ_SEQDESC :
      VisitSeqDescr (&iac, (SeqDescrPtr) dataptr, NULL, 0, NULL);
      break;
    case OBJ_SEQANNOT :
      VisitSeqAnnot (&iac, (SeqAnnotPtr) dataptr, NULL, 0, NULL);
      break;
    case OBJ_SEQFEAT :
      VisitSeqFeat (&iac, (SeqFeatPtr) dataptr, OBJ_SEQFEAT, NULL, 0, NULL);
      break;
    case OBJ_SEQALIGN :
      VisitSeqAlign (&iac, (SeqAlignPtr) dataptr, OBJ_SEQALIGN, NULL, 0, NULL);
      break;
    case OBJ_SEQGRAPH :
      VisitSeqGraph (&iac, (SeqGraphPtr) dataptr, NULL, 0, NULL);
      break;
    case OBJ_SEQSUB :
      VisitSeqSubmit (&iac, (SeqSubmitPtr) dataptr);
      break;
    case OBJ_SUBMIT_BLOCK :
      VisitSubBlock (&iac, (SubmitBlockPtr) dataptr, NULL, 0, NULL);
      break;
    case OBJ_SEQSUB_CONTACT :
      VisitSeqSubContact (&iac, (ContactInfoPtr) dataptr, NULL, 0, NULL);
      break;
    case OBJ_SEQHIST :
      VisitSeqHist (&iac, (SeqHistPtr) dataptr, NULL, 0, NULL);
      break;
    case OBJ_SEQHIST_ALIGN :
      VisitSeqAlign (&iac, (SeqAlignPtr) dataptr, OBJ_SEQHIST_ALIGN, NULL, 0, NULL);
      break;
    case OBJ_PUB :
      VisitPub (&iac, (ValNodePtr) dataptr, OBJ_PUB, NULL, 0, NULL);
      break;
    case OBJ_SEQSUB_CIT :
      VisitSeqSubCit (&iac, (CitSubPtr) dataptr, NULL, 0, NULL);
      break;
    case OBJ_SEQID :
      VisitSeqIds (&iac, (SeqIdPtr) dataptr, NULL, 0, NULL);
      break;
    default :
      return FALSE;
  }

  return TRUE;
}

NLM_EXTERN Boolean LIBCALL AssignIDsInEntity (Uint2 entityID, Uint2 datatype, Pointer dataptr)

{
  return VisitEntity (entityID, datatype, dataptr, TRUE, NULL, NULL, NULL);
}

NLM_EXTERN Boolean LIBCALL GatherObjectsInEntity (Uint2 entityID, Uint2 datatype, Pointer dataptr,
                                                  GatherObjectProc callback, Pointer userdata, BoolPtr objMgrFilter)

{
  if (callback == NULL) return FALSE;
  return VisitEntity (entityID, datatype, dataptr, FALSE, callback, userdata, objMgrFilter);
}

/*****************************************************************************
*
*   GetNextDescriptorUnindexed (bsp, choice, curr)
*   	After AssignIDsInEntity, gets next descriptor up the set hierarchy.
*
*****************************************************************************/

NLM_EXTERN SeqDescrPtr GetNextDescriptorUnindexed (
  BioseqPtr bsp,
  Uint1 choice,
  SeqDescrPtr curr
)

{
  BioseqSetPtr   bssp = NULL;
  ObjValNodePtr  ovp;
  SeqDescrPtr    sdp;

  if (bsp == NULL || choice == 0) return NULL;

  if (curr == NULL) {
    sdp = bsp->descr;
    curr = sdp;
  } else {
    sdp = curr->next;
  }
  while (sdp != NULL) {
    if (sdp->choice == choice) return sdp;
    sdp = sdp->next;
  }

  if (curr == NULL || curr->extended == 0) return NULL;
  ovp = (ObjValNodePtr) curr;
  if (ovp->idx.parenttype == OBJ_BIOSEQ) {
    bsp = (BioseqPtr) ovp->idx.parentptr;
    if (bsp == NULL) return NULL;
    if (bsp->idx.parenttype != OBJ_BIOSEQSET) return NULL;
    bssp = (BioseqSetPtr) ovp->idx.parentptr;
  } else if (ovp->idx.parenttype == OBJ_BIOSEQSET) {
    bssp = (BioseqSetPtr) ovp->idx.parentptr;
    if (bssp == NULL) return NULL;
    if (bssp->idx.parenttype != OBJ_BIOSEQSET) return NULL;
    bssp = (BioseqSetPtr) ovp->idx.parentptr;
  } else return NULL;

  while (bssp != NULL) {
    for (sdp = bssp->descr; sdp != NULL; sdp = sdp->next) {
      if (sdp->choice == choice) return sdp;
     }
     if (bssp->idx.parenttype != OBJ_BIOSEQSET) return NULL;
     bssp = (BioseqSetPtr) bsp->idx.parentptr;
  }
  return NULL;
}

typedef struct getptrforid {
  Uint2    entityID;
  Uint2    itemID;
  Uint2    itemtype;
  Pointer  dataptr;
} GetPtrForId, PNTR GetPtrForIdPtr;

static Boolean GetPointerProc (GatherObjectPtr gop)

{
  GetPtrForIdPtr  gfp;

  if (gop == NULL) return TRUE;
  gfp = (GetPtrForIdPtr) gop->userdata;
  if (gfp == NULL) return TRUE;
  if (gfp->itemID != gop->itemID || gfp->itemtype != gop->itemtype) return TRUE;
  gfp->dataptr = gop->dataptr;
  return TRUE;
}

NLM_EXTERN Pointer LIBCALL GetPointerForIDs (Uint2 entityID, Uint2 itemID, Uint2 itemtype)

{
  GetPtrForId  gfi;
  Boolean      objMgrFilter [OBJ_MAX];

  if (itemtype >= OBJ_MAX) return NULL;

  MemSet ((Pointer) objMgrFilter, FALSE, sizeof (objMgrFilter));
  objMgrFilter [itemtype] = TRUE;
  gfi.entityID = entityID;
  gfi.itemID = itemID;
  gfi.itemtype = itemtype;
  gfi.dataptr = NULL;

  GatherObjectsInEntity (entityID, 0, NULL, GetPointerProc, &gfi, objMgrFilter);

  return gfi.dataptr;
}

/*****************************************************************************
*
*   DeleteMarkedObjects (entityID, datatype, dataptr)
*   	Unlinks and removes all objects whose GatherIndex.deleteme flag is not 0.
*
*****************************************************************************/

static void DeleteMarkedSeqFeat (SeqFeatPtr sfp, Pointer PNTR prevlink)

{
  SeqFeatPtr  next;

  while (sfp != NULL) {
    next = sfp->next;

    if (sfp->idx.deleteme != 0) {
      *prevlink = sfp->next;
      sfp->next = NULL;
      SeqFeatFree (sfp);
    } else {
      sfp->idx.prevlink = prevlink;
      prevlink = (Pointer PNTR) &(sfp->next);
    }

    sfp = next;
  }
}

static void DeleteMarkedSeqAlign (SeqAlignPtr sap, Pointer PNTR prevlink)

{
  SeqAlignPtr  next;

  while (sap != NULL) {
    next = sap->next;

    if (sap->idx.deleteme != 0) {
      *prevlink = sap->next;
      sap->next = NULL;
      SeqAlignFree (sap);
    } else {
      sap->idx.prevlink = prevlink;
      prevlink = (Pointer PNTR) &(sap->next);
    }

    sap = next;
  }
}

static void DeleteMarkedSeqGraph (SeqGraphPtr sgp, Pointer PNTR prevlink)

{
  SeqGraphPtr  next;

  while (sgp != NULL) {
    next = sgp->next;

    if (sgp->idx.deleteme != 0) {
      *prevlink = sgp->next;
      sgp->next = NULL;
      SeqGraphFree (sgp);
    } else {
      sgp->idx.prevlink = prevlink;
      prevlink = (Pointer PNTR) &(sgp->next);
    }

    sgp = next;
  }
}

static void DeleteMarkedSeqAnnot (SeqAnnotPtr sap, Pointer PNTR prevlink)

{
  SeqAnnotPtr  next;

  while (sap != NULL) {
    next = sap->next;

    if (sap->idx.deleteme == 0) {
      switch (sap->type) {
        case 1 :
          DeleteMarkedSeqFeat ((SeqFeatPtr) sap->data, (Pointer PNTR) &(sap->data));
          break;
        case 2 :
          DeleteMarkedSeqAlign ((SeqAlignPtr) sap->data, (Pointer PNTR) &(sap->data));
          break;
        case 3 :
          DeleteMarkedSeqGraph ((SeqGraphPtr) sap->data, (Pointer PNTR) &(sap->data));
          break;
        default :
          break;
      }
      if (sap->data == NULL) {
        sap->idx.deleteme = 1;
      }
    }

    if (sap->idx.deleteme != 0) {
      *prevlink = sap->next;
      sap->next = NULL;
      SeqAnnotFree (sap);
    } else {
      sap->idx.prevlink = prevlink;
      prevlink = (Pointer PNTR) &(sap->next);
    }
  
    sap = next;
  }
}

static void DeleteMarkedSeqDescr (SeqDescrPtr sdp, Pointer PNTR prevlink)

{
  SeqDescrPtr    next;
  ObjValNodePtr  ovp;

  while (sdp != NULL) {
    next = sdp->next;

    ovp = (ObjValNodePtr) sdp;
    if (sdp->extended != 0 && ovp->idx.deleteme != 0) {
      *prevlink = sdp->next;
      sdp->next = NULL;
      SeqDescFree (sdp);
    } else {
      if (sdp->extended != 0) {
        ovp->idx.prevlink = prevlink;
      }
      prevlink = (Pointer PNTR) &(sdp->next);
    }

    sdp = next;
  }
}

static void DeleteMarkedSeqEntry (SeqEntryPtr sep, Pointer PNTR prevlink)

{
  BioseqPtr     bsp;
  BioseqSetPtr  bssp;
  SeqEntryPtr   next;
  Boolean       unlink;

  while (sep != NULL) {
    next = sep->next;
    unlink = FALSE;
    bsp = NULL;
    bssp = NULL;

    if (IS_Bioseq (sep)) {

      bsp = (BioseqPtr) sep->data.ptrvalue;
      if (bsp != NULL) {
        if (bsp->idx.deleteme != 0) {
          unlink = TRUE;
        } else {
          DeleteMarkedSeqDescr (bsp->descr, (Pointer PNTR) &(bsp->descr));
          DeleteMarkedSeqAnnot (bsp->annot, (Pointer PNTR) &(bsp->annot));
        }
      }

    } else if (IS_Bioseq_set (sep)) {

      bssp = (BioseqSetPtr) sep->data.ptrvalue;
      if (bssp != NULL) {
        if (bssp->idx.deleteme != 0) {
          unlink = TRUE;
        } else {
          DeleteMarkedSeqDescr (bssp->descr, (Pointer PNTR) &(bssp->descr));
          DeleteMarkedSeqAnnot (bssp->annot, (Pointer PNTR) &(bssp->annot));
          DeleteMarkedSeqEntry (bssp->seq_set, (Pointer PNTR) &(bssp->seq_set));
        }
      }
    }
    if (unlink) {
      *prevlink = sep->next;
      sep->next = NULL;
      SeqEntryFree (sep);
    } else {
      if (bsp != NULL) {
        bsp->idx.prevlink = prevlink;
      } else if (bssp != NULL) {
        bssp->idx.prevlink = prevlink;
      }
      prevlink = (Pointer PNTR) &(sep->next);
    }
    sep = next;
  }
}

NLM_EXTERN Boolean DeleteMarkedObjects (Uint2 entityID, Uint2 datatype, Pointer dataptr)

{
  BioseqPtr      bsp;
  BioseqSetPtr   bssp;
  ObjMgrDataPtr  omdp;
  ObjMgrPtr      omp;
  SeqEntryPtr    sep = NULL;
  SeqSubmitPtr   ssp;

  if (entityID > 0) {
    omp = ObjMgrReadLock ();
    omdp = ObjMgrGetDataStruct (omp, entityID);
    ObjMgrUnlock();
    if (omdp == NULL) return FALSE;
    if (omdp->choicetype == OBJ_SEQENTRY) {
      datatype = omdp->choicetype;
      dataptr = omdp->choice;
    } else {
      datatype = omdp->datatype;
      dataptr = omdp->dataptr;
    }
  }

  if (datatype == 0 || dataptr == NULL) return FALSE;

  switch (datatype) {
    case OBJ_SEQENTRY :
      sep = (SeqEntryPtr) dataptr;
      break;
    case OBJ_BIOSEQ :
      bsp = (BioseqPtr) dataptr;
      sep = bsp->seqentry;
      break;
    case OBJ_BIOSEQSET :
      bssp = (BioseqSetPtr) dataptr;
      sep = bssp->seqentry;
      break;
    case OBJ_SEQSUB :
      ssp = (SeqSubmitPtr) dataptr;
      if (ssp->datatype == 1) {
        sep = (SeqEntryPtr) ssp->data;
      }
      break;
    default :
      return FALSE;
  }

  if (sep == NULL) return FALSE;

  DeleteMarkedSeqEntry (sep, (Pointer PNTR) &sep);

  return TRUE;
}

