/*   gbfview.c
* ===========================================================================
*
*                            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:  gbfview.c
*
* Author:  Jonathan Kans
*
* Version Creation Date:   2/5/97
*
* $Revision: 6.106 $
*
* File Description: 
*
* Modifications:  
* --------------------------------------------------------------------------
* Date     Name        Description of modification
* -------  ----------  -----------------------------------------------------
*
*
* ==========================================================================
*/

#include <bspview.h>
#include <objsub.h>
#include <asn2gnbp.h>
#include <asn2gnbi.h>
#include <tofasta.h>
#include <explore.h>
#include <subutil.h>

static ParData ffParFmt = {FALSE, FALSE, FALSE, FALSE, TRUE, 0, 0};
static ColData ffColFmt = {0, 0, 80, 0, NULL, 'l', FALSE, FALSE, FALSE, FALSE, TRUE};

typedef struct docdescrstruct {
  Uint2  entityID, itemtype;
  Uint4  itemID;
  Int2   docitem;
} DocDescrStruct, PNTR DocDescrPtr;

#define NOT_A_CDS     0
#define CDS_UNTESTED  1
#define CDS_OKAY      2
#define CDS_INVALID   3

typedef struct flatstruct {
  Asn2gbJobPtr       ajp;
  BaseBlockPtr PNTR  paragraphs;
  Int4               numParagraphs;
  SeqEntryPtr        sep;
  Int4               numdescr;
  DocDescrPtr        descr;
  Uint1Ptr           cdsstatus;
} FlatStruct, PNTR FlatStructPtr;

static Boolean GetIDsFromDoc (DoC d, Int2 item, Uint2Ptr entityPtr,
                              Uint4Ptr itemPtr, Uint2Ptr typePtr)

{
  BaseBlockPtr       bbp;
  BioseqViewPtr      bvp;
  Pointer            dataPtr;
  Uint2              entityID;
  FlatStructPtr      fsp;
  Uint4              itemID;
  Uint2              itemtype;
  Boolean            okay;
  BaseBlockPtr PNTR  paragraphs;

  okay = FALSE;
  entityID = 0;
  itemID = 0;
  itemtype = 0;
  bvp = (BioseqViewPtr) GetObjectExtra (d);
  if (bvp != NULL) {
    if (! bvp->highlightSelections) return FALSE;
    if (bvp->useScrollText) return FALSE;
    GetItemParams (d, item, NULL, NULL, NULL, NULL, &dataPtr);
    if (dataPtr != NULL) {
      fsp = (FlatStructPtr) dataPtr;
      paragraphs = fsp->paragraphs;
      if (paragraphs != NULL) {
        bbp = paragraphs [item - 1];
        if (bbp != NULL) {
          entityID = bbp->entityID;
          itemID = bbp->itemID;
          itemtype = bbp->itemtype;
          okay = (Boolean) (entityID > 0 && itemID > 0 && itemtype > 0);
        }
      }
    }
  }
  if (entityPtr != NULL) {
    *entityPtr = entityID;
  }
  if (itemPtr != NULL) {
    *itemPtr = itemID;
  }
  if (typePtr != NULL) {
    *typePtr = itemtype;
  }
  return okay;
}

static void DrawIcon (DoC d, RectPtr r, Int2 item, Int2 firstLine)

{
  BioseqViewPtr  bvp;
  Uint2          entityID;
  Uint4          itemID;
  Uint2          itemtype;
  RecT           rct;
  SelStructPtr   sel;

  bvp = (BioseqViewPtr) GetObjectExtra (d);
  if (bvp == NULL) return;
  if (! bvp->highlightSelections) return;
  if (GetIDsFromDoc (d, item, &entityID, &itemID, &itemtype)) {
    for (sel = ObjMgrGetSelected (); sel != NULL; sel = sel->next) {
      if (entityID == sel->entityID &&
          itemID == sel->itemID &&
          itemtype == sel->itemtype) {
        rct = *r;
        rct.right = rct.left + 4;
        PaintRect (&rct);
      }
    }
  }
}

static DocDescrPtr FindFFPDocDescr (DocDescrPtr doscr, Int4 numdescr,
                                    Uint2 entityID, Uint2 itemID, Uint2 itemtype)

{
  DocDescrPtr  dsp;
  Int4         L, R, mid;
  DocDescrPtr  rsult;

  L = 0;
  R = numdescr - 1;
  while (L <= R) {
    mid = (L + R) / 2;
    dsp = &(doscr [mid]);
    if (dsp == NULL) return NULL;
    if (dsp->entityID > entityID) {
      R = mid - 1;
    } else if (dsp->entityID < entityID) {
      L = mid + 1;
    } else if (dsp->itemtype > itemtype) {
      R = mid - 1;
    } else if (dsp->itemtype < itemtype) {
      L = mid + 1;
    } else if (dsp->itemID > itemID) {
      R = mid - 1;
    } else if (dsp->itemID < itemID) {
      L = mid + 1;
    } else {
      rsult = dsp;
      /* scan to first paragraph for item */
      while (mid >= 0) {
        dsp = &(doscr [mid]);
        if (dsp != NULL) {
          if (dsp->entityID == entityID &&
              dsp->itemtype == itemtype &&
              dsp->itemID == itemID) {
            rsult = dsp;
          }
        }
        mid--;
      }
      return rsult;
    }
  }

  return NULL;
}

static Boolean OverlapgGeneIsPseudo (SeqFeatPtr sfp)

{
  SeqFeatPtr      gene;
  GeneRefPtr      grp;

  if (sfp == NULL)
    return FALSE;
  grp = SeqMgrGetGeneXref (sfp);
  if (grp != NULL) {
    if (grp->pseudo)
      return TRUE;
    return FALSE;
  }
  gene = SeqMgrGetOverlappingGene (sfp->location, NULL);
  if (gene != NULL) {
    if (gene->pseudo)
      return TRUE;
    grp = (GeneRefPtr) gene->data.value.ptrvalue;
    if (grp != NULL) {
      if (grp->pseudo)
        return TRUE;
    }
  }
  return FALSE;
}

static CharPtr bypass_cds_check [] = {
  "RNA editing",
  "reasons given in citation",
  "artificial frameshift",
  "rearrangement required for product",
  "unclassified translation discrepancy",
  "mismatches in translation",
  "adjusted for low-quality genome",
  NULL
};

static Boolean CdsIsInvalid (SeqFeatPtr sfp)

{
  ByteStorePtr  bs;
  BioseqPtr     bsp;
  Char          ch;
  CdRegionPtr   crp;
  Int2          i;
  CharPtr       ptr, str1, str2;

  if (sfp->pseudo) return FALSE;
  if (OverlapgGeneIsPseudo (sfp)) return FALSE;

  crp = (CdRegionPtr) (sfp->data.value.ptrvalue);
  if (crp != NULL && crp->conflict) return FALSE;

  if (sfp->excpt && StringDoesHaveText (sfp->except_text)) {
    for (i = 0; bypass_cds_check [i] != NULL; i++) {
      if (StringISearch (sfp->except_text,  bypass_cds_check [i]) != NULL) return FALSE;
    }
  }

  bsp = BioseqFindFromSeqLoc (sfp->product);
  str1 = GetSequenceByBsp (bsp);
  if (str1 != NULL) {
    ptr = str1;
    ch = *ptr;
    while (ch != '\0') {
      if (ch == '-' || ch == '*') {
        MemFree (str1);
        return TRUE;
      }
      ptr++;
      ch = *ptr;
    }
  }
  bs = TransTableTranslateCdRegion (NULL, sfp, FALSE, FALSE, FALSE);
  str2 = (CharPtr) BSMerge (bs, NULL);
  BSFree (bs);

  if (str1 != NULL && str2 != NULL && StringCmp (str1, str2) != 0) {
    MemFree (str1);
    MemFree (str2);
    return TRUE;
  }

  MemFree (str1);
  MemFree (str2);

  return FALSE;
}

static Boolean ColorIcon (
  DoC d,
  Int2 item,
  Int2 row, 
  Int2 col
)

{
  SeqMgrFeatContext  context;
  Uint2              entityID;
  FlatStructPtr      fsp;
  Uint4              itemID;
  Uint2              itemtype;
  SeqFeatPtr         sfp;
  Uint1              status;

  fsp = (FlatStructPtr) GetDocData (d);
  if (fsp == NULL) return FALSE;

  status = fsp->cdsstatus [item - 1];
  if (status == NOT_A_CDS) return FALSE;
  if (status == CDS_OKAY) return FALSE;

  if (status == CDS_UNTESTED) {
    if (GetIDsFromDoc (d, item, &entityID, &itemID, &itemtype) && itemtype == OBJ_SEQFEAT) {
      sfp = SeqMgrGetDesiredFeature (entityID, NULL, itemID, 0, NULL, &context);
      if (sfp != NULL && sfp->idx.subtype == FEATDEF_CDS) {
        if (CdsIsInvalid (sfp)) {
          status = CDS_INVALID;
          fsp->cdsstatus [item - 1] = status;
        }
      }
    }
  }

  if (status == CDS_INVALID) {
    Red ();
    return TRUE;
  }

  fsp->cdsstatus [item - 1] = CDS_OKAY;
  return FALSE;
}

static void ClickIcon (DoC d, PoinT pt)

{
  BioseqViewPtr  bvp;

  bvp = (BioseqViewPtr) GetObjectExtra (d);
  if (bvp == NULL) return;
  bvp->wasDoubleClick = dblClick;
  bvp->wasShiftKey = shftKey;
  MapDocPoint (d, pt, &(bvp->itemClicked), NULL, NULL, NULL);
}

typedef struct matchstruc {
  CharPtr   str;
  Uint4     editItemID;
  Boolean   found;
  Boolean   slashgene;
  Boolean   slashproduct;
} MatchStruc, PNTR MatchStrucPtr;

static void LIBCALLBACK FindStringCallBack (AsnExpOptStructPtr pAEOS)

{
  MatchStrucPtr  msp;
  CharPtr        pchSource;

  if (pAEOS == NULL) return;
  msp = (MatchStrucPtr) pAEOS->data;
  if (msp == NULL) return;
  if (! ISA_STRINGTYPE (AsnFindBaseIsa (pAEOS->atp))) return;
  pchSource = (CharPtr) pAEOS->dvp->ptrvalue;
  if (StringSearch (pchSource, msp->str) == NULL) return;
  msp->found = TRUE;
}

static void CheckForStringInFeature (SeqFeatPtr sfp, MatchStrucPtr msp)

{
  AsnExpOptPtr  aeop;
  AsnIoPtr      aip;
  SeqLocPtr     location;
  SeqLocPtr     product;
  ValNode       vn;

  if (sfp == NULL || msp == NULL) return;
  msp->found = FALSE;
  aip = AsnIoNullOpen ();
  if (aip != NULL) {
    aeop = AsnExpOptNew (aip, NULL, NULL, FindStringCallBack);
    if (aeop != NULL) {
      aeop->user_data = msp;
      location = sfp->location;
      product = sfp->product;
      vn.choice = SEQLOC_NULL;
      vn.data.ptrvalue = NULL;
      sfp->location = &vn;
      sfp->product = &vn;
      SeqFeatAsnWrite (sfp, aip, NULL);
      sfp->location = location;
      sfp->product = product;
    }
    AsnIoClose (aip);
  }
}

typedef struct protgenegatherlist {
  SeqLocPtr  slp;
  Uint2      choice;
  Int4       min;
  Uint2      entityID;
  Uint4      itemID;
  Uint2      itemtype;
  Boolean    found;
} ProtGeneGatherList, PNTR ProtGeneGatherPtr;

