/*
* ===========================================================================
*
*                            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.62 $
*
* File Description: 
*
* Modifications:  
* --------------------------------------------------------------------------
* Date     Name        Description of modification
* -------  ----------  -----------------------------------------------------
*
* ==========================================================================
*/

#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, Uint4 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 = FALSE, rtrunc = FALSE;
  SeqLocPtr tslp;

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

  if( sfp_loc->choice == SEQLOC_NULL || 
      sfp_loc->choice == SEQLOC_EMPTY ) 
  {
    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, tmp, slp, prev, next, thead;
    SeqIntPtr sip, sip2;
    SeqPntPtr spp, spp2;
    PackSeqPntPtr pspp, pspp2;
    SeqBondPtr sbp, sbp2;
    Int4 numpnt, i, tpos, intcnt, othercnt;
    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;
    Uint4 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;
    Uint4 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 = FALSE;
    Uint4 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;
    Uint4 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;
}

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 = SeqMgrGetOmdpForBioseq (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 = NULL, trdp, lrdp;
    Int4 offset = 0, totlen, left_end;
    Boolean rev, revs[2];
    Int2 ctr, max_interval, i, numcheck, j;
    GatherRange trange;
    Uint4 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 != NULL) {
                          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(sint != NULL && 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 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 = 0, 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 = 0;    /*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 = FALSE;
    Int4 leftover;
    Int4 left, right;
    Boolean use_stop;
    Uint1 ma_strand;
    SeqAlignPtr sap;

    strand = 0;
    MemSet ((Pointer) &gr, 0, sizeof (GatherRange));
    MemSet ((Pointer) &t_range, 0, sizeof (GatherRange));
    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;
    Uint4 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;
    Uint4 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 GatherAnnotDesc(InternalGCCPtr gccp, AnnotDescPtr desc,
    Uint1 ttype, Pointer tparent, Pointer PNTR prevlink, Boolean in_scope)
{
    GatherContextPtr gcp;
    GatherScopePtr gsp;
    Uint4 LocateItem = 0;
    Pointer LocateData = NULL;
    Uint1 thistype;

    if (desc == NULL) return TRUE;

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

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

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

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

    while (desc != NULL)
    {
        gccp->itemIDs[OBJ_ANNOTDESC]++;
        if (LocateItem == gccp->itemIDs[OBJ_ANNOTDESC])
            in_scope = TRUE;
        if (LocateData == (Pointer)desc)
            in_scope = TRUE;
        if (in_scope)
        {
            gcp->itemID = gccp->itemIDs[OBJ_ANNOTDESC];
            gcp->thisitem = (Pointer)desc;
            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)desc;
        prevlink = (Pointer PNTR)&(desc->next);
        desc = desc->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;
    Uint4 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++;
        if (! GatherAnnotDesc(gccp, (AnnotDescPtr)(sap->desc), thistype, (Pointer)sap, (Pointer PNTR) &(sap->desc), in_scope))
            return FALSE;
        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;
    Uint4 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;
    Uint4 LocateItem = 0;
    Int2 segctr, first_seg, last_seg;
    Pointer LocateData = NULL;
    ValNode vn;
    SeqLocPtr head, slp, 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 = NULL;
    Pointer dataptr = NULL;  /* 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 */
                {
                    if (dsp != NULL) {
                      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;
    Uint4 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;
    Uint4 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;
    Uint4 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;
    Uint4 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;
    Uint4 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)
{
    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 if (scope != NULL) {
                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:
                    GatherAnnotDesc(gccp, (AnnotDescPtr)ptr, 0,NULL,NULL, in_scope);
                    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;
    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)
{
    Uint4Ptr ptr;

    ptr = (Uint4Ptr)(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 Uint4 LIBCALL GatherItemIDByData (Uint2 entityID, Uint2 itemtype, Pointer dataptr)
{
    Uint4 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, Uint4 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, Uint4 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;
            break;
        case OBJ_ANNOTDESC:
            gs.ignore[OBJ_SEQANNOT] = FALSE;
            break;
        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_ANNOTDESC:
            next = (Pointer)(((AnnotDescPtr)(ptr))->next);
            (((AnnotDescPtr)(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 Boolean AddAnnotDesc (SeqAnnotPtr sap, Pointer addptr)
{
    AnnotDescPtr adp;
    Pointer PNTR prevlink = NULL;

    if (sap == NULL) return FALSE;

    if (sap->desc == NULL) {
        prevlink = (Pointer PNTR) &(sap->desc);
    } else {
        for (adp = (AnnotDescPtr) sap->desc; adp->next != NULL; adp = adp->next)
            continue;
        prevlink = (Pointer PNTR) &(adp->next);
    }
    if (prevlink != NULL)
        *prevlink = addptr;

    return TRUE;
}

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_ANNOTDESC:
                    if (! AddAnnotDesc(sap, 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_ANNOTDESC:
            vnp = (ValNodePtr)newptr;
            switch (newtype)
            {
                case OBJ_ANNOTDESC:
                    if (gcp->prevlink != NULL)
                    {
                        vnp->next = *(gcp->prevlink);
                        *(gcp->prevlink) = vnp;
                    }
                    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 = NULL;
    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, Uint4 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;
    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, Uint4 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:
        case OBJ_ANNOTDESC:
            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;
  Uint4             itemIDs [OBJ_MAX];
  Boolean           assignIDs;
  GatherObjectProc  callback;
  Pointer           userdata;
  BoolPtr           objMgrFilter;
  Boolean           external;
} 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;
      go.external = iap->external;
      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 Uint1 FastFindFeatDefType (SeqFeatPtr sfp)

{
  if (sfp != NULL && sfp->idx.subtype != 0) return sfp->idx.subtype;
  return FindFeatDefType (sfp);
}

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, FastFindFeatDefType (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 VisitAnnotDesc (InternalACCPtr iap, AnnotDescrPtr adp, Pointer parent, Uint2 parenttype, Pointer PNTR prevlink)

{
  Uint1          itemtype = OBJ_ANNOTDESC;
  ObjValNodePtr  ovp;

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

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

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

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

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

    prevlink = (Pointer PNTR) &(adp->next);
    adp = adp->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;
    }

    if (! VisitAnnotDesc (iap, sap->desc, (Pointer) sap, itemtype, (Pointer PNTR) &(sap->desc))) 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.
*
*   The Ex versions take a ValNodePtr parameter whose data.ptrvalue fields point to
*       a Bioseq that contains a SeqAnnot with remotely fetched features.
*
*****************************************************************************/

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

{
  BioseqPtr      bsp;
  InternalACC    iac;
  ObjMgrDataPtr  omdp;
  ObjMgrPtr      omp;
  ValNodePtr     vnp;

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

  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_ANNOTDESC :
      VisitAnnotDesc (&iac, (AnnotDescrPtr) 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;
  }

  /* handle remotely fetched features from ValNode list of Bioseqs */

  for (vnp = extra; vnp != NULL; vnp = vnp->next) {
    bsp = (BioseqPtr) vnp->data.ptrvalue;
    if (bsp == NULL || bsp->annot == NULL) continue;
    iac.external = TRUE;
    if (! VisitSeqAnnot (&iac, bsp->annot, (Pointer) bsp, OBJ_BIOSEQ, (Pointer PNTR) &(bsp->annot))) return FALSE;
  }

  return TRUE;
}

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

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

NLM_EXTERN Boolean LIBCALL AssignIDsInEntityEx (
  Uint2 entityID,
  Uint2 datatype,
  Pointer dataptr,
  ValNodePtr extra
)

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

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, NULL);
}

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

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

/*****************************************************************************
*
*   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) {
    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) bsp->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) bssp->idx.parentptr;
    } else {
      return NULL;
    }
  } else {
    if (bsp->idx.parenttype != OBJ_BIOSEQSET) return NULL;
    bssp = (BioseqSetPtr) bsp->idx.parentptr;
  }

  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) bssp->idx.parentptr;
  }
  return NULL;
}

typedef struct getptrforid {
  Uint2    entityID;
  Uint4    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, Uint4 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 Boolean NoGenomeAnnotationInAnnotDescr (SeqAnnotPtr sap)

{
  AnnotDescrPtr  adp;
  ObjectIdPtr    oip;
  CharPtr        str;
  UserFieldPtr   ufp;
  UserObjectPtr  uop;

  if (sap == NULL) return TRUE;

  for (adp = sap->desc; adp != NULL; adp = adp->next) {
    if (adp->choice != Annot_descr_user) continue;
    uop = (UserObjectPtr) adp->data.ptrvalue;
    if (uop == NULL) continue;
    oip = uop->type;
    if (oip == NULL) continue;
    if (StringICmp (oip->str, "StructuredComment") != 0) continue;
    for (ufp = uop->data; ufp != NULL; ufp = ufp->next) {
      if (ufp->choice != 1) continue;
      oip = ufp->label;
      if (oip == NULL) continue;
      if (StringCmp (oip->str, "StructuredCommentPrefix") != 0) continue;
      str = (CharPtr) ufp->data.ptrvalue;
      if (StringCmp (str, "##Genome-Annotation-Data-START##") == 0) return FALSE;
    }
  }

  return TRUE;
}

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;
      }
      /* now keep empty annot if annot_descr present */
      if (sap->data == NULL && /* sap->desc == NULL */ NoGenomeAnnotationInAnnotDescr (sap)) {
        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 (bssp->seq_set == NULL && bssp->_class != BioseqseqSet_class_empty_set) {
            bssp->idx.deleteme = 1;
            unlink = TRUE;
          }
        }
      }
    }
    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->idx.deleteme) {
        ssp = SeqSubmitFree (ssp);
        return TRUE;
      } else if (ssp->datatype == 1) {
        sep = (SeqEntryPtr) ssp->data;
      }
      break;
    default :
      return FALSE;
  }

  if (sep == NULL) return FALSE;

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

  return TRUE;
}