static Boolean ProtGeneMatchFunc (GatherContextPtr gcp)

{
  Int4               diff;
  ProtGeneGatherPtr  pgp;
  SeqFeatPtr         sfp;

  if (gcp == NULL) return TRUE;

  pgp = (ProtGeneGatherPtr) gcp->userdata;
  if (pgp == NULL) return TRUE;

  if (gcp->thistype != OBJ_SEQFEAT) return TRUE;
  sfp = (SeqFeatPtr) gcp->thisitem;
  if (sfp == NULL || sfp->data.choice != pgp->choice ||
      sfp->data.value.ptrvalue == NULL) return TRUE;
  if (pgp->choice == SEQFEAT_PROT) {
    diff = SeqLocAinB (sfp->location, pgp->slp);
  } else {
    diff = SeqLocAinB (pgp->slp, sfp->location);
  }
  if (diff < 0) return TRUE;
  if (diff >= pgp->min) return TRUE;
  pgp->min = diff;
  pgp->entityID = gcp->entityID;
  pgp->itemID = gcp->itemID;
  pgp->itemtype = gcp->thistype;
  pgp->found = TRUE;

  return TRUE;
}

static Uint2 GetBestGeneOrProteinFeature (Uint2 entityID, SeqEntryPtr scope,
                                          SeqLocPtr location, Uint2 choice)

{
  GatherScope         gs;
  ProtGeneGatherList  pgl;

  if (entityID == 0 || location == NULL) return 0;
  pgl.entityID = 0;
  pgl.itemID = 0;
  pgl.itemtype = 0;
  pgl.found = FALSE;
  pgl.slp = location;
  pgl.choice = choice;
  pgl.min = INT4_MAX;
  MemSet ((Pointer) (&gs), 0, sizeof (GatherScope));
  gs.seglevels = 1;
  gs.get_feats_location = FALSE;
  gs.scope = scope;
  MemSet((Pointer)(gs.ignore), (int)(TRUE), (size_t)(OBJ_MAX * sizeof(Boolean)));
  gs.ignore[OBJ_BIOSEQ] = FALSE;
  gs.ignore[OBJ_BIOSEQ_SEG] = FALSE;
  gs.ignore[OBJ_SEQFEAT] = FALSE;
  gs.ignore[OBJ_SEQANNOT] = FALSE;
  GatherEntity (entityID, (Pointer) &pgl, ProtGeneMatchFunc, &gs);
  return pgl.itemID;
}

static Boolean MatchSubItemInFlatFileProc (GatherContextPtr gcp)

{
  MatchStrucPtr  msp;
  SeqFeatPtr     sfp;

  if (gcp == NULL || gcp->thisitem == NULL || gcp->thistype != OBJ_SEQFEAT) {
    return FALSE;
  }
  msp = (MatchStrucPtr) gcp->userdata;
  if (msp == NULL) return FALSE;
  sfp = (SeqFeatPtr) gcp->thisitem;
  CheckForStringInFeature (sfp, msp);
  return FALSE;
}

static Boolean MatchItemInFlatFileProc (GatherContextPtr gcp)

{
  Uint4          itemID;
  MatchStrucPtr  msp;
  SeqFeatPtr     sfp;

  if (gcp == NULL || gcp->thisitem == NULL || gcp->thistype != OBJ_SEQFEAT) {
    return FALSE;
  }
  msp = (MatchStrucPtr) gcp->userdata;
  if (msp == NULL) return FALSE;
  sfp = (SeqFeatPtr) gcp->thisitem;
  /*
  if (msp->slashgene) {
    itemID = GetBestGeneOrProteinFeature (gcp->entityID, NULL, sfp->location, SEQFEAT_GENE);
    if (itemID != 0) {
      GatherItem (gcp->entityID, itemID, OBJ_SEQFEAT, (Pointer) msp, MatchSubItemInFlatFileProc);
      if (msp->found) {
        msp->editItemID = itemID;
        return TRUE;
      }
    }
  }
  CheckForStringInFeature (sfp, msp);
  if (msp->found) {
    return TRUE;
  }
  */
  if (sfp->data.choice == SEQFEAT_CDREGION) {
    itemID = GetBestGeneOrProteinFeature (gcp->entityID, NULL, sfp->product, SEQFEAT_PROT);
    if (itemID != 0) {
      GatherItem (gcp->entityID, itemID, OBJ_SEQFEAT, (Pointer) msp, MatchSubItemInFlatFileProc);
      if (msp->found) {
        msp->editItemID = itemID;
        return TRUE;
      }
    }
  }
  /*
  if (! msp->slashgene) {
    itemID = GetBestGeneOrProteinFeature (gcp->entityID, NULL, sfp->location, SEQFEAT_GENE);
    if (itemID != 0) {
      GatherItem (gcp->entityID, itemID, OBJ_SEQFEAT, (Pointer) msp, MatchSubItemInFlatFileProc);
      if (msp->found) {
        msp->editItemID = itemID;
        return TRUE;
      }
    }
  }
  */
  return FALSE;
}

static Uint2 MatchItemInFlatFile (Uint2 entityID, Uint4 itemID, CharPtr str,
                                  Boolean slashgene, Boolean slashproduct)

{
  MatchStruc  ms;

  ms.editItemID = itemID;
  ms.str = str;
  ms.slashgene = slashgene;
  ms.slashproduct = slashproduct;
  GatherItem (entityID, itemID, OBJ_SEQFEAT, (Pointer) &ms, MatchItemInFlatFileProc);
  return ms.editItemID;
}

static CharPtr google_earth_1 =
  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \
  "<kml xmlns=\"http://earth.google.com/kml/2.2\">\n" \
  "<Document>\n" \
  "  <name>KmlFile</name>\n" \
  "  <StyleMap id=\"default_copy0+nicon=http://maps.google.com/mapfiles/kml/pal3/icon60.png+hicon=http://maps.google.com/mapfiles/kml/pal3/icon52.png\">\n" \
  "    <Pair>\n" \
  "      <key>normal</key>\n" \
  "      <styleUrl>#default_copy0+icon=http://maps.google.com/mapfiles/kml/pal3/icon60.png</styleUrl>\n" \
  "    </Pair>\n" \
  "    <Pair>\n" \
  "      <key>highlight</key>\n" \
  "      <styleUrl>#default_copy0+icon=http://maps.google.com/mapfiles/kml/pal3/icon52.png</styleUrl>\n" \
  "    </Pair>\n" \
  "  </StyleMap>\n" \
  "  <Style id=\"default_copy0+icon=http://maps.google.com/mapfiles/kml/pal3/icon60.png\">\n" \
  "    <IconStyle>\n" \
  "      <Icon>\n" \
  "        <href>http://maps.google.com/mapfiles/kml/pal3/icon60.png</href>\n" \
  "      </Icon>\n" \
  "    </IconStyle>\n" \
  "  </Style>\n" \
  "  <Placemark>\n";

static CharPtr google_earth_2 =
  "    <styleUrl>#default_copy0+nicon=http://maps.google.com/mapfiles/kml/pal3/icon60.png+hicon=http://maps.google.com/mapfiles/kml/pal3/icon52.png</styleUrl>\n" \
  "    <Point>\n";

static CharPtr google_earth_3 =
  "    </Point>\n" \
  "  </Placemark>\n" \
  "</Document>\n" \
  "</kml>\n";

static void ReleaseIcon (DoC d, PoinT pt)

{
  BioSourcePtr       biop;
  BioseqViewPtr      bvp;
  Char               ch;
  SeqMgrDescContext  context;
  CharPtr            dst;
  Uint4              editItemID;
  Uint2              entityID;
  Boolean            format_ok = FALSE;
  FILE               *fp;
  Int2               handled;
  Int2               item;
  Uint4              itemID;
  Uint2              itemtype;
  FloatHi            lat = 0.0;
  FloatHi            lon = 0.0;
  CharPtr            lat_lon = NULL;
  Boolean            lat_in_range = FALSE;
  Boolean            lon_in_range = FALSE;
  Char               path [PATH_MAX];
  Boolean            precision_ok = FALSE;
  Int2               row;
  SeqDescPtr         sdp;
  SeqEntryPtr        sep;
  Boolean            slashgene;
  Boolean            slashproduct;
  CharPtr            src;
  SubSourcePtr       ssp;
  CharPtr            str;
#ifdef OS_UNIX
  Char               cmmd [256];
#endif

  bvp = (BioseqViewPtr) GetObjectExtra (d);
  if (bvp == NULL) return;
  MapDocPoint (d, pt, &item, &row, NULL, NULL);
  if (row != 0 && item != 0 && item == bvp->itemClicked) {
    if (GetIDsFromDoc (d, item, &entityID, &itemID, &itemtype)) {
      if (bvp->wasDoubleClick) {

        if (bvp->wasShiftKey) {
          if (itemtype == OBJ_SEQDESC) {
            sdp = SeqMgrGetDesiredDescriptor (entityID, NULL, itemID, 0, NULL, &context);
            if (sdp != NULL && sdp->choice == Seq_descr_source) {
              biop = (BioSourcePtr) sdp->data.ptrvalue;
              if (biop != NULL) {
                for (ssp = biop->subtype; ssp != NULL; ssp = ssp->next) {
                  if (ssp->subtype != SUBSRC_lat_lon) continue;
                  lat_lon = ssp->name;
                  if (StringHasNoText (lat_lon)) continue;
                  IsCorrectLatLonFormat (lat_lon, &format_ok, &precision_ok, &lat_in_range, &lon_in_range);
                  if (! format_ok) continue;
                  /*
                  if (! precision_ok) continue;
                  */
                  if (! lat_in_range) continue;
                  if (! lon_in_range) continue;
                  if (! ParseLatLon (lat_lon, &lat, &lon)) continue;
                  TmpNam (path);
                  /* write to original temp file, so next temp file name will not collide */
                  fp = FileOpen (path, "w");
                  if (fp != NULL) {
                    fprintf (fp, "\n");
                    FileClose (fp);
                    RememberSqnTempFile (path);
                  }
                  /* now append .kml extension so proper application is launched */
                  StringCat (path, ".kml");
                  fp = FileOpen (path, "w");
                  if (fp != NULL) {
                    fprintf (fp, "%s", google_earth_1);
                    fprintf (fp, "    <name>%s</name>\n", lat_lon);
                    fprintf (fp, "%s", google_earth_2);
                    fprintf (fp, "      <coordinates>%lf,%lf</coordinates>\n", (double) lon, (double) lat);
                    fprintf (fp, "%s", google_earth_3);
                    FileClose (fp);
                    RememberSqnTempFile (path);
#ifdef OS_UNIX
                    sprintf (cmmd, "open %s", path);
                    system (cmmd);
#endif
#ifdef WIN_MSWIN
                    Nlm_MSWin_OpenDocument (path);
#endif
                  }
                  return;
                }
              }
            }
          }
        }

        sep = GetTopSeqEntryForEntityID (entityID);
        if (bvp->launchSubviewers) {
          WatchCursor ();
          Update ();
          LaunchNewBioseqViewer (bvp->bsp, entityID, itemID, itemtype);
          ArrowCursor ();
          Update ();
          return;
        } else if (LaunchViewerNotEditor (bvp, sep, entityID, itemID, itemtype)) {
          WatchCursor ();
          Update ();
          LaunchNewBioseqViewer (bvp->bsp, entityID, itemID, itemtype);
          ArrowCursor ();
          Update ();
          return;
        } else if (bvp->launchEditors) {
          WatchCursor ();
          Update ();
          editItemID = itemID;
          if (itemtype == OBJ_SEQFEAT && GetAppProperty ("InternalNcbiSequin") != NULL) {
            str = GetDocText (d, item, row, 1);
            TrimSpacesAroundString (str);
            src = str;
            dst = str;
            ch = *src;
            slashgene = FALSE;
            slashproduct = FALSE;
            if (str != NULL && str [0] == '/') {
              if (StringStr (str, "/gene") != NULL) {
                slashgene = TRUE;
              }
              if (StringStr (str, "/product") != NULL) {
                slashproduct = TRUE;
              }
              while (ch != '=' && ch != '\0') {
                src++;
                ch = *src;
              }
              if (ch == '=') {
                src++;
                ch = *src;
              }
            }
            while (ch != '\0') {
              if (ch != '"') {
                *dst = ch;
                dst++;
              }
              src++;
              ch = *src;
            }
            *dst = '\0';
            editItemID = MatchItemInFlatFile (entityID, itemID, str, slashgene, slashproduct);
            MemFree (str);
          }
          handled = GatherProcLaunch (OMPROC_EDIT, FALSE, entityID, editItemID,
                                      itemtype, 0, 0, itemtype, 0);
          ArrowCursor ();
          Update ();
          if (handled == OM_MSG_RET_DONE || handled == OM_MSG_RET_NOPROC) {
            return;
          }
        } else {
          return;
        }
      }
      if (! bvp->sendSelectMessages) return;
      if (bvp->wasShiftKey) {
        ObjMgrAlsoSelect (entityID, itemID, itemtype,0,NULL);
      } else {
        ObjMgrSelect (entityID, itemID, itemtype,0,NULL);
      }
    }
  } else if (item == bvp->itemClicked) {
    if (! bvp->sendSelectMessages) return;
    ObjMgrDeSelect (0, 0, 0,0,NULL);
  }
}

static void DocFreeFlat (DoC d, VoidPtr data)

{
  FlatStructPtr  fsp;

  if (data != NULL) {
    fsp = (FlatStructPtr) data;
    fsp->ajp = asn2gnbk_cleanup (fsp->ajp);
    MemFree (fsp->descr);
    MemFree (fsp->cdsstatus);
    MemFree (fsp);
  }
}

static CharPtr FFPrintFunc (DoC d, Int2 index, Pointer data)

{
  BaseBlockPtr       bbp;
  BaseFormPtr        bfp;
  BioseqPtr          bsp;
  BioseqViewPtr      bvp;
  FlatStructPtr      fsp;
  ErrSev             level;
  SeqEntryPtr        oldsep = NULL;
  OMUserDataPtr      omudp;
  BaseBlockPtr PNTR  paragraphs;
  CharPtr            str = NULL;
  SeqEntryPtr        topsep;

  bvp = (BioseqViewPtr) GetObjectExtra (d);
  fsp = (FlatStructPtr) data;
  if (bvp == NULL || bvp->bsp == NULL || fsp == NULL) return StringSave ("?\n");
  level = ErrSetMessageLevel (SEV_MAX);
  bsp = BioseqLock (bvp->bsp);
  bfp = (BaseFormPtr) GetObjectExtra (bvp->form);
  if (bfp != NULL) {
    topsep = GetTopSeqEntryForEntityID (bfp->input_entityID);
    oldsep = SeqEntrySetScope (topsep);
  }
  str = asn2gnbk_format (fsp->ajp, (Int4) (index - 1));
  if (oldsep != NULL) {
    SeqEntrySetScope (oldsep);
  }
  if (bfp != NULL && bfp->userkey > 0) {
    paragraphs = fsp->paragraphs;
    if (paragraphs != NULL) {
      bbp = paragraphs [index - 1];
      if (bbp != NULL && bbp->entityID != 0 && bbp->entityID != bfp->input_entityID) {
        if (! InBioseqViewEntityList (bbp->entityID, bvp)) {
          ValNodeAddInt (&(bvp->entityList), 0, (Int4) bbp->entityID);
          omudp = ObjMgrAddUserData (bbp->entityID, bfp->procid,
                                     OMPROC_VIEW, bfp->userkey);
          if (omudp != NULL) {
            omudp->userdata.ptrvalue = (Pointer) bfp;
            omudp->messagefunc = BioseqViewMsgFunc;
          }
        }
      }
    }
  }
  BioseqUnlock (bsp);
  ErrSetMessageLevel (level);
  return str;
}

static int LIBCALLBACK SortDescrProc (VoidPtr vp1, VoidPtr vp2)

{
  DocDescrPtr  descr1;
  DocDescrPtr  descr2;

  descr1 = (DocDescrPtr) vp1;
  descr2 = (DocDescrPtr) vp2;
  if (descr1 == NULL || descr2 == NULL) return 0;

  if (descr1->entityID > descr2->entityID) return 1;
  if (descr1->entityID < descr2->entityID) return -1;

  if (descr1->itemtype > descr2->itemtype) return 1;
  if (descr1->itemtype < descr2->itemtype) return -1;

  if (descr1->itemID > descr2->itemID) return 1;
  if (descr1->itemID < descr2->itemID) return -1;

  if (descr1->docitem > descr2->docitem) return 1;
  if (descr1->docitem < descr2->docitem) return -1;

  return 0;
}

typedef struct locallookforids {
  Boolean isGED;
  Boolean isNTorNWorNG;
  Boolean isNC;
  Boolean isTPA;
  Boolean isAEorCH;
} LocalLookForIDs, PNTR LocalLookForIDsPtr;

static void LookForSeqIDs (BioseqPtr bsp, Pointer userdata)

{
  LocalLookForIDsPtr  lfip;
  SeqIdPtr       sip;
  TextSeqIdPtr   tsip;

  lfip = (LocalLookForIDsPtr) userdata;
  for (sip = bsp->id; sip != NULL; sip = sip->next) {
    switch (sip->choice) {
      case SEQID_GENBANK :
      case SEQID_EMBL :
      case SEQID_DDBJ :
        lfip->isGED = TRUE;
        tsip = (TextSeqIdPtr) sip->data.ptrvalue;
        if (tsip != NULL) {
          if (StringNCmp (tsip->accession, "AE", 2) == 0) {
            lfip->isAEorCH = TRUE;
          } else if (StringNCmp (tsip->accession, "CH", 2) == 0) {
            lfip->isAEorCH = TRUE;
          }
        }
        break;
      case SEQID_TPG :
      case SEQID_TPE :
      case SEQID_TPD :
        lfip->isTPA = TRUE;
        break;
      case SEQID_OTHER :
        tsip = (TextSeqIdPtr) sip->data.ptrvalue;
        if (tsip != NULL) {
          if (StringNCmp (tsip->accession, "NC_", 3) == 0) {
            lfip->isNC = TRUE;
          } else if (StringNCmp (tsip->accession, "NT_", 3) == 0) {
            lfip->isNTorNWorNG = TRUE;
          } else if (StringNCmp (tsip->accession, "NW_", 3) == 0) {
            lfip->isNTorNWorNG = TRUE;
          } else if (StringNCmp (tsip->accession, "NG_", 3) == 0) {
            lfip->isNTorNWorNG = TRUE;
          }
        }
        break;
      default :
        break;
    }
  }
}

static void LookForGEDetc (
  SeqEntryPtr topsep,
  BoolPtr isGED,
  BoolPtr isNTorNWorNG,
  BoolPtr isNC,
  BoolPtr isTPA,
  BoolPtr isAEorCH
)

{
  LocalLookForIDs  lfi;

  MemSet (&lfi, 0, sizeof (LocalLookForIDs));
  VisitBioseqsInSep (topsep, &lfi, LookForSeqIDs);
  *isGED = lfi.isGED;
  *isNTorNWorNG = lfi.isNTorNWorNG;
  *isNC = lfi.isNC;
  *isTPA = lfi.isTPA;
  *isAEorCH = lfi.isAEorCH;
}

static void LookForNonLocalID (BioseqPtr bsp, Pointer userdata)

{
  BoolPtr   isNonLocalPtr;
  SeqIdPtr  sip;

  isNonLocalPtr = (BoolPtr) userdata;
  for (sip = bsp->id; sip != NULL; sip = sip->next) {
    switch (sip->choice) {
      case SEQID_LOCAL :
        break;
      default :
        *isNonLocalPtr = TRUE;
        break;
    }
  }
}

static void LookForPubs (BioseqPtr bsp, Pointer userdata)

{
  BoolPtr  hasPub;

  hasPub = (BoolPtr) userdata;
  *hasPub = TRUE;
}

static void CheckVersionWithGi (BioseqPtr bsp, Pointer userdata)

{
  Boolean       hasGi = FALSE;
  BoolPtr       missingVersion;
  SeqIdPtr      sip;
  TextSeqIdPtr  tsip;
  Boolean       zeroVersion = FALSE;

  for (sip = bsp->id; sip != NULL; sip = sip->next) {
    switch (sip->choice) {
      case SEQID_TPG:
      case SEQID_TPE:
      case SEQID_TPD:
      case SEQID_GENBANK:
      case SEQID_EMBL:
      case SEQID_DDBJ:
        tsip = (TextSeqIdPtr) sip->data.ptrvalue;
        if (tsip != NULL && tsip->version == 0) {
          zeroVersion = TRUE;
        }
        break;
      case SEQID_GI :
        hasGi = TRUE;
        break;
      default :
        break;
    }
  }
  if (hasGi && zeroVersion) {
    missingVersion = (BoolPtr) userdata;
    *missingVersion = TRUE;
  }
}

static CharPtr relmodemsg1 = "Record cannot only have a local Seq-id for release mode";
static CharPtr relmodemsg2 = "Record must have a publication for release mode";
static CharPtr relmodemsg3 = "Record with gi must have version number for release mode";
static CharPtr relmodemsg4 = "Release mode failure";

static CharPtr RelModeFailText (
  BioseqPtr bsp,
  SeqEntryPtr usethetop,
  SeqEntryPtr topsep
)

{
  SeqMgrDescContext  dcontext;
  SeqMgrFeatContext  fcontext;
  Boolean            missingVersion;
  Boolean            nonLocalID;
  Boolean            hasPubs;

  nonLocalID = FALSE;
  if (usethetop) {
    VisitBioseqsInSep (usethetop, (Pointer) &nonLocalID, LookForNonLocalID);
  } else {
    LookForNonLocalID (bsp, (Pointer) &nonLocalID);
  }
  if (! nonLocalID) {
    return StringSave (relmodemsg1);
  }

  hasPubs = FALSE;
  if (usethetop) {
    if (VisitPubdescsInSep (usethetop, NULL, NULL) == 0) {
      return StringSave (relmodemsg2);
    }
  } else {
    if (SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_pub, &dcontext) == NULL) {
      if (SeqMgrGetNextFeature (bsp, NULL, SEQFEAT_PUB, 0, &fcontext) == NULL) {
        return StringSave (relmodemsg2);
      }
    }
  }

  missingVersion = FALSE;
  VisitBioseqsInSep (topsep, (Pointer) &missingVersion, CheckVersionWithGi);
  if (missingVersion) {
    return StringSave (relmodemsg3);
  }

  return StringSave (relmodemsg4);
}

static Int2 asn2gb_line_estimate [30] = {
  0,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1, /* source */
  2, /* organism */
  1, /* ref-stats */
  6, /* reference */
  4, /* primary */
  4, /* comment */
  1, /* feat-stats */
  1,
  4, /* source */
  6, /* feature */
  1,
  1,
 20, /* sequence */
  4, /* contig */
  1, /* wgs */
  1, /* genome */
  1, /* slash */
  1  /* tail */
};

static Boolean PopulateFF (
  DoC d,
  SeqEntryPtr sep,
  BioseqPtr bsp,
  SeqEntryPtr usethetop,
  FmtType format,
  ModType mode,
  StlType style,
  FlgType flags,
  CstType custom
)

{
  Asn2gbJobPtr    ajp;
  BaseBlockPtr    bbp;
  BlockType       blocktype;
  BioseqSetPtr    bssp;
  BioseqViewPtr   bvp;
  Uint1Ptr        cdsstatus;
  DocDescrPtr     doscr;
  DocDescrPtr     doscrp;
  Int2            estimate;
  XtraBlock       extra;
  FeatBlockPtr    fbp;
  FonT            fnt;
  FlatStructPtr   fsp;
  Int4            index;
  ErrSev          level;
  Boolean         rsult;

  rsult = FALSE;
  if (d != NULL && sep != NULL && bsp != NULL && spop != NULL) {
    fnt = programFont;
    bvp = (BioseqViewPtr) GetObjectExtra (d);
    if (bvp != NULL && bvp->displayFont != NULL) {
      fnt = bvp->displayFont;
    }
    fsp = MemNew (sizeof (FlatStruct));
    if (fsp != NULL) {
      fsp->sep = sep;
      SetDocData (d, (Pointer) fsp, DocFreeFlat);
      level = ErrSetMessageLevel (SEV_MAX);
      MemSet ((Pointer) &extra, 0, sizeof (XtraBlock));
      if (usethetop != NULL && IS_Bioseq_set (usethetop)) {
        bssp = (BioseqSetPtr) usethetop->data.ptrvalue;
        ajp = asn2gnbk_setup (NULL, bssp, NULL, format, mode, style, flags, 0, custom, &extra);
      } else {
        ajp = asn2gnbk_setup (bsp, NULL, NULL, format, mode, style, flags, 0, custom, &extra);
      }
      if (ajp == NULL) return FALSE;
      fsp->ajp = ajp;
      fsp->numParagraphs = ajp->numParagraphs;
      fsp->paragraphs = ajp->paragraphArray;
      if (fsp->numParagraphs > 0 && fsp->paragraphs != NULL) {
        fsp->numdescr = 0;
        for (index = 0; index < fsp->numParagraphs; index++) {
          estimate = 1;
          bbp = fsp->paragraphs [index];
          if (bbp != NULL) {
            blocktype = bbp->blocktype;
            if (blocktype >= HEAD_BLOCK && blocktype <= TAIL_BLOCK) {
              estimate = asn2gb_line_estimate [(int) blocktype];
            }
          }
          AppendItem (d, FFPrintFunc, (Pointer) fsp, FALSE,
                      estimate, &ffParFmt, &ffColFmt, fnt);
          if (bbp != NULL) {
            (fsp->numdescr)++;
          }
        }
        doscrp = (DocDescrPtr) MemNew (sizeof (DocDescrStruct) * (size_t) (fsp->numdescr + 1));
        fsp->descr = doscrp;
        cdsstatus = (Uint1Ptr) MemNew (sizeof (Uint1) * (size_t) (fsp->numdescr + 1));
        fsp->cdsstatus = cdsstatus;
        fsp->numdescr = 0;
        if (doscrp != NULL && cdsstatus != NULL) {
          for (index = 0; index < fsp->numParagraphs; index++) {
            bbp = fsp->paragraphs [index];
            if (bbp != NULL) {
              doscr = &(doscrp [fsp->numdescr]);
              doscr->entityID = bbp->entityID;
              doscr->itemID = bbp->itemID;
              doscr->itemtype = bbp->itemtype;
              doscr->docitem = index + 1;
              if (bbp->blocktype == FEATURE_BLOCK) {
                fbp = (FeatBlockPtr) bbp;
                if (fbp->featdeftype == FEATDEF_CDS) {
                  cdsstatus [index] = CDS_UNTESTED;
                }
              }
              (fsp->numdescr)++;
            }
          }
        }
        HeapSort (doscrp, (size_t) fsp->numdescr, sizeof (DocDescrStruct), SortDescrProc);
        rsult = TRUE;
      }
      ErrSetMessageLevel (level);
    }
  }
  return rsult;
}

static void LookForTpa (
  SeqDescrPtr sdp,
  Pointer userdata
)

{
  BoolPtr        hastpaP;
  ObjectIdPtr    oip;
  UserObjectPtr  uop;

  if (sdp == NULL || sdp->choice != Seq_descr_user) return;
  uop = (UserObjectPtr) sdp->data.ptrvalue;
  if (uop == NULL) return;

  oip = uop->type;
  if (oip == NULL) return;
  if (StringCmp (oip->str, "TpaAssembly") != 0) return;

  hastpaP = (BoolPtr) userdata;
  *hastpaP = TRUE;
}

static void LookForTsa (
  SeqDescrPtr sdp,
  Pointer userdata
)

{
  BoolPtr     hastsaP;
  MolInfoPtr  mip;

  if (sdp == NULL || sdp->choice != Seq_descr_molinfo) return;
  mip = (MolInfoPtr) sdp->data.ptrvalue;
  if (mip == NULL) return;

  if (mip->tech != MI_TECH_tsa) return;

  hastsaP = (BoolPtr) userdata;
  *hastsaP = TRUE;
}

static void LookForFarBsp (
  BioseqPtr bsp,
  Pointer userdata
)

{
  BoolPtr  doColorsP;

  if (bsp == NULL) return;
  doColorsP = (BoolPtr) userdata;
  if (doColorsP == NULL) return;

  if (bsp->repr == Seq_repr_seg && (! SegHasParts (bsp))) {
    *doColorsP = FALSE;
  } else if (bsp->repr == Seq_repr_delta && (! DeltaLitOnly (bsp))) {
    *doColorsP = FALSE;
  }
}

static void LookForFarProds (
  SeqFeatPtr sfp,
  Pointer userdata
)

{
  BoolPtr  doColorsP;

  if (sfp == NULL) return;
  doColorsP = (BoolPtr) userdata;
  if (doColorsP == NULL) return;

  if (sfp->idx.subtype != FEATDEF_CDS) return;
  if (sfp->product == NULL) return;
  if (BioseqFindFromSeqLoc (sfp->product) == NULL) {
    *doColorsP = FALSE;
  }
}

static void GbfLookFarFeatFetchPolicy (
  SeqDescrPtr sdp,
  Pointer userdata
)

{
  BoolPtr        forceOnlyNearFeatsP;
  ObjectIdPtr    oip;
  UserFieldPtr   ufp;
  UserObjectPtr  uop;

  if (sdp == NULL || sdp->choice != Seq_descr_user) return;
  forceOnlyNearFeatsP = (BoolPtr) userdata;
  if (forceOnlyNearFeatsP == NULL) return;

  uop = (UserObjectPtr) sdp->data.ptrvalue;
  if (uop == NULL) return;
  oip = uop->type;
  if (oip == NULL) return;
  if (StringCmp (oip->str, "FeatureFetchPolicy") != 0) return;

  for (ufp = uop->data; ufp != NULL; ufp = ufp->next) {
    oip = ufp->label;
    if (oip == NULL || ufp->data.ptrvalue == NULL) continue;
    if (StringCmp (oip->str, "Policy") == 0) {
      if (StringICmp ((CharPtr) ufp->data.ptrvalue, "OnlyNearFeatures") == 0) {
        *forceOnlyNearFeatsP = TRUE;
      }
    }
  }
}

static void PopulateFlatFile (BioseqViewPtr bvp, FmtType format, FlgType flags)

{
  BioseqPtr          bsp;
  SeqMgrFeatContext  context;
  CstType            custom = 0;
  DoC                doc;
  Boolean            doColors;
  Boolean            doLockFarComponents = FALSE;
  Uint2              entityID;
  Int4               feats_with_product_count;
  FonT               fnt;
  Boolean            forceOnlyNearFeats = FALSE;
  FILE               *fp;
  Boolean            hastpaaligns;
  Boolean            hastsaaligns;
  Int2               into;
  Boolean            isAEorCH;
  Boolean            isGED;
  Boolean            isNTorNWorNG;
  Boolean            isNC;
  Boolean            isTPA;
  Int2               item;
  ErrSev             level;
  Boolean            lockFar = FALSE;
  Boolean            lookupFar = FALSE;
  ModType            mode = SEQUIN_MODE;
  SeqEntryPtr        oldsep;
  Char               path [PATH_MAX];
  BaR                sb = NULL;
  SeqEntryPtr        sep;
  SeqFeatPtr         sfp;
  Int4               startsAt;
  CharPtr            str;
  StlType            style = NORMAL_STYLE;
  SeqViewProcsPtr    svpp;
  SeqEntryPtr        topsep;
  TexT               txt;
  SeqEntryPtr        usethetop = NULL;
  Int2               val;

  if (bvp == NULL) return;
  if (bvp->hasTargetControl && bvp->ffModeCtrl != NULL) {
    val = GetValue (bvp->ffModeCtrl);
    switch (val) {
      case 1 :
        mode = RELEASE_MODE;
        break;
      case 2 :
        mode = ENTREZ_MODE;
        break;
      case 3 :
        mode = SEQUIN_MODE;
        break;
      case 4 :
        mode = DUMP_MODE;
        break;
      default :
        break;
    }
  }
  /* now using control instead of seqid type */
  if (bvp->ffStyleCtrl != NULL) {
    val = GetValue (bvp->ffStyleCtrl);
    switch (val) {
      case 1 :
        style = NORMAL_STYLE;
        lookupFar = TRUE;
        break;
      case 2 :
        style = SEGMENT_STYLE;
        lockFar = TRUE;
        break;
      case 3 :
        style = MASTER_STYLE;
        lockFar = TRUE;
        break;
      case 4 :
        style = CONTIG_STYLE;
        lookupFar = TRUE;
        break;
      default :
        break;
    }
  }

  bsp = bvp->bsp;
  entityID = ObjMgrGetEntityIDForPointer (bsp);
  topsep = GetTopSeqEntryForEntityID (entityID);
  LookForGEDetc (topsep, &isGED, &isNTorNWorNG, &isNC, &isTPA, &isAEorCH);
  VisitDescriptorsInSep (topsep, (Pointer) &forceOnlyNearFeats, GbfLookFarFeatFetchPolicy);

  if ((flags & SHOW_CONTIG_FEATURES) != 0 || (flags & SHOW_CONTIG_SOURCES) != 0) {
    if (isNTorNWorNG || isTPA) {
      lockFar = FALSE;
      lookupFar = TRUE;
      if (GetAppProperty ("InternalNcbiSequin") != NULL) {
        doLockFarComponents = TRUE;
      }
    } else {
      lockFar = TRUE;
    }
  }
  if (bvp->hasTargetControl && bvp->ffCustomBtn != NULL) {
    if (GetValue (bvp->ffCustomBtn) == 2) {
      flags |= REFSEQ_CONVENTIONS | SHOW_TRANCRIPTION | SHOW_PEPTIDE | FORCE_PRIMARY_BLOCK | RELAXED_MAPPING;
    }
  }
  if (bvp->hasTargetControl && bvp->ffRifCtrl != NULL) {
    val = GetValue (bvp->ffRifCtrl);
    switch (val) {
      case 1 :
        break;
      case 2 :
        custom |= HIDE_GENE_RIFS;
        break;
      case 3 :
        custom |= ONLY_GENE_RIFS;
        break;
      case 4 :
        custom |= NEWEST_PUBS;
        break;
      case 5 :
        custom |= OLDEST_PUBS;
        break;
      case 6 :
        custom |= ONLY_REVIEW_PUBS;
        break;
      case 7 :
        custom |= HIDE_ALL_PUBS;
        break;
      default :
        break;
    }
  }
  doc = NULL;
  txt = NULL;
  bsp = bvp->bsp;
  if (bvp->useScrollText) {
    txt = bvp->text;
    Reset (txt);
    Update ();
  } else {
    doc = bvp->doc;
    GetScrlParams (doc, NULL, &item, &into);
    sb = GetSlateVScrollBar ((SlatE) doc);
    Reset (doc);
    SetDocShade (doc, NULL, NULL, NULL, NULL);
    SetDocProcs (doc, NULL, NULL, NULL, NULL);
    SetDocCache (doc, NULL, NULL, NULL);
    Update ();
    SetDocAutoAdjust (doc, FALSE);
  }
  if (bsp == NULL) return;
  if (spop == NULL) {
    spop = StdPrintOptionsNew (NULL);
    if (spop != NULL) {
      spop->newline = "\r";
      spop->indent = "";
    } else {
      Message (MSG_ERROR, "StdPrintOptionsNew failed");
    }
  }

  svpp = (SeqViewProcsPtr) GetAppProperty ("SeqDisplayForm");
  if (svpp != NULL) {
    if (svpp->lockFarComponents) {
      doLockFarComponents = TRUE;
    }
  }

  if (mode == ENTREZ_MODE) {
    doLockFarComponents = FALSE;
    lockFar = FALSE;
    lookupFar = FALSE;
    flags = flags ^ (SHOW_CONTIG_FEATURES | SHOW_CONTIG_SOURCES | SHOW_FAR_TRANSLATION);
  }

  if (doLockFarComponents) {
    entityID = ObjMgrGetEntityIDForPointer (bsp);
    sep = GetTopSeqEntryForEntityID (entityID);
    if (bvp->bsplist == NULL && lockFar) {
      bvp->bsplist = LockFarComponentsEx (sep, TRUE, FALSE, FALSE, NULL);
    }
    if (lookupFar) {
      feats_with_product_count = 0;
      sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &context);
      while (sfp != NULL) {
        if (sfp->product != NULL) {
          feats_with_product_count++;
        }
        sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &context);
      }
      if (feats_with_product_count > 500) {
        /* too many to lookup with older caching implementation - now sufficiently fast */
        /*
        lookupFar = FALSE;
        */
      }
    }
    if (lookupFar) {
      hastpaaligns = FALSE;
      hastsaaligns = FALSE;
      VisitDescriptorsInSep (sep, (Pointer) &hastpaaligns, LookForTpa);
      VisitDescriptorsInSep (sep, (Pointer) &hastsaaligns, LookForTsa);
      LookupFarSeqIDs (sep, TRUE, TRUE, TRUE, FALSE, hastpaaligns || hastsaaligns, FALSE, TRUE);
    }
  }

  sep = SeqMgrGetSeqEntryForData (bsp);
  entityID = ObjMgrGetEntityIDForChoice (sep);
  if (bvp->hasTargetControl) {
    if (bvp->viewWholeEntity) {
      sep = GetTopSeqEntryForEntityID (entityID);
      usethetop = sep;
      if (format == FTABLE_FMT) {
        custom |= SHOW_PROT_FTABLE;
      }
    } else if (ISA_na (bsp->mol) && bsp->repr == Seq_repr_seg) {
      sep = GetBestTopParentForData (entityID, bsp);
    } else if (ISA_aa (bsp->mol) && bsp->repr == Seq_repr_seg) {
      sep = GetBestTopParentForData (entityID, bsp);
    }
  } else {
    if (ISA_na (bsp->mol) || bsp->repr == Seq_repr_seg) {
      sep = GetBestTopParentForData (entityID, bsp);
    }
  }
  if (sep == NULL) return;

  topsep = GetTopSeqEntryForEntityID (entityID);
  oldsep = SeqEntrySetScope (topsep);

  WatchCursor ();
  ffColFmt.pixWidth = screenRect.right - screenRect.left;
  ffColFmt.pixInset = 8;
  /* LookForGEDetc (topsep, &isGED, &isNTorNWorNG, &isNC, &isTPA); */
  if ((flags & SHOW_CONTIG_FEATURES) != 0 || (flags & SHOW_CONTIG_SOURCES) != 0) {
    if (forceOnlyNearFeats) {
      flags |= ONLY_NEAR_FEATURES;
    } else if (isNTorNWorNG || isTPA) {
      flags |= ONLY_NEAR_FEATURES;
    } else if (isNC) {
      flags |= NEAR_FEATURES_SUPPRESS;
    } else if (isAEorCH) {
      flags |= NEAR_FEATURES_SUPPRESS;
    }
  }
  if (bvp->useScrollText) {
    TmpNam (path);
    fp = FileOpen (path, "w");
    if (fp != NULL) {
      level = ErrSetMessageLevel (SEV_MAX);
      if (SeqEntryToGnbk (sep, NULL, format, mode, style, flags, 0, custom, NULL, fp)) {
        FileClose (fp);
        if (! FileToScrollText (txt, path)) {
          SetTitle (txt, "(Text is too large to be displayed in this control.)");
        }
      } else if (mode == RELEASE_MODE) {
        str = RelModeFailText (bsp, usethetop, topsep);
        if (str != NULL) {
          fprintf (fp, "%s", str);
        }
        FileClose (fp);
        if (str != NULL) {
          FileToScrollText (txt, path);
        }
        MemFree (str);
      } else {
        FileClose (fp);
      }
      ErrSetMessageLevel (level);
    }
    FileRemove (path);
  } else {
    if (PopulateFF (doc, sep, bsp, usethetop, format, mode, style, flags, custom)) {
      doColors = TRUE;
      /*
      VisitBioseqsInSep (topsep, (Pointer) &doColors, LookForFarBsp);
      if (doColors) {
        VisitFeaturesInSep (topsep, (Pointer) &doColors, LookForFarProds);
      }
      if (doColors) {
        SetDocShade (doc, DrawIcon, NULL, NULL, ColorIcon);
      } else {
        SetDocShade (doc, DrawIcon, NULL, NULL, NULL);
      }
      */
      SetDocShade (doc, DrawIcon, NULL, NULL, NULL);
      SetDocProcs (doc, ClickIcon, NULL, ReleaseIcon, NULL);
      SetDocCache (doc, StdPutDocCache, StdGetDocCache, StdResetDocCache);
      SetDocAutoAdjust (doc, FALSE);
      ForceFormat (doc, item);
      SetDocAutoAdjust (doc, TRUE);
      AdjustDocScroll (doc);
      GetItemParams4 (doc, item, &startsAt, NULL, NULL, NULL, NULL);
      CorrectBarValue (sb, startsAt + into);
      UpdateDocument (doc, 0, 0);
    } else if (mode == RELEASE_MODE) {
      str = RelModeFailText (bsp, usethetop, topsep);
      if (str != NULL) {
        fnt = programFont;
        if (bvp != NULL && bvp->displayFont != NULL) {
          fnt = bvp->displayFont;
        }
        AppendText (doc, str, &ffParFmt, &ffColFmt, fnt);
      }
      MemFree (str);
      UpdateDocument (doc, 0, 0);
    }
  }

  SeqEntrySetScope (oldsep);

  ArrowCursor ();
  Update ();
}

static void PopulateGenBank (BioseqViewPtr bvp)

{
  PopulateFlatFile (bvp, GENBANK_FMT, SHOW_CONTIG_FEATURES | SHOW_CONTIG_SOURCES | SHOW_FAR_TRANSLATION);
}

static void PopulateEMBL (BioseqViewPtr bvp)

{
  if (bvp == NULL) return;
  if (bvp->hasTargetControl) {
    PopulateFlatFile (bvp, EMBL_FMT, 0);
  } else {
    PopulateFlatFile (bvp, EMBL_FMT, 0);
  }
}

static void PopulateDDBJ (BioseqViewPtr bvp)

{
  PopulateFlatFile (bvp, GENBANK_FMT, DDBJ_VARIANT_FORMAT);
}

static void PopulateGenPept (BioseqViewPtr bvp)

{
  PopulateFlatFile (bvp, GENPEPT_FMT, 0);
}

static void PopulateFTable (BioseqViewPtr bvp)

{
  PopulateFlatFile (bvp, FTABLE_FMT, 0);
}

static void PopulateFasta (BioseqViewPtr bvp)

{
  BioseqPtr        bsp;
  DoC              doc;
  Uint2            entityID;
  Boolean          fastaOK;
  Boolean          fastaNucOK;
  Boolean          fastaPrtOK;
  FonT             fnt;
  FILE             *fp;
  Uint1            group_segs;
  Int2             into = 0;
  Int2             item = 0;
  Boolean          master_style;
  Char             path [PATH_MAX];
  BaR              sb = NULL;
  SeqEntryPtr      sep;
  Int4             startsAt = 0;
  SeqViewProcsPtr  svpp;
  TexT             txt;

  if (bvp == NULL) return;
  doc = NULL;
  txt = NULL;
  bsp = bvp->bsp;
  if (bvp->useScrollText) {
    txt = bvp->text;
    Reset (txt);
    Update ();
  } else {
    doc = bvp->doc;
    GetScrlParams (doc, NULL, &item, &into);
    sb = GetSlateVScrollBar ((SlatE) doc);
    Reset (doc);
    SetDocShade (doc, NULL, NULL, NULL, NULL);
    SetDocProcs (doc, NULL, NULL, NULL, NULL);
    SetDocCache (doc, NULL, NULL, NULL);
    Update ();
    SetDocAutoAdjust (doc, FALSE);
  }
  if (bsp == NULL) return;

  svpp = (SeqViewProcsPtr) GetAppProperty ("SeqDisplayForm");
  if (svpp != NULL && svpp->lockFarComponents) {
    entityID = ObjMgrGetEntityIDForPointer (bsp);
    sep = GetTopSeqEntryForEntityID (entityID);
    if (bvp->bsplist == NULL) {
      bvp->bsplist = LockFarComponentsEx (sep, TRUE, FALSE, FALSE, NULL);
    }
  }

  sep = SeqMgrGetSeqEntryForData (bsp);
  if (bvp->hasTargetControl) {
    if (bvp->viewWholeEntity) {
      entityID = ObjMgrGetEntityIDForChoice (sep);
      sep = GetTopSeqEntryForEntityID (entityID);
    }
  } else {
    if (ISA_na (bsp->mol) || bsp->repr == Seq_repr_seg) {
      entityID = ObjMgrGetEntityIDForChoice (sep);
      sep = GetBestTopParentForData (entityID, bsp);
    }
  }
  if (sep == NULL) return;

  WatchCursor ();
  ffColFmt.pixWidth = screenRect.right - screenRect.left;
  ffColFmt.pixInset = 8;
  TmpNam (path);
  fp = FileOpen (path, "w");
  if (fp != NULL) {
    fnt = programFont;
    if (bvp != NULL && bvp->displayFont != NULL) {
      fnt = bvp->displayFont;
    }
    fastaOK = FALSE;
    fastaNucOK = FALSE;
    fastaPrtOK = FALSE;
    if (ISA_na (bsp->mol)) {TRUE, 
      group_segs = 0;
      master_style = FALSE;
      if (bvp->hasTargetControl) {
        if (bvp->viewWholeEntity) {
          if (bsp->repr == Seq_repr_seg) {
            group_segs = 2;
          }
          /*
          fastaNucOK = SeqEntrysToFasta (sep, fp, TRUE, group_segs);
          fastaPrtOK = SeqEntrysToFasta (sep, fp, FALSE, 0);
          */
          if (SeqEntryFastaStream (sep, fp, STREAM_EXPAND_GAPS | STREAM_CORRECT_INVAL, 
              70, 0, 0, TRUE, FALSE, master_style) > 0)
          {
            fastaNucOK = TRUE;
          }
          else 
          {
            fastaNucOK = FALSE;
          }
          if (SeqEntryFastaStream (sep, fp, STREAM_EXPAND_GAPS | STREAM_CORRECT_INVAL, 
              70, 0, 0, FALSE, TRUE, master_style) > 0)
          {
            fastaPrtOK = TRUE;
          }
          else
          {
            fastaPrtOK = FALSE;
          }
          fastaOK = fastaNucOK || fastaPrtOK;
        } else {
          if (bsp->repr == Seq_repr_seg) {
            group_segs = 1;
            master_style = TRUE;
          } else if (bsp->repr == Seq_repr_delta) {
            group_segs = 3;
          }
          /*
          fastaOK = SeqEntrysToFasta (sep, fp, TRUE, group_segs);
          */
          if (SeqEntryFastaStream (sep, fp, STREAM_EXPAND_GAPS | STREAM_CORRECT_INVAL,
               70, 0, 0, TRUE, FALSE, master_style) > 0)
          {
            fastaOK = TRUE;
          }
          else
          {
            fastaOK = FALSE;
          }
        }
      } else {
        if (bsp->repr == Seq_repr_seg) {
          group_segs = 1;
          master_style = TRUE;
        } else if (bsp->repr == Seq_repr_delta) {
          group_segs = 3;
        }
        /*
        fastaOK = SeqEntrysToFasta (sep, fp, TRUE, group_segs);
        */
        if (SeqEntryFastaStream (sep, fp, STREAM_EXPAND_GAPS | STREAM_CORRECT_INVAL,
                                 70, 0, 0, TRUE, FALSE, master_style) > 0)
        {
          fastaOK = TRUE;
        }
        else
        {
          fastaOK = FALSE;
        }
      }
    } else if (ISA_aa (bsp->mol)) {
      /*
      fastaOK = SeqEntrysToFasta (sep, fp, FALSE, 0);
      */
      if (SeqEntryFastaStream (sep, fp, STREAM_EXPAND_GAPS | STREAM_CORRECT_INVAL,
                               70, 0, 0, FALSE, TRUE, FALSE) > 0)
      {
        fastaOK = TRUE;
      }
      else
      {
        fastaOK = FALSE;
      }
    }
    if (fastaOK) {
      FileClose (fp);
      if (bvp->useScrollText) {
        if (! FileToScrollText (txt, path)) {
          SetTitle (txt, "(Text is too large to be displayed in this control.)");
        }
      } else {
        DisplayFancy (doc, path, &ffParFmt, &ffColFmt, fnt, 4);
        SetDocCache (doc, StdPutDocCache, StdGetDocCache, StdResetDocCache);
        SetDocAutoAdjust (doc, FALSE);
        ForceFormat (doc, item);
        SetDocAutoAdjust (doc, TRUE);
        AdjustDocScroll (doc);
        GetItemParams4 (doc, item, &startsAt, NULL, NULL, NULL, NULL);
        CorrectBarValue (sb, startsAt + into);
        UpdateDocument (doc, 0, 0);
      }
    } else {
      FileClose (fp);
    }
  }
  FileRemove (path);
  ArrowCursor ();
  Update ();
}

static void PrintQualProc (CharPtr buf, Uint4 buflen, Pointer userdata)

{
  FILE  *fp;

  fp = (FILE*) userdata;
  fprintf (fp, "%s", buf);
}

static void PrintQualScoresProc (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)

{
  BioseqPtr  bsp;
  FILE       *fp;

  if (! IS_Bioseq (sep)) return;
  bsp = (BioseqPtr) sep->data.ptrvalue;
  if (bsp == NULL) return;
  fp = (FILE*) mydata;
  PrintQualityScoresToBuffer (bsp, FALSE, fp, PrintQualProc);
}

static void PrintFarQualScoresProc (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)

{
  BioseqPtr  bsp;
  FILE       *fp;

  if (! IS_Bioseq (sep)) return;
  bsp = (BioseqPtr) sep->data.ptrvalue;
  if (bsp == NULL) return;
  fp = (FILE*) mydata;
  PrintQualityScoresForContig (bsp, FALSE, fp);
}

static void PopulateQuality (BioseqViewPtr bvp)

{
  BioseqPtr    bsp;
  DoC          doc;
  Uint2        entityID;
  FonT         fnt;
  FILE         *fp;
  Int2         into;
  Int2         item = 0;
  Char         path [PATH_MAX];
  BaR          sb = NULL;
  SeqEntryPtr  sep;
  Int4         startsAt;
  TexT         txt;

  if (bvp == NULL) return;
  doc = NULL;
  txt = NULL;
  bsp = bvp->bsp;
  if (bvp->useScrollText) {
    txt = bvp->text;
    Reset (txt);
    Update ();
  } else {
    doc = bvp->doc;
    GetScrlParams (doc, NULL, &item, &into);
    sb = GetSlateVScrollBar ((SlatE) doc);
    Reset (doc);
    SetDocShade (doc, NULL, NULL, NULL, NULL);
    SetDocProcs (doc, NULL, NULL, NULL, NULL);
    SetDocCache (doc, NULL, NULL, NULL);
    Update ();
    SetDocAutoAdjust (doc, FALSE);
  }
  if (bsp == NULL) return;
  sep = SeqMgrGetSeqEntryForData (bsp);
  if (bvp->hasTargetControl) {
    if (bvp->viewWholeEntity) {
      entityID = ObjMgrGetEntityIDForChoice (sep);
      sep = GetTopSeqEntryForEntityID (entityID);
    }
  } else {
    if (ISA_na (bsp->mol) || bsp->repr == Seq_repr_seg) {
      entityID = ObjMgrGetEntityIDForChoice (sep);
      sep = GetBestTopParentForData (entityID, bsp);
    }
  }
  if (sep == NULL) return;

  WatchCursor ();
  ffColFmt.pixWidth = screenRect.right - screenRect.left;
  ffColFmt.pixInset = 8;
  TmpNam (path);
  fp = FileOpen (path, "w");
  if (fp != NULL) {
    fnt = programFont;
    if (bvp != NULL && bvp->displayFont != NULL) {
      fnt = bvp->displayFont;
    }
    if (VisitGraphsInSep (sep, NULL, NULL) > 0) {
      SeqEntryExplore (sep, (Pointer) fp, PrintQualScoresProc);
    } else if (bsp->repr == Seq_repr_delta) {
      SeqEntryExplore (sep, (Pointer) fp, PrintFarQualScoresProc);
    } else {
      SeqEntryExplore (sep, (Pointer) fp, PrintQualScoresProc);
    }
    FileClose (fp);
    if (bvp->useScrollText) {
      if (! FileToScrollText (txt, path)) {
        SetTitle (txt, "(Text is too large to be displayed in this control.)");
      }
    } else {
      DisplayFancy (doc, path, &ffParFmt, &ffColFmt, fnt, 4);
      SetDocCache (doc, StdPutDocCache, StdGetDocCache, StdResetDocCache);
      SetDocAutoAdjust (doc, FALSE);
      ForceFormat (doc, item);
      SetDocAutoAdjust (doc, TRUE);
      AdjustDocScroll (doc);
      GetItemParams4 (doc, item, &startsAt, NULL, NULL, NULL, NULL);
      CorrectBarValue (sb, startsAt + into);
      UpdateDocument (doc, 0, 0);
    }
  }
  FileRemove (path);
  ArrowCursor ();
  Update ();
}

NLM_EXTERN void AsnPrintNewLine PROTO((AsnIoPtr aip));

static void PopulateAsnOrXML (BioseqViewPtr bvp, CharPtr outmode, Boolean doGbseq)

{
  AsnIoPtr     aipout = NULL;
  AsnTypePtr   atp = NULL;
  BioseqPtr    bsp;
  CstType      custom = 0;
  DoC          doc;
  Uint2        entityID;
  XtraPtr      extra = NULL;
  FlgType      flags = CREATE_XML_GBSEQ_FILE;
  FonT         fnt;
  FmtType      format = GENBANK_FMT;
  GBSeq        gbsq;
  GBSet        gbst;
  Int2         into = 0;
  Int2         item = 0;
  Boolean      lockFar = FALSE;
  Boolean      lookupFar = FALSE;
  ModType      mode = SEQUIN_MODE;
  Char         path [PATH_MAX];
  BaR          sb = NULL;
  SeqEntryPtr  sep;
  Int4         startsAt = 0;
  StlType      style = NORMAL_STYLE;
  TexT         txt;
  Int2         val;
  Char         xmlbuf [128];
  XtraBlock    xtra;

  if (bvp == NULL) return;
  doc = NULL;
  txt = NULL;
  bsp = bvp->bsp;
  if (bvp->useScrollText) {
    txt = bvp->text;
    Reset (txt);
    Update ();
  } else {
    doc = bvp->doc;
    GetScrlParams (doc, NULL, &item, &into);
    sb = GetSlateVScrollBar ((SlatE) doc);
    Reset (doc);
    SetDocShade (doc, NULL, NULL, NULL, NULL);
    SetDocProcs (doc, NULL, NULL, NULL, NULL);
    SetDocCache (doc, NULL, NULL, NULL);
    Update ();
    SetDocAutoAdjust (doc, FALSE);
  }
  if (bsp == NULL) return;
  sep = SeqMgrGetSeqEntryForData (bsp);
  if (bvp->hasTargetControl) {
    if (bvp->viewWholeEntity) {
      entityID = ObjMgrGetEntityIDForChoice (sep);
      sep = GetTopSeqEntryForEntityID (entityID);
    }
  } else {
    if (ISA_na (bsp->mol) || bsp->repr == Seq_repr_seg) {
      entityID = ObjMgrGetEntityIDForChoice (sep);
      sep = GetBestTopParentForData (entityID, bsp);
    }
  }
  if (sep == NULL) return;

  WatchCursor ();
  ffColFmt.pixWidth = screenRect.right - screenRect.left;
  ffColFmt.pixInset = 8;
  TmpNam (path);
  aipout = AsnIoOpen (path, outmode);
  fnt = programFont;
  if (bvp != NULL && bvp->displayFont != NULL) {
    fnt = bvp->displayFont;
  }
  if (bsp != NULL && ISA_aa (bsp->mol)) {
    format = GENPEPT_FMT;
  }
  if (doGbseq && aipout != NULL) {
    if (bvp->hasTargetControl && bvp->ffModeCtrl != NULL) {
      val = GetValue (bvp->ffModeCtrl);
      switch (val) {
        case 1 :
          mode = RELEASE_MODE;
          break;
        case 2 :
          mode = ENTREZ_MODE;
          break;
        case 3 :
          mode = SEQUIN_MODE;
          break;
        case 4 :
          mode = DUMP_MODE;
          break;
        default :
          break;
      }
    }
    /* now using control instead of seqid type */
    if (bvp->ffStyleCtrl != NULL) {
      val = GetValue (bvp->ffStyleCtrl);
      switch (val) {
        case 1 :
          style = NORMAL_STYLE;
          lookupFar = TRUE;
          break;
        case 2 :
          style = SEGMENT_STYLE;
          lockFar = TRUE;
          break;
        case 3 :
          style = MASTER_STYLE;
          lockFar = TRUE;
          break;
        case 4 :
          style = CONTIG_STYLE;
          lookupFar = TRUE;
          break;
        default :
          break;
      }
    }
    if (bvp->hasTargetControl && bvp->ffCustomBtn != NULL) {
      if (GetValue (bvp->ffCustomBtn) == 2) {
        flags = REFSEQ_CONVENTIONS | SHOW_TRANCRIPTION | SHOW_PEPTIDE | FORCE_PRIMARY_BLOCK | RELAXED_MAPPING;
      }
    }
    if (bvp->hasTargetControl && bvp->ffRifCtrl != NULL) {
      val = GetValue (bvp->ffRifCtrl);
      switch (val) {
        case 1 :
          break;
        case 2 :
          custom |= HIDE_GENE_RIFS;
          break;
        case 3 :
          custom |= ONLY_GENE_RIFS;
          break;
        case 4 :
          custom |= NEWEST_PUBS;
          break;
        case 5 :
          custom |= OLDEST_PUBS;
          break;
        case 6 :
          custom |= ONLY_REVIEW_PUBS;
          break;
        case 7 :
          custom |= HIDE_ALL_PUBS;
          break;
        default :
          break;
      }
    }
    if (GetAppParam ("NCBI", "SETTINGS", "XMLPREFIX", NULL, xmlbuf, sizeof (xmlbuf))) {
      AsnSetXMLmodulePrefix (StringSave (xmlbuf));
    }
    objgbseqAsnLoad ();
    objinsdseqAsnLoad ();
    MemSet ((Pointer) &xtra, 0, sizeof (XtraBlock));
    MemSet ((Pointer) &gbsq, 0, sizeof (GBSeq));
    xtra.gbseq = &gbsq;
    xtra.aip = aipout;
    /*
    atp = AsnLinkType (NULL, AsnFind ("GBSet"));
    xtra.atp = AsnLinkType (NULL, AsnFind ("GBSet.E"));
    */
    atp = AsnLinkType (NULL, AsnFind ("INSDSet"));
    xtra.atp = AsnLinkType (NULL, AsnFind ("INSDSet.E"));
    extra = &xtra;
    MemSet ((Pointer) &gbst, 0, sizeof (GBSet));
    AsnOpenStruct (aipout, atp, (Pointer) &gbst);
    if (SeqEntryToGnbk (sep, NULL, format, mode, style, flags, 0, custom, extra, NULL)) {
      AsnCloseStruct (aipout, atp, NULL);
      AsnPrintNewLine (aipout);
      AsnIoClose (aipout);
      if (bvp->useScrollText) {
        if (! FileToScrollText (txt, path)) {
          SetTitle (txt, "(Text is too large to be displayed in this control.)");
        }
      } else {
        DisplayFancy (doc, path, &ffParFmt, &ffColFmt, fnt, 4);
        SetDocCache (doc, StdPutDocCache, StdGetDocCache, StdResetDocCache);
        SetDocAutoAdjust (doc, FALSE);
        ForceFormat (doc, item);
        SetDocAutoAdjust (doc, TRUE);
        AdjustDocScroll (doc);
        GetItemParams4 (doc, item, &startsAt, NULL, NULL, NULL, NULL);
        CorrectBarValue (sb, startsAt + into);
        UpdateDocument (doc, 0, 0);
      }
    } else {
      AsnIoClose (aipout);
    }
  } else if (aipout != NULL) {
    if (SeqEntryAsnWrite (sep, aipout, NULL)) {
      AsnIoClose (aipout);
      if (bvp->useScrollText) {
        if (! FileToScrollText (txt, path)) {
          SetTitle (txt, "(Text is too large to be displayed in this control.)");
        }
      } else {
        DisplayFancy (doc, path, &ffParFmt, &ffColFmt, fnt, 4);
        SetDocCache (doc, StdPutDocCache, StdGetDocCache, StdResetDocCache);
        SetDocAutoAdjust (doc, FALSE);
        ForceFormat (doc, item);
        SetDocAutoAdjust (doc, TRUE);
        AdjustDocScroll (doc);
        GetItemParams4 (doc, item, &startsAt, NULL, NULL, NULL, NULL);
        CorrectBarValue (sb, startsAt + into);
        UpdateDocument (doc, 0, 0);
      }
    } else {
      AsnIoClose (aipout);
    }
  }
  FileRemove (path);
  ArrowCursor ();
  Update ();
}

static void PopulateXML (BioseqViewPtr bvp)

{
  PopulateAsnOrXML (bvp, "wx", FALSE);
}

static void PopulateAsn (BioseqViewPtr bvp)

{
  PopulateAsnOrXML (bvp, "w", FALSE);
}

static void PopulateGBSeq (BioseqViewPtr bvp)

{
  PopulateAsnOrXML (bvp, "wx", TRUE);
}

static void ShowFlatFile (BioseqViewPtr bvp, Boolean show)

{
  if (bvp == NULL) return;
  if (show) {
    if (bvp->useScrollText) {
      SafeShow (bvp->text);
    } else {
      SafeShow (bvp->doc);
    }
    SafeShow (bvp->baseCtgControlGrp);
    SafeShow (bvp->modeControlGrp);
    SafeShow (bvp->extraControlGrp);
    SafeShow (bvp->docTxtControlGrp);
    SafeShow (bvp->clickMe);
  } else {
    SafeHide (bvp->text);
    SafeHide (bvp->doc);
    Reset (bvp->text);
    Reset (bvp->doc);
    SetDocShade (bvp->doc, NULL, NULL, NULL, NULL);
    SetDocProcs (bvp->doc, NULL, NULL, NULL, NULL);
    SetDocCache (bvp->doc, NULL, NULL, NULL);
    SafeHide (bvp->styleControlGrp);
    SafeHide (bvp->scaleControlGrp);
    EnableDisableLegendItem (bvp, FALSE);
    SafeHide (bvp->findGeneGrp);
    SafeHide (bvp->docTxtControlGrp);
    SafeHide (bvp->baseCtgControlGrp);
    SafeHide (bvp->modeControlGrp);
    SafeHide (bvp->extraControlGrp);
    SafeHide (bvp->newGphControlGrp);
    SafeHide (bvp->clickMe);
  }
}

static void ShowFastaOrAsn (BioseqViewPtr bvp, Boolean show)

{
  if (bvp == NULL) return;
  if (show) {
    if (bvp->useScrollText) {
      SafeShow (bvp->text);
    } else {
      SafeShow (bvp->doc);
    }
    SafeHide (bvp->modeControlGrp);
    SafeHide (bvp->baseCtgControlGrp);
    SafeHide (bvp->extraControlGrp);
    SafeShow (bvp->docTxtControlGrp);
    SafeHide (bvp->clickMe);
  } else {
    SafeHide (bvp->text);
    SafeHide (bvp->doc);
    Reset (bvp->text);
    Reset (bvp->doc);
    SetDocShade (bvp->doc, NULL, NULL, NULL, NULL);
    SetDocProcs (bvp->doc, NULL, NULL, NULL, NULL);
    SetDocCache (bvp->doc, NULL, NULL, NULL);
    SafeHide (bvp->styleControlGrp);
    SafeHide (bvp->scaleControlGrp);
    EnableDisableLegendItem (bvp, FALSE);
    SafeHide (bvp->findGeneGrp);
    SafeHide (bvp->docTxtControlGrp);
    SafeHide (bvp->baseCtgControlGrp);
    SafeHide (bvp->modeControlGrp);
    SafeHide (bvp->extraControlGrp);
    SafeHide (bvp->newGphControlGrp);
    SafeHide (bvp->clickMe);
  }
}

static void ShowGBSeq (BioseqViewPtr bvp, Boolean show)

{
  if (bvp == NULL) return;
  if (show) {
    if (bvp->useScrollText) {
      SafeShow (bvp->text);
    } else {
      SafeShow (bvp->doc);
    }
    SafeShow (bvp->modeControlGrp);
    SafeShow (bvp->baseCtgControlGrp);
    SafeShow (bvp->extraControlGrp);
    SafeShow (bvp->docTxtControlGrp);
    SafeHide (bvp->clickMe);
  } else {
    SafeHide (bvp->text);
    SafeHide (bvp->doc);
    Reset (bvp->text);
    Reset (bvp->doc);
    SetDocShade (bvp->doc, NULL, NULL, NULL, NULL);
    SetDocProcs (bvp->doc, NULL, NULL, NULL, NULL);
    SetDocCache (bvp->doc, NULL, NULL, NULL);
    SafeHide (bvp->styleControlGrp);
    SafeHide (bvp->scaleControlGrp);
    EnableDisableLegendItem (bvp, FALSE);
    SafeHide (bvp->findGeneGrp);
    SafeHide (bvp->docTxtControlGrp);
    SafeHide (bvp->baseCtgControlGrp);
    SafeHide (bvp->modeControlGrp);
    SafeHide (bvp->extraControlGrp);
    SafeHide (bvp->newGphControlGrp);
    SafeHide (bvp->clickMe);
  }
}

static void SelectFlatFile (BioseqViewPtr bvp, Uint2 selentityID, Uint4 selitemID,
                            Uint2 selitemtype, SeqLocPtr region,
                            Boolean select, Boolean scrollto)

{
  Int2           bottom = 0;
  DoC            doc;
  DocDescrPtr    dsp;
  FlatStructPtr  fsp;
  Uint2          entityID;
  Uint4          itemID;
  Uint2          itemtype;
  Int2           item;
  Boolean        needToScroll;
  Int2           numItems;
  RecT           rct;
  BaR            sb;
  Int2           scrollhere;
  Int4           startsAt;
  WindoW         tempPort;
  CharPtr        text;
  Int2           top = 0;

  if (bvp == NULL) return;
  if (! bvp->highlightSelections) return;
  if (bvp->useScrollText) return;
  doc = bvp->doc;
  if (doc == NULL) return;
  tempPort = SavePort (doc);
  Select (doc);
  GetDocParams (doc, &numItems, NULL);
  needToScroll = TRUE;
  scrollhere = 0;
  fsp = (FlatStructPtr) GetDocData (doc);
  if (fsp != NULL && fsp->descr != NULL && fsp->numdescr > 0) {
    if (GetScrlParams (doc, NULL, &item, NULL)) {
      while (item <= numItems && ItemIsVisible (doc, item, &top, &bottom, NULL)) {
        if (GetIDsFromDoc (doc, item, &entityID, &itemID, &itemtype)) {
          if (entityID == selentityID &&
              itemID == selitemID &&
              itemtype == selitemtype) {
            needToScroll = FALSE;
            ObjectRect (doc, &rct);
            InsetRect (&rct, 4, 4);
            rct.right = rct.left + 4;
            rct.top = top;
            rct.bottom = bottom;
            InsetRect (&rct, -1, -1);
            InvalRect (&rct);
          }
        }
        item++;
      }
    }
    dsp = FindFFPDocDescr (fsp->descr, fsp->numdescr,
                           selentityID, selitemID, selitemtype);
    scrollhere = 0;
    if (dsp != NULL) {
      scrollhere = dsp->docitem;
    }
    if (scrollhere > 0) {
      if (ItemIsVisible (doc, scrollhere, &top, &bottom, NULL)) {
        needToScroll = FALSE;
      }
      ObjectRect (doc, &rct);
      InsetRect (&rct, 4, 4);
      rct.right = rct.left + 4;
      rct.top = top;
      rct.bottom = bottom;
      InsetRect (&rct, -1, -1);
      InvalRect (&rct);
    } else if (selitemtype == OBJ_BIOSEQ) { /* not preindexed in fsp descr */
      ObjectRect (doc, &rct);
      InsetRect (&rct, 4, 4);
      rct.right = rct.left + 4;
      rct.top = top;
      rct.bottom = bottom;
      InsetRect (&rct, -1, -1);
      InvalRect (&rct);
    }
  }
  /* for items currently not preindexed (LOCUS, ORGANISM), do a short linear search */
  if (/* scrollhere == 0 && */ selitemID > 0 /* && needToScroll */) {
    for (item = 1; item <= numItems && item < 10; item++) {
      if (GetIDsFromDoc (doc, item, &entityID, &itemID, &itemtype)) {
        if (entityID == selentityID &&
            itemID == selitemID &&
            itemtype == selitemtype) {
          /*
          if (ItemIsVisible (doc, item, &top, &bottom, NULL)) {
            needToScroll = FALSE;
            ObjectRect (doc, &rct);
            InsetRect (&rct, 4, 4);
            rct.right = rct.left + 4;
            rct.top = top;
            rct.bottom = bottom;
            InsetRect (&rct, -1, -1);
            InvalRect (&rct);
          } else if (scrollhere == 0) {
            scrollhere = item;
          }
          */
          if (needToScroll) {
            scrollhere = item;
            item = 10; /* break the for loop */
          }
        }
      }
    }
  }
  if (scrollto && needToScroll && scrollhere > 0 && selitemtype != OBJ_BIOSEQ) {
    text = GetDocText (doc, scrollhere, 0, 1); /* forces format if not before */
    MemFree (text);
    ForceFormat (doc, scrollhere); /* forces UpdateLineStarts */
    GetItemParams4 (doc, scrollhere, &startsAt, NULL, NULL, NULL, NULL);
    sb = GetSlateVScrollBar ((SlatE) doc);
    CorrectBarValue (sb, startsAt);
    ObjectRect (doc, &rct);
    InsetRect (&rct, 4, 4);
    InsetRect (&rct, -1, -1);
    InvalRect (&rct);
  }
  RestorePort (tempPort);
}

static void CopyFlatFileFastaOrAsn (BioseqViewPtr bvp)

{
  FILE  *fp;
  Char  path [PATH_MAX];

  if (bvp == NULL) return;
  if (bvp->useScrollText) {
    if (bvp->text != NULL) {
      CopyText (bvp->text);
    }
  } else {
    TmpNam (path);
    fp = FileOpen (path, "w");
    if (fp != NULL) {
      SaveDocument (bvp->doc, fp);
      FileClose (fp);
      FileToClipboard (path);
    }
    FileRemove (path);
  }
}

#ifdef WIN_MOTIF
extern CharPtr Nlm_XrmGetResource (const Char PNTR _resource);
#endif

static void PrintFlatFileFastaOrAsn (BioseqViewPtr bvp)

{
  DoC      doc;
  TexT     txt;
#ifdef WIN_MOTIF
  Char     cmmd [256];
  Int2     len;
  CharPtr  printCmd;
  Char     str [PATH_MAX];
#endif

  if (bvp == NULL) return;
  if (bvp->bsp == NULL) return;
  doc = NULL;
  txt = NULL;
  if (bvp->useScrollText) {
    txt = bvp->text;
  } else {
    doc = bvp->doc;
  }
  if (doc != NULL) {
    PrintDocument (doc);
  } else if (txt != NULL) {
#ifdef WIN_MOTIF
    TmpNam (str);
    ScrollTextToFile (txt, str);
    printCmd = Nlm_XrmGetResource ("printCommand");
    if (printCmd != NULL) {
      StringNCpy_0 (cmmd, printCmd, sizeof (cmmd) - 1);
    } else {
      StringCpy (cmmd, "lp -c");
    }
    MemFree (printCmd);
    len = (Int2) StringLen (cmmd);
    while (len > 0 && cmmd [len] == ' ') {
      cmmd [len] = '\0';
      len--;
    }
    StringCat (cmmd, " ");
    StringCat (cmmd, str);
    StringCat (cmmd, "; rm ");
    StringCat (cmmd, str);
    system (cmmd);
    /*
    FileRemove (str);
    */
#endif
  }
}

static void ExportFlatFileFastaOrAsnEx (BioseqViewPtr bvp, CharPtr filename, CharPtr dfault, Boolean specialSave)

{
  Char     ch;
  Char     dfaultFile [32];
  DoC      doc;
  FILE     *f;
  Int2     i;
  Int2     j;
  Int2     k;
  Int2     numItems;
  Char     path [PATH_MAX];
  CharPtr  str;
  TexT     txt;

  if (bvp == NULL) return;
  if (bvp->bsp == NULL) return;
  doc = NULL;
  txt = NULL;
  if (bvp->useScrollText) {
    txt = bvp->text;
  } else {
    doc = bvp->doc;
  }
  if (doc != NULL || txt != NULL) {
    dfault [0] = '\0';
    StringNCpy_0 (dfaultFile, dfault, sizeof (dfaultFile));
    j = 0;
    k = 0;
    ch = dfaultFile [j];
    while (j < sizeof (dfaultFile) && ch != '\0') {
      if (ch <= ' ') {
        j++;
      } else {
        dfaultFile [k] = dfaultFile [j];
        k++;
        j++;
      }
      ch = dfaultFile [j];
    }
    dfaultFile [k] = '\0';
#ifdef WIN_MSWIN
    j = 0;
    ch = dfaultFile [j];
    while (j < sizeof (dfaultFile) && ch != '\0') {
      if (ch == '_' || IS_ALPHANUM (ch)) {
        j++;
        ch = dfaultFile [j];
      } else {
        ch = '\0';
      }
    }
    dfaultFile [j] = '\0';
#endif
    path [0] = '\0';
    StringNCpy_0 (path, filename, sizeof (path));
    if (path [0] != '\0' || GetOutputFileName (path, sizeof (path), dfaultFile)) {
      WatchCursor ();
#ifdef WIN_MAC
      f = FileOpen (path, "r");
      if (f != NULL) {
        FileClose (f);
      } else {
        FileCreate (path, "TEXT", "ttxt");
      }
#endif
      if (filename == NULL || filename [0] == '\0') {
        f = FileOpen (path, "w");
      } else {
        f = FileOpen (path, "a");
      }
      if (f != NULL) {
        if (bvp->useScrollText) {
          ScrollTextToFile (txt, path);
        } else if (specialSave) {
          GetDocParams (doc, &numItems, NULL);
          for (i = 1; i <= numItems; i++) {
            str = GetDocText (doc, i, 0, 0);
            if (! StringHasNoText (str)) {
              fprintf (f, "%s", str);
            }
            MemFree (str);
          }
        } else {
          SaveDocument (doc, f);
        }
        FileClose (f);
      }
      ArrowCursor ();
    }
  }
}

static void ExportFlatFileFastaOrAsn (BioseqViewPtr bvp, CharPtr filename, CharPtr dfault)

{
  ExportFlatFileFastaOrAsnEx (bvp, filename, dfault, FALSE);
}

static void ExportFeatureTable (BioseqViewPtr bvp, CharPtr filename, CharPtr dfault)

{
  ExportFlatFileFastaOrAsnEx (bvp, filename, dfault, TRUE);
}

static CharPtr asnconfirmmsg =
"'Export' saves only the targeted portion of the record.\n\
Use 'Save' to save the entire record to a file, so that\n\
it can be submitted to the database.  Proceed with export?";

static void ExportAsnAfterConfirming (BioseqViewPtr bvp, CharPtr filename, CharPtr dfault)

{
  MsgAnswer  ans;

  if (bvp->hasTargetControl) {
    ans = Message (MSG_YN, "%s", asnconfirmmsg);
    if (ans == ANS_NO) return;
  }
  ExportFlatFileFastaOrAsn (bvp, filename, dfault);
}

static void ResizeFlatFileFastaOrAsn (BioseqViewPtr bvp)

{
  if (bvp == NULL) return;
  if (bvp->doc != NULL) {
    if (Visible (bvp->doc) && AllParentsVisible (bvp->doc)) {
      UpdateDocument (bvp->doc, 0, 0);
    }
  }
}

BioseqPageData gbgnPageData = {
  "GenBank", FALSE, FALSE, TRUE, FALSE, -1,
  PopulateGenBank, ShowFlatFile, SelectFlatFile,
  CopyFlatFileFastaOrAsn, PrintFlatFileFastaOrAsn,
  ExportFlatFileFastaOrAsn, NULL, ResizeFlatFileFastaOrAsn, NULL
};

BioseqPageData gnbkPageData = {
  "GenBank", TRUE, FALSE, FALSE, FALSE, -1,
  PopulateGenBank, ShowFlatFile, SelectFlatFile,
  CopyFlatFileFastaOrAsn, PrintFlatFileFastaOrAsn,
  ExportFlatFileFastaOrAsn, NULL, ResizeFlatFileFastaOrAsn, NULL
};

BioseqPageData emblPageData = {
  "EMBL", TRUE, FALSE, FALSE, FALSE, -1,
  PopulateEMBL, ShowFlatFile, SelectFlatFile,
  CopyFlatFileFastaOrAsn, PrintFlatFileFastaOrAsn,
  ExportFlatFileFastaOrAsn, NULL, ResizeFlatFileFastaOrAsn, NULL
};

BioseqPageData ddbjPageData = {
  "DDBJ", TRUE, FALSE, FALSE, FALSE, -1,
  PopulateDDBJ, ShowFlatFile, SelectFlatFile,
  CopyFlatFileFastaOrAsn, PrintFlatFileFastaOrAsn,
  ExportFlatFileFastaOrAsn, NULL, ResizeFlatFileFastaOrAsn, NULL
};

BioseqPageData gnptPageData = {
  "GenPept", FALSE, TRUE, FALSE, FALSE, -1,
  PopulateGenPept, ShowFlatFile, SelectFlatFile,
  CopyFlatFileFastaOrAsn, PrintFlatFileFastaOrAsn,
  ExportFlatFileFastaOrAsn, NULL, ResizeFlatFileFastaOrAsn, NULL
};

BioseqPageData ftblPageData = {
  "Table", TRUE, TRUE, TRUE, FALSE, -1,
  PopulateFTable, ShowFlatFile, SelectFlatFile,
  CopyFlatFileFastaOrAsn, PrintFlatFileFastaOrAsn,
  ExportFeatureTable, NULL, ResizeFlatFileFastaOrAsn, NULL
};

BioseqPageData fstaPageData = {
  "FASTA", TRUE, TRUE, TRUE, FALSE, -1,
  PopulateFasta, ShowFastaOrAsn, NULL,
  CopyFlatFileFastaOrAsn, PrintFlatFileFastaOrAsn,
  ExportFlatFileFastaOrAsn, NULL, ResizeFlatFileFastaOrAsn, NULL
};

BioseqPageData qualPageData = {
  "Quality", TRUE, TRUE, FALSE, FALSE, -1,
  PopulateQuality, ShowFastaOrAsn, NULL,
  CopyFlatFileFastaOrAsn, PrintFlatFileFastaOrAsn,
  ExportFlatFileFastaOrAsn, NULL, ResizeFlatFileFastaOrAsn, NULL
};

BioseqPageData asnPageData = {
  "ASN.1", TRUE, TRUE, TRUE, FALSE, -1,
  PopulateAsn, ShowFastaOrAsn, NULL,
  CopyFlatFileFastaOrAsn, PrintFlatFileFastaOrAsn,
  ExportAsnAfterConfirming, NULL, ResizeFlatFileFastaOrAsn, NULL
};

BioseqPageData xmlPageData = {
  "XML", TRUE, TRUE, TRUE, FALSE, -1,
  PopulateXML, ShowFastaOrAsn, NULL,
  CopyFlatFileFastaOrAsn, PrintFlatFileFastaOrAsn,
  ExportAsnAfterConfirming, NULL, ResizeFlatFileFastaOrAsn, NULL
};

BioseqPageData gbseqPageData = {
  "INSDSeq", TRUE, TRUE, TRUE, FALSE, -1,
  PopulateGBSeq, ShowGBSeq, NULL,
  CopyFlatFileFastaOrAsn, PrintFlatFileFastaOrAsn,
  ExportAsnAfterConfirming, NULL, ResizeFlatFileFastaOrAsn, NULL
};

