NCBI C Toolkit Cross Reference

C/api/asn2gnb3.c


  1 /*   asn2gnb3.c
  2 * ===========================================================================
  3 *
  4 *                            PUBLIC DOMAIN NOTICE
  5 *            National Center for Biotechnology Information (NCBI)
  6 *
  7 *  This software/database is a "United States Government Work" under the
  8 *  terms of the United States Copyright Act.  It was written as part of
  9 *  the author's official duties as a United States Government employee and
 10 *  thus cannot be copyrighted.  This software/database is freely available
 11 *  to the public for use. The National Library of Medicine and the U.S.
 12 *  Government do not place any restriction on its use or reproduction.
 13 *  We would, however, appreciate having the NCBI and the author cited in
 14 *  any work or product based on this material
 15 *
 16 *  Although all reasonable efforts have been taken to ensure the accuracy
 17 *  and reliability of the software and data, the NLM and the U.S.
 18 *  Government do not and cannot warrant the performance or results that
 19 *  may be obtained by using this software or data. The NLM and the U.S.
 20 *  Government disclaim all warranties, express or implied, including
 21 *  warranties of performance, merchantability or fitness for any particular
 22 *  purpose.
 23 *
 24 * ===========================================================================
 25 *
 26 * File Name:  asn2gnb3.c
 27 *
 28 * Author:  Karl Sirotkin, Tom Madden, Tatiana Tatusov, Jonathan Kans,
 29 *          Mati Shomrat
 30 *
 31 * Version Creation Date:   10/21/98
 32 *
 33 * $Revision: 1.120 $
 34 *
 35 * File Description:  New GenBank flatfile generator - work in progress
 36 *
 37 * Modifications:
 38 * --------------------------------------------------------------------------
 39 * ==========================================================================
 40 */
 41 
 42 #include <ncbi.h>
 43 #include <objall.h>
 44 #include <objsset.h>
 45 #include <objsub.h>
 46 #include <objfdef.h>
 47 #include <objpubme.h>
 48 #include <seqport.h>
 49 #include <sequtil.h>
 50 #include <sqnutils.h>
 51 #include <subutil.h>
 52 #include <tofasta.h>
 53 #include <explore.h>
 54 #include <gbfeat.h>
 55 #include <gbftdef.h>
 56 #include <edutil.h>
 57 #include <alignmgr2.h>
 58 #include <asn2gnbi.h>
 59 
 60 #ifdef WIN_MAC
 61 #if __profile__
 62 #include <Profiler.h>
 63 #endif
 64 #endif
 65 
 66 static CharPtr ref_link = "http://www.ncbi.nlm.nih.gov/RefSeq/";
 67 
 68 static CharPtr doc_link = "http://www.ncbi.nlm.nih.gov/genome/guide/build.shtml";
 69 
 70 static CharPtr ev_link = "http://www.ncbi.nlm.nih.gov/sutils/evv.cgi?";
 71 
 72 static CharPtr link_encode = "http://www.nhgri.nih.gov/10005107";
 73 
 74 static CharPtr link_seqn = "http://www.ncbi.nlm.nih.gov/nuccore/";
 75 static CharPtr link_seqp = "http://www.ncbi.nlm.nih.gov/protein/";
 76 
 77 static CharPtr link_gold_stamp_id = "http://genomesonline.org/GOLD_CARDS/";
 78 
 79 
 80 /* ********************************************************************** */
 81 
 82 static void AddHistCommentString (
 83   IntAsn2gbJobPtr ajp,
 84   StringItemPtr ffstring,
 85   CharPtr prefix,
 86   CharPtr suffix,
 87   DatePtr dp,
 88   SeqIdPtr ids,
 89   Boolean is_na
 90 )
 91 
 92 {
 93   Int2      count = 0;
 94   Char      buf [256];
 95   Boolean   first;
 96   Int4      gi = 0;
 97   SeqIdPtr  sip;
 98   CharPtr   strd;
 99   
100   if (dp == NULL || ids == NULL || prefix == NULL || suffix == NULL || ffstring == NULL) return;
101 
102   strd = asn2gb_PrintDate (dp);
103   if (strd == NULL) {
104     strd = StringSave ("?");
105   }
106 
107   for (sip = ids; sip != NULL; sip = sip->next) {
108     if (sip->choice == SEQID_GI) {
109       gi = (long) sip->data.intvalue;
110       count++;
111     }
112   }
113 
114   if (count > 1) {
115     sprintf (buf, "%s or before %s %s", prefix, strd, suffix);
116   } else {
117     sprintf (buf, "%s %s %s", prefix, strd, suffix);
118   }
119   FFAddOneString (ffstring, buf, FALSE, FALSE, TILDE_EXPAND);
120 
121   MemFree (strd);
122 
123   if (gi == 0) {
124     FFAddOneString (ffstring, " gi:?", FALSE, FALSE, TILDE_EXPAND);
125     return;
126   }
127 
128   first = TRUE;
129   for (sip = ids; sip != NULL; sip = sip->next) {
130     if (sip->choice == SEQID_GI) {
131       gi = (long) sip->data.intvalue;
132       if (! first) {
133         FFAddOneString (ffstring, ",", FALSE, FALSE, TILDE_IGNORE);
134       }
135       first = FALSE;
136       if ( GetWWW(ajp) ) {
137         FFAddOneString (ffstring, " gi:", FALSE, FALSE, TILDE_IGNORE);
138         FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
139         if (is_na) {
140           FF_Add_NCBI_Base_URL (ffstring, link_seqn);
141         } else {
142           FF_Add_NCBI_Base_URL (ffstring, link_seqp);
143         }
144         sprintf (buf, "%ld", (long) gi);
145         FFAddTextToString (ffstring, /* "val=" */ NULL, buf, "\">", FALSE, FALSE, TILDE_IGNORE);
146         FFAddOneString (ffstring, buf, FALSE, FALSE, TILDE_EXPAND);
147         FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
148       } else {
149         sprintf (buf, " gi:%ld", (long) gi);
150         FFAddOneString (ffstring, buf, FALSE, FALSE, TILDE_EXPAND);
151       }
152     }
153   }
154 
155   FFAddOneString (ffstring, ".", FALSE, FALSE, TILDE_EXPAND);
156 }
157 
158 static void AddHTGSCommentString (
159   StringItemPtr ffstring,
160   BioseqPtr bsp,
161   MolInfoPtr mip
162 )
163 
164 {
165   CharPtr      buf = NULL;
166   Char         buffer [256];
167   Int4         buflen = 0;
168   DeltaSeqPtr  dsp;
169   ValNodePtr   head = NULL;
170   Int4         num_s = 0;
171   Int4         num_g = 0;
172   CharPtr      str = NULL;
173 
174   if (bsp == NULL || mip == NULL || mip->tech < 2) return;
175 
176   if (bsp->repr == Seq_repr_delta) {
177     for (dsp = (DeltaSeqPtr) bsp->seq_ext, buflen = 0; dsp != NULL; dsp = dsp->next) {
178       buflen += 80;
179     }
180     if (buflen > 0) {
181       buf = MemNew ((size_t) (buflen + 1));
182       if (buf == NULL) return;
183       CountGapsInDeltaSeq (bsp, &num_s, &num_g, NULL, NULL, buf, buflen);
184     }
185   }
186 
187   if (mip->tech == MI_TECH_htgs_0) {
188 
189     if (num_s > 0) {
190       sprintf (buffer, "* NOTE: This record contains %ld individual~", (long) (num_g + 1));
191       ValNodeCopyStr (&head, 0, buffer);
192       ValNodeCopyStr (&head, 0, "* sequencing reads that have not been assembled into~");
193       ValNodeCopyStr (&head, 0, "* contigs. Runs of N are used to separate the reads~");
194       ValNodeCopyStr (&head, 0, "* and the order in which they appear is completely~");
195       ValNodeCopyStr (&head, 0, "* arbitrary. Low-pass sequence sampling is useful for~");
196       ValNodeCopyStr (&head, 0, "* identifying clones that may be gene-rich and allows~");
197       ValNodeCopyStr (&head, 0, "* overlap relationships among clones to be deduced.~");
198       ValNodeCopyStr (&head, 0, "* However, it should not be assumed that this clone~");
199       ValNodeCopyStr (&head, 0, "* will be sequenced to completion. In the event that~");
200       ValNodeCopyStr (&head, 0, "* the record is updated, the accession number will~");
201       ValNodeCopyStr (&head, 0, "* be preserved.");
202     }
203     ValNodeCopyStr (&head, 0, "~");
204     ValNodeCopyStr (&head, 0, buf);
205 
206   } else if (mip->tech == MI_TECH_htgs_1) {
207 
208     ValNodeCopyStr (&head, 0, "* NOTE: This is a \"working draft\" sequence.");
209     if (num_s > 0) {
210       sprintf (buffer, " It currently~* consists of %ld contigs. The true order of the pieces~", (long) (num_g + 1));
211       ValNodeCopyStr (&head, 0, buffer);
212       ValNodeCopyStr (&head, 0, "* is not known and their order in this sequence record is~");
213       ValNodeCopyStr (&head, 0, "* arbitrary. Gaps between the contigs are represented as~");
214       ValNodeCopyStr (&head, 0, "* runs of N, but the exact sizes of the gaps are unknown.");
215     }
216     ValNodeCopyStr (&head, 0, "~* This record will be updated with the finished sequence~");
217     ValNodeCopyStr (&head, 0, "* as soon as it is available and the accession number will~");
218     ValNodeCopyStr (&head, 0, "* be preserved.");
219     ValNodeCopyStr (&head, 0, "~");
220     ValNodeCopyStr (&head, 0, buf);
221 
222   } else if (mip->tech == MI_TECH_htgs_2) {
223 
224     ValNodeCopyStr (&head, 0, "* NOTE: This is a \"working draft\" sequence.");
225     if (num_s > 0) {
226       sprintf (buffer, " It currently~* consists of %ld contigs. Gaps between the contigs~", (long) (num_g + 1));
227       ValNodeCopyStr (&head, 0, buffer);
228       ValNodeCopyStr (&head, 0, "* are represented as runs of N. The order of the pieces~");
229       ValNodeCopyStr (&head, 0, "* is believed to be correct as given, however the sizes~");
230       ValNodeCopyStr (&head, 0, "* of the gaps between them are based on estimates that have~");
231       ValNodeCopyStr (&head, 0, "* provided by the submittor.");
232     }
233     ValNodeCopyStr (&head, 0, "~* This sequence will be replaced~");
234     ValNodeCopyStr (&head, 0, "* by the finished sequence as soon as it is available and~");
235     ValNodeCopyStr (&head, 0, "* the accession number will be preserved.");
236     ValNodeCopyStr (&head, 0, "~");
237     ValNodeCopyStr (&head, 0, buf);
238 
239   } else if ((str = StringForSeqTech (mip->tech)) != NULL) {
240 
241       sprintf (buffer, "Method: %s.", str);
242       ValNodeCopyStr (&head, 0, buffer);
243   }
244 
245   MemFree (buf);
246 
247   str = MergeFFValNodeStrs (head);
248 
249   FFAddOneString (ffstring, str, TRUE, TRUE, TILDE_EXPAND);
250 
251   MemFree (str);
252   ValNodeFreeData (head);
253 }
254 
255 static void AddWGSMasterCommentString (
256   StringItemPtr ffstring,
257   BioseqPtr bsp,
258   CharPtr wgsaccn,
259   CharPtr wgsname
260 )
261 
262 {
263   size_t             acclen;
264   BioSourcePtr       biop;
265   Char               buf [256];
266   SeqMgrDescContext  dcontext;
267   CharPtr            first = NULL;
268   CharPtr            last = NULL;
269   ObjectIdPtr        oip;
270   OrgRefPtr          orp;
271   SeqDescrPtr        sdp;
272   CharPtr            taxname = NULL;
273   UserFieldPtr       ufp;
274   UserObjectPtr      uop;
275   Char               ver [16];
276 
277   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_source, &dcontext);
278   if (sdp != NULL) {
279     biop = (BioSourcePtr) sdp->data.ptrvalue;
280     if (biop != NULL) {
281       orp = biop->org;
282       if (orp != NULL) {
283         taxname = orp->taxname;
284       }
285     }
286   }
287 
288   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_user, &dcontext);
289   while (sdp != NULL) {
290     uop = (UserObjectPtr) sdp->data.ptrvalue;
291     if (uop != NULL) {
292       oip = uop->type;
293       if (oip != NULL && StringICmp (oip->str, "WGSProjects") == 0) {
294         for (ufp = uop->data; ufp != NULL; ufp = ufp->next) {
295           oip = ufp->label;
296           if (oip == NULL || oip->str == NULL || ufp->choice != 1) continue;
297           if (StringICmp (oip->str, "WGS_accession_first") == 0) {
298             first = (CharPtr) ufp->data.ptrvalue;
299           } else if (StringICmp (oip->str, "WGS_accession_last") == 0) {
300             last = (CharPtr) ufp->data.ptrvalue;
301           }
302         }
303       }
304     }
305     sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_user, &dcontext);
306   }
307 
308   if (StringHasNoText (taxname)) {
309     taxname = "?";
310   }
311   ver [0] = '\0';
312   acclen = StringLen (wgsname);
313   if (acclen == 12) {
314     StringCpy (ver, wgsname + 4);
315     ver [2] = '\0';
316   } else if (acclen == 13) {
317     StringCpy (ver, wgsname + 4);
318     ver [2] = '\0';
319   } else if (acclen == 15) {
320     StringCpy (ver, wgsname + 7);
321     ver [2] = '\0';
322   }
323 
324   sprintf (buf, "The %s whole genome shotgun (WGS) project has the project accession %s.", taxname, wgsaccn);
325   FFAddOneString(ffstring, buf, TRUE, FALSE, TILDE_EXPAND);
326 
327   sprintf (buf, "  This version of the project (%s) has the accession number %s", ver, wgsname);
328   FFAddOneString(ffstring, buf, FALSE, FALSE, TILDE_EXPAND);
329 
330   if (first == NULL && last == NULL) {
331     sprintf (buf, ".");
332     FFAddOneString(ffstring, buf, TRUE, FALSE, TILDE_EXPAND);
333   } else {
334     if (first != NULL && last == NULL) {
335       last = first;
336     } else if (first == NULL && last != NULL) {
337       first = last;
338     }
339     if (StringDoesHaveText (first) && StringDoesHaveText (last)) {
340       if (StringCmp (first, last) != 0) {
341         sprintf (buf, ", and consists of sequences %s-%s.", first, last);
342         FFAddOneString(ffstring, buf, TRUE, FALSE, TILDE_EXPAND);
343       } else {
344         sprintf (buf, ", and consists of sequence %s.", first);
345         FFAddOneString(ffstring, buf, TRUE, FALSE, TILDE_EXPAND);
346       }
347     } else {
348       sprintf (buf, ".");
349       FFAddOneString(ffstring, buf, TRUE, FALSE, TILDE_EXPAND);
350     }
351   }
352 }
353 
354 
355 static CharPtr GetMolInfoCommentString (
356   BioseqPtr bsp,
357   MolInfoPtr mip
358 )
359 
360 {
361   Boolean  is_aa;
362   CharPtr  str = NULL;
363 
364   if (bsp == NULL || mip == NULL) return NULL;
365 
366   is_aa = ISA_aa (bsp->mol);
367   switch (mip->completeness) {
368     case 1 :
369       str = "COMPLETENESS: full length";
370       break;
371     case 2 :
372       str = "COMPLETENESS: not full length";
373       break;
374     case 3 :
375       if (is_aa) {
376         str = "COMPLETENESS: incomplete on the amino end";
377       } else {
378         str = "COMPLETENESS: incomplete on the 5' end";
379       }
380       break;
381     case 4 :
382       if (is_aa) {
383         str = "COMPLETENESS: incomplete on the carboxy end";
384       } else {
385         str = "COMPLETENESS: incomplete on the 3' end";
386       }
387       break;
388     case 5 :
389       str = "COMPLETENESS: incomplete on both ends";
390       break;
391     case 6 :
392       if (is_aa) {
393         str = "COMPLETENESS: complete on the amino end";
394       } else {
395         str = "COMPLETENESS: complete on the 5' end";
396       }
397       break;
398     case 7 :
399       if (is_aa) {
400         str = "COMPLETENESS: complete on the carboxy end";
401       } else {
402         str = "COMPLETENESS: complete on the 3' end";
403       }
404       break;
405     default :
406       str = "COMPLETENESS: unknown";
407       break;
408   }
409 
410   return str;
411 }
412 
413 static CharPtr GetStrForBankit (
414   UserObjectPtr uop
415 )
416 
417 {
418   CharPtr       bic = NULL, uvc = NULL, ptr;
419   ObjectIdPtr   oip;
420   UserFieldPtr  ufp;
421 
422   if (uop == NULL) return NULL;
423   if ((oip = uop->type) == NULL) return NULL;
424   if (StringCmp (oip->str, "Submission") != 0) return NULL;
425 
426   for (ufp = uop->data; ufp != NULL; ufp = ufp->next) {
427     oip = ufp->label;
428     if (StringCmp(oip->str, "UniVecComment") == 0) {
429       uvc = ufp->data.ptrvalue;
430     } else if (StringCmp(oip->str, "AdditionalComment") == 0) {
431       bic = ufp->data.ptrvalue;
432     }
433   }
434 
435   if (uvc == NULL && bic == NULL) return NULL;
436 
437   ptr = (CharPtr) MemNew (StringLen (uvc) + StringLen (bic) + 45);
438   if (uvc != NULL && bic != NULL) {
439     sprintf (ptr, "Vector Explanation: %s~Bankit Comment: %s", uvc, bic);
440   } else if (uvc != NULL) {
441     sprintf (ptr, "Vector Explanation: %s", uvc);
442   } else if (bic != NULL) {
443     sprintf (ptr, "Bankit Comment: %s", bic);
444   }
445 
446   return ptr;
447 }
448 
449 static CharPtr reftxt0 = " The reference sequence was derived from ";
450 static CharPtr reftxtg = " The reference sequence was generated based on analysis of ";
451 static CharPtr reftxti = " The reference sequence is identical to ";
452 static CharPtr reftxt1 = " This record is predicted by genome sequence analysis and is not yet supported by experimental evidence.";
453 static CharPtr reftxt2 = " This record has not yet been subject to final NCBI review.";
454 static CharPtr reftxt3 = " This record has not been reviewed and the function is unknown.";
455 static CharPtr reftxt4 = " This record has undergone validation or preliminary review.";
456 static CharPtr reftxt5 = " This record has been curated by ";
457 static CharPtr reftxt6 = " This record is predicted by automated computational analysis.";
458 static CharPtr reftxt7 = " This record is provided to represent a collection of whole genome shotgun sequences.";
459 static CharPtr reftxt9 = " This record is derived from an annotated genomic sequence (";
460 static CharPtr reftxt21 = "NCBI contigs are derived from assembled genomic sequence data.";
461 static CharPtr reftxt22 = " Features on this sequence have been produced for build ";
462 static CharPtr reftxt23 = " of the NCBI's genome annotation";
463 static CharPtr reftxt41 = " This record is based on preliminary annotation provided by ";
464 
465 static CharPtr GetStatusForRefTrack (
466   UserObjectPtr uop
467 )
468 
469 {
470   CharPtr       st;
471   ObjectIdPtr   oip;
472   UserFieldPtr  ufp, urf = NULL;
473 
474   if (uop == NULL) return NULL;
475   if ((oip = uop->type) == NULL) return NULL;
476   if (StringCmp (oip->str, "RefGeneTracking") != 0) return NULL;
477   for (ufp = uop->data; ufp != NULL; ufp = ufp->next) {
478     oip = ufp->label;
479     if (StringCmp(oip->str, "Assembly") == 0) {
480       urf = ufp;
481     }
482   }
483   /* if (urf == NULL || urf->choice != 11) return NULL; */
484   for (ufp = uop->data; ufp != NULL; ufp = ufp->next) {
485     oip = ufp->label;
486     if (StringCmp (oip->str, "Status") == 0) {
487       st = (CharPtr) ufp->data.ptrvalue;
488       if (StringICmp (st, "Inferred") == 0) {
489         return "INFERRED ";
490       } else if (StringICmp (st, "Provisional") == 0) {
491         return "PROVISIONAL ";
492       } else if (StringICmp (st, "Predicted") == 0) {
493         return "PREDICTED ";
494       } else if (StringICmp (st, "Validated") == 0) {
495         return "VALIDATED ";
496       } else if (StringICmp (st, "Reviewed") == 0) {
497         return "REVIEWED ";
498       } else if (StringICmp (st, "Model") == 0) {
499         return "MODEL ";
500       } else if (StringICmp (st, "WGS") == 0) {
501         return "WGS ";
502       } else if (StringICmp (st, "Pipeline") == 0) {
503         return "Pipeline ";
504       }
505     }
506   }
507   return NULL;
508 }
509 
510 
511 static Boolean URLHasSuspiciousHtml (
512   IntAsn2gbJobPtr ajp,
513   CharPtr searchString
514 )
515 
516 {
517   Char        ch;
518   CharPtr     ptr;
519   Int4        state;
520   ValNodePtr  matches;
521 
522   if (StringHasNoText (searchString)) return FALSE;
523 
524   state = 0;
525   ptr = searchString;
526   ch = *ptr;
527 
528   while (ch != '\0') {
529     matches = NULL;
530     ch = TO_LOWER (ch);
531     state = TextFsaNext (ajp->bad_html_fsa, state, ch, &matches);
532     if (matches != NULL) {
533       return TRUE;
534     }
535     ptr++;
536     ch = *ptr;
537   }
538 
539   return FALSE;
540 }
541 
542 static Boolean GetGiFromAccnDotVer (CharPtr source, Int4Ptr gip)
543 
544 {
545   Int4      gi = 0;
546   SeqIdPtr  sip;
547 
548   if (StringHasNoText (source) || gip == NULL) return FALSE;
549   *gip = 0;
550 
551   sip = SeqIdFromAccessionDotVersion (source);
552   if (sip == NULL) return FALSE;
553   gi = GetGIForSeqId (sip);
554   SeqIdFree (sip);
555   if (gi == 0) return FALSE;
556 
557   *gip = gi;
558   return TRUE;
559 }
560 
561 static void AddStrForRefTrack (
562   IntAsn2gbJobPtr ajp,
563   StringItemPtr ffstring,
564   UserObjectPtr uop,
565   Boolean is_na,
566   CharPtr genomeBuildNumber,
567   CharPtr genomeVersionNumber
568 )
569 
570 {
571   CharPtr       accn, curator = NULL, name, source = NULL, st, url = NULL;
572   Char          buf [64];
573   ObjectIdPtr   oip;
574   UserFieldPtr  ufp, tmp, u, urf = NULL;
575   Int4          from, to, gi;
576   Int2          i = 0;
577   Int2          review = 0;
578   Boolean       generated = FALSE, identical = FALSE;
579 
580   if ( uop == NULL || ffstring == NULL ) return;
581   if ((oip = uop->type) == NULL) return;
582   if (StringCmp (oip->str, "RefGeneTracking") != 0) return;
583 
584   for (ufp = uop->data; ufp != NULL; ufp = ufp->next) {
585     oip = ufp->label;
586     if (StringCmp(oip->str, "Assembly") == 0) {
587       urf = ufp;
588     } else if (StringCmp(oip->str, "IdenticalTo") == 0) {
589       urf = ufp;
590       identical = TRUE;
591     }
592     if (StringCmp (oip->str, "Status") == 0) {
593       st = (CharPtr) ufp->data.ptrvalue;
594       if (StringICmp (st, "Inferred") == 0) {
595         review = 1;
596       } else if (StringICmp (st, "Provisional") == 0) {
597         review = 2;
598       } else if (StringICmp (st, "Predicted") == 0) {
599         review = 3;
600       } else if (StringICmp (st, "Validated") == 0) {
601         review = 4;
602       } else if (StringICmp (st, "Reviewed") == 0) {
603         review = 5;
604       } else if (StringICmp (st, "Model") == 0) {
605         review = 6;
606       } else if (StringICmp (st, "WGS") == 0) {
607         review = 7;
608       } else if (StringICmp (st, "Pipeline") == 0) {
609         review = 8;
610       }
611     } else if (StringCmp (oip->str, "Generated") == 0) {
612       generated = ufp->data.boolvalue;
613     } else if (StringCmp (oip->str, "Collaborator") == 0) {
614       st = (CharPtr) ufp->data.ptrvalue;
615       if (! StringHasNoText (st)) {
616         curator = st;
617       }
618     } else if (StringCmp (oip->str, "CollaboratorURL") == 0) {
619       st = (CharPtr) ufp->data.ptrvalue;
620       if (! StringHasNoText (st)) {
621         url = st;
622       }
623     } else if (StringCmp (oip->str, "GenomicSource") == 0) {
624       st = (CharPtr) ufp->data.ptrvalue;
625       if (! StringHasNoText (st)) {
626         source = st;
627       }
628     }
629   }
630   if (urf != NULL && urf->choice == 11) {
631     for (tmp = urf->data.ptrvalue; tmp != NULL; tmp = tmp->next) {
632       for (u = tmp->data.ptrvalue; u != NULL; u = u->next) {
633         oip = u->label;
634         if (StringCmp (oip->str, "accession") == 0 ||
635             StringCmp (oip->str, "name") == 0) {
636           i++;
637         }
638       }
639     }
640   }
641   if ( GetWWW(ajp) ) {
642     FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
643     FF_Add_NCBI_Base_URL (ffstring, ref_link);
644     FFAddOneString (ffstring, "\">", FALSE, FALSE, TILDE_IGNORE);
645     FFAddOneString (ffstring, "REFSEQ", FALSE, FALSE, TILDE_IGNORE);
646     if (review == 8) {
647       FFAddOneString (ffstring, " INFORMATION", FALSE, FALSE, TILDE_IGNORE);
648     }
649     FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
650   } else {
651     FFAddOneString (ffstring, "REFSEQ", FALSE, FALSE, TILDE_IGNORE);
652     if (review == 8) {
653       FFAddOneString (ffstring, " INFORMATION", FALSE, FALSE, TILDE_IGNORE);
654     }
655   }
656   FFAddOneString (ffstring, ":", FALSE, FALSE, TILDE_IGNORE);
657   if (review == 1) {
658     FFAddOneString (ffstring, reftxt1, FALSE, FALSE, TILDE_IGNORE);
659   } else if (review == 2) {
660     if (curator == NULL) {
661       FFAddOneString (ffstring, reftxt2, FALSE, FALSE, TILDE_IGNORE);
662     }
663   } else if (review == 3) {
664     FFAddOneString (ffstring, reftxt3, FALSE, FALSE, TILDE_IGNORE);
665   } else if (review == 4) {
666     FFAddOneString (ffstring, reftxt4, FALSE, FALSE, TILDE_IGNORE);
667   } else if (review == 5) {
668     if (curator == NULL) {
669       curator = "NCBI staff";
670     }
671   } else if (review == 6) {
672     FFAddOneString (ffstring, reftxt6, FALSE, FALSE, TILDE_IGNORE);
673   } else if (review == 7) {
674     FFAddOneString (ffstring, reftxt7, FALSE, FALSE, TILDE_IGNORE);
675   } else if (review == 8) {
676   }
677   if (curator != NULL) {
678     if (review == 2) {
679       FFAddOneString (ffstring, reftxt41, FALSE, FALSE, TILDE_IGNORE);
680     } else {
681       FFAddOneString (ffstring, reftxt5, FALSE, FALSE, TILDE_IGNORE);
682     }
683     if (GetWWW (ajp) && url != NULL && (! URLHasSuspiciousHtml (ajp, url))) {
684       if (StringNCmp (url, "http://", 7) == 0 || StringNCmp (url, "https://", 8) == 0) {
685         FFAddTextToString(ffstring, "<a href=\"", url, "\">", FALSE, FALSE, TILDE_IGNORE);
686         FFAddOneString (ffstring, curator, FALSE, FALSE, TILDE_IGNORE);
687         FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
688       } else if (StringNCmp (url, "www.", 4) == 0) {
689         FFAddTextToString(ffstring, "<a href=http://\"", url, "\">", FALSE, FALSE, TILDE_IGNORE);
690         FFAddOneString (ffstring, curator, FALSE, FALSE, TILDE_IGNORE);
691         FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
692       } else {
693         FFAddOneString (ffstring, curator, FALSE, FALSE, TILDE_IGNORE);
694       }
695     } else {
696       FFAddOneString (ffstring, curator, FALSE, FALSE, TILDE_IGNORE);
697     }
698     FFAddOneString (ffstring, ".", FALSE, FALSE, TILDE_IGNORE);
699   }
700   if (source != NULL) {
701     FFAddOneString (ffstring, reftxt9, FALSE, FALSE, TILDE_IGNORE);
702     gi = 0;
703     if (GetWWW (ajp) && ValidateAccnDotVer (source) == 0 && GetGiFromAccnDotVer (source, &gi)) {
704       FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
705       if (is_na) {
706         FF_Add_NCBI_Base_URL (ffstring, link_seqn);
707       } else {
708         FF_Add_NCBI_Base_URL (ffstring, link_seqp);
709       }
710       if (gi > 0) {
711         sprintf (buf, "%ld", (long) gi);
712         FFAddTextToString(ffstring, /* "val=" */ NULL, buf, "\">", FALSE, FALSE, TILDE_IGNORE);
713       } else {
714         FFAddTextToString(ffstring, /* "val=" */ NULL, source, "\">", FALSE, FALSE, TILDE_IGNORE);
715       }
716       FFAddOneString (ffstring, source, FALSE, FALSE, TILDE_IGNORE);
717       FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
718     } else {
719       FFAddOneString (ffstring, source, FALSE, FALSE, TILDE_IGNORE);
720     }
721     FFAddOneString (ffstring, ").", FALSE, FALSE, TILDE_IGNORE);
722   }
723   if (i > 0) {
724     if (review == 8 && (genomeBuildNumber != NULL || genomeVersionNumber != NULL)) {
725       FFAddOneString (ffstring, reftxt22, FALSE, FALSE, TILDE_EXPAND);
726       FFAddOneString (ffstring, genomeBuildNumber, FALSE, FALSE, TILDE_EXPAND);
727       if (StringHasNoText (genomeVersionNumber)) {
728         genomeVersionNumber = "1";
729       }
730       FFAddOneString (ffstring, " version ", FALSE, FALSE, TILDE_EXPAND);
731       FFAddOneString (ffstring, genomeVersionNumber, FALSE, FALSE, TILDE_EXPAND);
732       FFAddOneString (ffstring, reftxt23, FALSE, FALSE, TILDE_EXPAND);
733 
734       FFAddOneString (ffstring, " [see ", FALSE, FALSE, TILDE_EXPAND);
735 
736       if ( GetWWW(ajp) ) {
737         FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
738         FF_Add_NCBI_Base_URL (ffstring, doc_link);
739         FFAddOneString (ffstring, "\">", FALSE, FALSE, TILDE_IGNORE);
740       }
741       FFAddOneString (ffstring, "documentation", FALSE, FALSE, TILDE_IGNORE);
742       if ( GetWWW(ajp) ) {
743         FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
744       }
745 
746       FFAddOneString (ffstring, "].  ", FALSE, FALSE, TILDE_EXPAND);
747     }
748     if (generated) {
749       FFAddOneString (ffstring, reftxtg, FALSE, FALSE, TILDE_IGNORE);
750     } else if (identical) {
751       FFAddOneString (ffstring, reftxti, FALSE, FALSE, TILDE_IGNORE);
752     } else {
753       FFAddOneString (ffstring, reftxt0, FALSE, FALSE, TILDE_IGNORE);
754     }
755 
756     for (tmp = urf->data.ptrvalue; tmp != NULL; tmp = tmp->next) {
757       accn = NULL;
758       from = 0;
759       to = 0;
760       name = NULL;
761       gi = 0;
762       for (u = tmp->data.ptrvalue; u != NULL; u = u->next) {
763         oip = u->label;
764         if (oip != NULL && oip->str != NULL) {
765           if (StringICmp (oip->str, "accession") == 0 && u->choice == 1) {
766             accn = (CharPtr) u->data.ptrvalue;
767           } else if (StringICmp (oip->str, "from") == 0 && u->choice == 2) {
768             from = u->data.intvalue;
769           } else if (StringICmp (oip->str, "to") == 0 && u->choice == 2) {
770             to = u->data.intvalue;
771           } else if (StringICmp (oip->str, "name") == 0 && u->choice == 1) {
772             name = (CharPtr) u->data.ptrvalue;
773           } else if (StringICmp (oip->str, "gi") == 0 && u->choice == 2) {
774             gi = u->data.intvalue;
775           }
776         }
777       }
778       if (StringDoesHaveText (accn)) {
779         if (GetWWW (ajp) && ValidateAccnDotVer (accn) == 0 && GetGiFromAccnDotVer (accn, &gi)) {
780           FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
781           if (is_na) {
782             FF_Add_NCBI_Base_URL (ffstring, link_seqn);
783           } else {
784             FF_Add_NCBI_Base_URL (ffstring, link_seqp);
785           }
786           if (gi > 0) {
787             sprintf (buf, "%ld", (long) gi);
788             FFAddTextToString(ffstring, /* "val=" */ NULL, buf, "\">", FALSE, FALSE, TILDE_IGNORE);
789           } else {
790             FFAddTextToString(ffstring, /* "val=" */ NULL, accn, "\">", FALSE, FALSE, TILDE_IGNORE);
791           }
792           FFAddOneString (ffstring, accn, FALSE, FALSE, TILDE_IGNORE);
793           FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
794         } else if (GetWWW (ajp) && ValidateAccn (accn) == 0) {
795           FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
796           if (is_na) {
797             FF_Add_NCBI_Base_URL (ffstring, link_seqn);
798           } else {
799             FF_Add_NCBI_Base_URL (ffstring, link_seqp);
800           }
801           FFAddTextToString(ffstring, /* "val=" */ NULL, accn, "\">", FALSE, FALSE, TILDE_IGNORE);
802           FFAddOneString (ffstring, accn, FALSE, FALSE, TILDE_IGNORE);
803           FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
804         } else {
805           FFAddOneString (ffstring, accn, FALSE, FALSE, TILDE_IGNORE);
806         }
807         if (from > 0 && to > 0) {
808           sprintf (buf, " (range: %ld-%ld)", (long) from, (long) to);
809           FFAddOneString (ffstring, buf, FALSE, FALSE, TILDE_IGNORE);
810         }
811       } else if (StringDoesHaveText (name)) {
812         FFAddOneString (ffstring, name, FALSE, FALSE, TILDE_IGNORE);
813       } else continue;
814       if (tmp->next != NULL) {
815         ufp = tmp->next;
816         if (ufp->next != NULL) {
817           FFAddOneString (ffstring, ", ", FALSE, FALSE, TILDE_IGNORE);
818         } else {
819           FFAddOneString (ffstring, " and ", FALSE, FALSE, TILDE_IGNORE);
820         }
821       }
822     }
823     FFAddOneString (ffstring, ".", FALSE, FALSE, TILDE_EXPAND);
824   }
825 }
826 
827 static CharPtr GetGenomeBuildNumber (
828   UserObjectPtr uop
829 )
830 
831 {
832   ObjectIdPtr   oip;
833   CharPtr       str;
834   UserFieldPtr  ufp;
835 
836   if (uop == NULL) return NULL;
837   if ((oip = uop->type) == NULL) return NULL;
838   if (StringCmp (oip->str, "GenomeBuild") != 0) return NULL;
839   for (ufp = uop->data; ufp != NULL; ufp = ufp->next) {
840     oip = ufp->label;
841     if (StringCmp(oip->str, "NcbiAnnotation") == 0) {
842       if (ufp->choice == 1) { /* string */
843         str = ufp->data.ptrvalue;
844         if (! StringHasNoText (str)) return str;
845       }
846     } else if (StringCmp (oip->str, "Annotation") == 0) {
847       if (ufp->choice == 1) { /* string */
848         str = ufp->data.ptrvalue;
849         if (! StringHasNoText (str)) {
850           if (StringNICmp (str, "NCBI build ", 11) == 0) {
851             if (! StringHasNoText (str + 11)) {
852               return (str + 11);
853             }
854           }
855         }
856       }
857     }
858   }
859   return NULL;
860 }
861 
862 static CharPtr GetGenomeVersionNumber (
863   UserObjectPtr uop
864 )
865 
866 {
867   ObjectIdPtr   oip;
868   CharPtr       str;
869   UserFieldPtr  ufp;
870 
871   if (uop == NULL) return NULL;
872   if ((oip = uop->type) == NULL) return NULL;
873   if (StringCmp (oip->str, "GenomeBuild") != 0) return NULL;
874   for (ufp = uop->data; ufp != NULL; ufp = ufp->next) {
875     oip = ufp->label;
876     if (StringCmp(oip->str, "NcbiVersion") == 0) {
877       if (ufp->choice == 1) { /* string */
878         str = ufp->data.ptrvalue;
879         if (! StringHasNoText (str)) return str;
880       }
881     }
882   }
883   return NULL;
884 }
885 
886 
887 static CharPtr reftxt11 = "This record is predicted by automated computational analysis. This record is derived from a genomic sequence";
888 static CharPtr reftxt12 = "annotated using gene prediction method:";
889 
890 static void FindModelEvidenceUop (
891   UserObjectPtr uop,
892   Pointer userdata
893 )
894 
895 {
896   ObjectIdPtr         oip;
897   UserObjectPtr PNTR  uopp;
898 
899   if (uop == NULL || userdata == NULL) return;
900   uopp = (UserObjectPtr PNTR) userdata;
901   oip = uop->type;
902   if (oip == NULL) return;
903   if (StringCmp (oip->str, "ModelEvidence") == 0) {
904     *uopp = uop;
905   }
906 }
907 
908 static Boolean DoGetAnnotationComment (
909    BioseqPtr bsp,
910    CharPtr PNTR namep,
911    CharPtr PNTR methodp,
912    BoolPtr mrnaEv,
913    BoolPtr estEv
914 )
915 
916 {
917   Int2               ce = 0, cm = 0;
918   SeqMgrDescContext  dcontext;
919   CharPtr            method = NULL;
920   UserObjectPtr      moduop;
921   CharPtr            name = NULL;
922   ObjectIdPtr        oip;
923   SeqDescrPtr        sdp;
924   UserFieldPtr       u;
925   UserFieldPtr       ufp;
926   UserObjectPtr      uop;
927 
928   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_user, &dcontext);
929   while (sdp != NULL) {
930     uop = (UserObjectPtr) sdp->data.ptrvalue;
931     if (uop != NULL) {
932       moduop = NULL;
933       VisitUserObjectsInUop (uop, (Pointer) &moduop, FindModelEvidenceUop);
934       if (moduop != NULL) {
935         oip = moduop->type;
936         if (oip != NULL && StringCmp(oip->str, "ModelEvidence") == 0) {
937           for (ufp = uop->data; ufp != NULL; ufp = ufp->next) {
938             oip = ufp->label;
939             if (oip == NULL) continue;
940             if (StringCmp (oip->str, "Contig Name") == 0) {
941               name = (CharPtr) ufp->data.ptrvalue;
942             } else if (StringCmp (oip->str, "Method") == 0) {
943               method = (CharPtr) ufp->data.ptrvalue;
944             } else if (StringCmp (oip->str, "mRNA") == 0) {
945               *mrnaEv = TRUE;
946             } else if (StringCmp (oip->str, "EST") == 0) {
947               *estEv = TRUE;
948             } else if (StringCmp (oip->str, "Counts") == 0) {
949               for (u = (UserFieldPtr) ufp->data.ptrvalue; u != NULL; u = u->next) {
950                 if (u->data.ptrvalue == NULL) continue;
951                 if (u->choice != 2) continue;
952                 oip = u->label;
953                 if (oip == NULL) continue;
954                 if (StringCmp (oip->str, "mRNA") == 0) {
955                   cm = (Int2) u->data.intvalue;
956                   if (cm > 0) {
957                     *mrnaEv = TRUE;
958                   }
959                 } else if (StringCmp (oip->str, "EST") == 0) {
960                   ce = (Int2) u->data.intvalue;
961                   if (ce > 0) {
962                     *estEv = TRUE;
963                   }
964                 }
965               }
966             }
967           }
968         }
969       }
970     }
971     sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_user, &dcontext);
972   }
973   if (StringHasNoText (name)) return FALSE;
974   *namep = name;
975   if (! StringHasNoText (method)) {
976     *methodp = method;
977   }
978   return TRUE;
979 }
980 
981 static Boolean GetAnnotationComment (
982    BioseqPtr bsp,
983    CharPtr PNTR namep,
984    CharPtr PNTR methodp,
985    BoolPtr mrnaEv,
986    BoolPtr estEv
987 )
988 
989 {
990   SeqFeatPtr  cds;
991 
992   if (DoGetAnnotationComment (bsp, namep, methodp, mrnaEv, estEv)) return TRUE;
993   if (ISA_aa (bsp->mol)) {
994     cds = SeqMgrGetCDSgivenProduct (bsp, NULL);
995     if (cds != NULL) {
996       bsp = BioseqFindFromSeqLoc (cds->location);
997       if (bsp != NULL) {
998         return DoGetAnnotationComment (bsp, namep, methodp, mrnaEv, estEv);
999       }
1000     }
1001   }
1002   return FALSE;
1003 }
1004 
1005 static void FindGeneFeat (
1006   SeqFeatPtr sfp,
1007   Pointer userdata
1008 )
1009 
1010 {
1011   SeqFeatPtr PNTR  sfpp;
1012 
1013   if (sfp->data.choice != SEQFEAT_GENE) return;
1014   sfpp = (SeqFeatPtr PNTR) userdata;
1015   *sfpp = sfp;
1016 }
1017 
1018 static void FindLocusId (
1019   ValNodePtr dbxref,
1020   CharPtr locusIDp
1021 )
1022 
1023 {
1024   DbtagPtr     dbt;
1025   ObjectIdPtr  oip;
1026   ValNodePtr   vnp;
1027 
1028   for (vnp = dbxref; vnp != NULL; vnp = vnp->next) {
1029     dbt = (DbtagPtr) vnp->data.ptrvalue;
1030     if (dbt == NULL) continue;
1031     if (StringICmp (dbt->db, "LocusID") != 0 && StringICmp (dbt->db, "InterimID") != 0) continue;
1032     oip = dbt->tag;
1033     if (oip == NULL) continue;
1034     if (oip->str != NULL) {
1035       StringCpy (locusIDp, oip->str);
1036     } else if (oip->id > 0) {
1037       sprintf (locusIDp, "%ld", (long) oip->id);
1038     }
1039   }
1040 }
1041 
1042 static Boolean GetGeneAndLocus (
1043   BioseqPtr bsp,
1044   CharPtr PNTR genep,
1045   CharPtr locusIDp,
1046   CharPtr taxIDp
1047 )
1048 
1049 {
1050   BioSourcePtr       biop;
1051   DbtagPtr           dbt;
1052   SeqMgrDescContext  dcontext;
1053   SeqFeatPtr         gene = NULL;
1054   GeneRefPtr         grp;
1055   ObjectIdPtr        oip;
1056   OrgRefPtr          orp;
1057   SeqDescrPtr        sdp;
1058   SeqEntryPtr        sep;
1059   CharPtr            str;
1060   ValNodePtr         syn;
1061   ValNodePtr         vnp;
1062 
1063   sep = GetTopSeqEntryForEntityID (bsp->idx.entityID);
1064   if (sep == NULL) return FALSE;
1065   VisitFeaturesInSep (sep, (Pointer) &gene, FindGeneFeat);
1066   if (gene == NULL) return FALSE;
1067 
1068   grp = (GeneRefPtr) gene->data.value.ptrvalue;
1069   if (grp == NULL) return FALSE;
1070   if (! StringHasNoText (grp->locus)) {
1071     *genep = grp->locus;
1072   } else {
1073     syn = grp->syn;
1074     if (syn != NULL) {
1075       str = (CharPtr) syn->data.ptrvalue;
1076       if (! StringHasNoText (str)) {
1077         *genep = str;
1078       }
1079     }
1080   }
1081   FindLocusId (gene->dbxref, locusIDp);
1082   FindLocusId (grp->db, locusIDp);
1083 
1084   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_source, &dcontext);
1085   if (sdp != NULL) {
1086     biop = (BioSourcePtr) sdp->data.ptrvalue;
1087     if (biop != NULL) {
1088       orp = biop->org;
1089       if (orp != NULL) {
1090         for (vnp = orp->db; vnp != NULL; vnp = vnp->next) {
1091           dbt = (DbtagPtr) vnp->data.ptrvalue;
1092           if (dbt == NULL) continue;
1093           if (StringCmp (dbt->db, "taxon") == 0) {
1094             oip = dbt->tag;
1095             if (oip == NULL) continue;
1096             if (oip->str != NULL) {
1097               StringCpy (taxIDp, oip->str);
1098             } else if (oip->id > 0) {
1099               sprintf (taxIDp, "%ld", (long) oip->id);
1100             }
1101           }
1102         }
1103       }
1104     }
1105   }
1106 
1107   if (genep == NULL || StringHasNoText (locusIDp)) return FALSE;
1108 
1109   return TRUE;
1110 }
1111 
1112 static CharPtr nsAreGapsString = "The strings of n's in this record represent gaps between contigs, and the length of each string corresponds to the length of the gap.";
1113 static CharPtr nsWGSGapsString = "The strings of n's in this record represent gaps between contigs or uncallable bases.";
1114 
1115 static Boolean IsTpa (
1116   BioseqPtr bsp,
1117   Boolean has_tpa_assembly,
1118   BoolPtr isRefSeqP,
1119   BoolPtr isTsaP
1120 )
1121 
1122 {
1123   SeqMgrDescContext  dcontext;
1124   DbtagPtr           dbt;
1125   Boolean            has_bankit = FALSE;
1126   Boolean            has_genbank = FALSE;
1127   Boolean            has_gi = FALSE;
1128   Boolean            has_local = FALSE;
1129   Boolean            has_refseq = FALSE;
1130   Boolean            has_smart = FALSE;
1131   Boolean            has_tpa = FALSE;
1132   Boolean            is_tsa = FALSE;
1133   MolInfoPtr         mip;
1134   SeqDescrPtr        sdp;
1135   SeqIdPtr           sip;
1136 
1137   if (bsp == NULL || bsp->id == NULL) return FALSE;
1138   for (sip = bsp->id; sip != NULL; sip = sip->next) {
1139     switch (sip->choice) {
1140       case SEQID_LOCAL :
1141         has_local = TRUE;
1142         break;
1143       case SEQID_GENBANK :
1144       case SEQID_EMBL :
1145       case SEQID_DDBJ :
1146         has_genbank = TRUE;
1147         break;
1148       case SEQID_OTHER :
1149         has_refseq = TRUE;
1150         if (isRefSeqP != NULL) {
1151           *isRefSeqP = TRUE;
1152         }
1153         break;
1154       case SEQID_GI :
1155         has_gi = TRUE;
1156         break;
1157       case SEQID_TPG :
1158       case SEQID_TPE :
1159       case SEQID_TPD :
1160         has_tpa = TRUE;
1161         break;
1162       case SEQID_GENERAL :
1163         dbt = (DbtagPtr) sip->data.ptrvalue;
1164         if (dbt != NULL) {
1165           if (StringICmp (dbt->db, "BankIt") == 0) {
1166             has_bankit = TRUE;
1167           }
1168           if (StringICmp (dbt->db, "TMSMART") == 0) {
1169             has_smart = TRUE;
1170           }
1171         }
1172         break;
1173       default :
1174         break;
1175     }
1176   }
1177 
1178   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_molinfo, &dcontext);
1179   if (sdp != NULL && sdp->choice == Seq_descr_molinfo) {
1180     mip = (MolInfoPtr) sdp->data.ptrvalue;
1181     if (mip != NULL) {
1182       if (mip->tech == MI_TECH_tsa) {
1183         is_tsa = TRUE;
1184         if (isTsaP != NULL) {
1185           *isTsaP = TRUE;
1186         }
1187       }
1188     }
1189   }
1190 
1191   if (is_tsa) return TRUE;
1192   if (has_genbank) return FALSE;
1193   if (has_tpa) return TRUE;
1194   if (has_refseq) return TRUE;
1195   if (has_bankit && has_tpa_assembly) return TRUE;
1196   if (has_smart && has_tpa_assembly) return TRUE;
1197   if (has_gi) return FALSE;
1198   if (has_local && has_tpa_assembly) return TRUE;
1199 
1200   return FALSE;
1201 }
1202 
1203 static CharPtr GetPrimaryStrForDelta (
1204   BioseqPtr bsp
1205 )
1206 
1207 {
1208   Boolean      accn;
1209   Char         buf [64], tmp [80];
1210   Int4         curr_start = 0, len, start0, start1;
1211   DbtagPtr     dbt;
1212   DeltaSeqPtr  deltasp;
1213   Int4         gi;
1214   ValNodePtr   head = NULL;
1215   SeqIdPtr     id, sip;
1216   SeqIntPtr    intp;
1217   SeqLitPtr    litp;
1218   SeqLocPtr    slp;
1219   CharPtr      str;
1220   Uint1        strand;
1221 
1222   if (bsp == NULL || bsp->repr != Seq_repr_delta || bsp->seq_ext_type != 4) return NULL;
1223 
1224   for (deltasp = (DeltaSeqPtr) bsp->seq_ext; deltasp != NULL; deltasp = deltasp->next) {
1225     if (deltasp->choice == 1) {
1226       slp = (SeqLocPtr) deltasp->data.ptrvalue;
1227       if (slp != NULL && slp->choice == SEQLOC_INT) {
1228         intp = (SeqIntPtr) slp->data.ptrvalue;
1229         start0 = curr_start;
1230         start1 = intp->from;
1231         len = intp->to - intp->from + 1;
1232         curr_start += len;
1233         strand = intp->strand;
1234         sip = intp->id;
1235         if (sip == NULL) continue;
1236         id = NULL;
1237         accn = FALSE;
1238         if (sip->choice == SEQID_GI) {
1239           gi = (Int4) sip->data.intvalue;
1240           if (GetAccnVerFromServer (gi, buf)) {
1241             accn = TRUE;
1242           } else {
1243             id = GetSeqIdForGI (gi);
1244           }
1245           if (id == NULL) {
1246             sprintf (buf, "%ld", (long) gi);
1247             accn = TRUE;
1248           }
1249         } else {
1250           id = SeqIdDup (sip);
1251         }
1252         if (id != NULL || accn) {
1253           if (head == NULL) {
1254             ValNodeCopyStr (&head, 0, "CONTIG_SPAN         PRIMARY_IDENTIFIER PRIMARY_SPAN        COMP");
1255           }
1256           if (id != NULL) {
1257             SeqIdWrite (id, buf, PRINTID_TEXTID_ACC_VER, sizeof (buf) - 1);
1258             if (id->choice == SEQID_GENERAL) {
1259               dbt = (DbtagPtr) id->data.ptrvalue;
1260               if (dbt != NULL && StringICmp (dbt->db, "ti") == 0) {
1261                 StringCpy (buf, "TI");
1262                 SeqIdWrite (id, buf + 2, PRINTID_TEXTID_ACC_VER, sizeof (buf) - 3);
1263               }
1264             }
1265           }
1266           sprintf (tmp, "~%ld-%ld                                        ",
1267                    (long) (start0 + 1), (long) (start0 + len));
1268           tmp [21] = '\0';
1269           StringCat (buf, "                                        ");
1270           buf [18] = '\0';
1271           StringCat (tmp, buf);
1272           sprintf (buf, " %ld-%ld                                        ",
1273                    (long) (start1 + 1), (long) (start1 + len));
1274           buf [21] = '\0';
1275           StringCat (tmp, buf);
1276           if (strand == Seq_strand_minus) {
1277             StringCat (tmp, "c");
1278           }
1279           ValNodeCopyStr (&head, 0, tmp);
1280         }
1281         SeqIdFree (id);
1282       }
1283     } else if (deltasp->choice == 2) {
1284       litp = (SeqLitPtr) deltasp->data.ptrvalue;
1285       if (litp != NULL) {
1286         curr_start += litp->length;
1287       }
1288     }
1289   }
1290 
1291   if (head == NULL) return NULL;
1292 
1293   str = MergeFFValNodeStrs (head);
1294   ValNodeFreeData (head);
1295 
1296   return str;
1297 }
1298 
1299 static CharPtr GetStrForTpaOrRefSeqHist (
1300   BioseqPtr bsp,
1301   Boolean isRefSeq,
1302   Boolean isTsa
1303 )
1304 
1305 {
1306   Boolean      accn;
1307   Char         bfr [100];
1308   Char         buf [100];
1309   DbtagPtr     dbt;
1310   Int4         gi;
1311   ValNodePtr   head = NULL;
1312   SeqHistPtr   hist;
1313   SeqIdPtr     id;
1314   Int2         j;
1315   int          k;
1316   Int2         max;
1317   Boolean      minus1;
1318   Boolean      minus2;
1319   Int4         oldstop = -1;
1320   Uint1        residue;
1321   SeqAlignPtr  salp;
1322   SeqAlignPtr  salptmp;
1323   StreamCache  sc;
1324   SeqIdPtr     sip;
1325   Int4         start;
1326   Int4         stop;
1327   CharPtr      str;
1328   Char         tmp [120];
1329 
1330   if (bsp == NULL) return NULL;
1331   hist = bsp->hist;
1332   if (hist != NULL && hist->assembly != NULL) {
1333     salp = SeqAlignListDup (hist->assembly);
1334     AlnMgr2IndexLite (salp);
1335     AlnMgr2SortAlnSetByNthRowPos (salp, 1);
1336     salptmp = (SeqAlignPtr) (salp->segs);
1337     while (salptmp != NULL) {
1338       AlnMgr2GetNthSeqRangeInSA (salptmp, 1, &start, &stop);
1339       sip = AlnMgr2GetNthSeqIdPtr (salptmp, 2);
1340       if (sip != NULL) {
1341         id = NULL;
1342         accn = FALSE;
1343         buf [0] = '\0';
1344         if (sip->choice == SEQID_GI) {
1345           gi = (Int4) sip->data.intvalue;
1346           if (GetAccnVerFromServer (gi, buf)) {
1347             accn = TRUE;
1348           } else {
1349             id = GetSeqIdForGI (gi);
1350           }
1351         } else {
1352           id = SeqIdDup (sip);
1353         }
1354         if (id != NULL || accn) {
1355           if (head == NULL) {
1356             if (isRefSeq) {
1357               ValNodeCopyStr (&head, 0, "REFSEQ_SPAN         PRIMARY_IDENTIFIER PRIMARY_SPAN        COMP");
1358             } else if (isTsa) {
1359               ValNodeCopyStr (&head, 0, "TSA_SPAN            PRIMARY_IDENTIFIER PRIMARY_SPAN        COMP");
1360             } else {
1361               ValNodeCopyStr (&head, 0, "TPA_SPAN            PRIMARY_IDENTIFIER PRIMARY_SPAN        COMP");
1362             }
1363           }
1364           if (isRefSeq && oldstop > -1 && oldstop < start) {
1365             sprintf (tmp, "~%ld-%ld                                        ",
1366                      (long) (oldstop + 1), (long) (start));
1367             tmp [21] = '\0';
1368             StringCpy (bfr, "                                        ");
1369             k = 0;
1370             if (StreamCacheSetup (bsp, NULL, 0, &sc)) {
1371               if (start - oldstop < 15) {
1372                 StreamCacheSetPosition (&sc, oldstop);
1373                 bfr [k] = '"';
1374                 k++;
1375                 max = start - oldstop;
1376                 for (j = 0; j < max; j++) {
1377                   residue = StreamCacheGetResidue (&sc);
1378                   bfr [k] = (Char) residue;
1379                   k++;
1380                 }
1381                 bfr [k] = '"';
1382                 k++;
1383               } else {
1384                 StreamCacheSetPosition (&sc, oldstop);
1385                 bfr [k] = '"';
1386                 k++;
1387                 for (j = 0; j < 4; j++) {
1388                   residue = StreamCacheGetResidue (&sc);
1389                   bfr [k] = (Char) residue;
1390                   k++;
1391                 }
1392                 bfr [k] = '.';
1393                 k++;
1394                 bfr [k] = '.';
1395                 k++;
1396                 bfr [k] = '.';
1397                 k++;
1398                 StreamCacheSetPosition (&sc, start - 4);
1399                 for (j = 0; j < 4; j++) {
1400                   residue = StreamCacheGetResidue (&sc);
1401                   bfr [k] = (Char) residue;
1402                   k++;
1403                 }
1404                 bfr [k] = '"';
1405                 k++;
1406               }
1407             } else {
1408               /*
1409               StringCpy (bfr, "inserted base(s)");
1410               */
1411             }
1412             bfr [k] = '\0';
1413             StringCat (bfr, "                                        ");
1414             bfr [18] = '\0';
1415             StringCat (tmp, bfr);
1416             sprintf (bfr, " %ld-%ld                                        ",
1417                      (long) 1, (long) (start - oldstop));
1418             bfr [21] = '\0';
1419             StringCat (tmp, bfr);
1420             ValNodeCopyStr (&head, 0, tmp);
1421           }
1422           oldstop = stop + 1;
1423           if (id != NULL) {
1424             SeqIdWrite (id, buf, PRINTID_TEXTID_ACC_VER, sizeof (buf) - 1);
1425             if (id->choice == SEQID_GENERAL) {
1426               dbt = (DbtagPtr) id->data.ptrvalue;
1427               if (dbt != NULL && StringICmp (dbt->db, "ti") == 0) {
1428                 StringCpy (buf, "TI");
1429                 SeqIdWrite (id, buf + 2, PRINTID_TEXTID_ACC_VER, sizeof (buf) - 3);
1430               }
1431             }
1432           }
1433           sprintf (tmp, "~%ld-%ld                                        ",
1434                    (long) (start + 1), (long) (stop + 1));
1435           /*
1436           i = 39 - StringLen (buf);
1437           if (i > 0) {
1438             tmp [i] = '\0';
1439           } else {
1440             tmp [21] = '\0';
1441           }
1442           */
1443           tmp [21] = '\0';
1444           StringCat (buf, "                                        ");
1445           buf [18] = '\0';
1446           StringCat (tmp, buf);
1447           AlnMgr2GetNthSeqRangeInSA (salptmp, 2, &start, &stop);
1448           sprintf (buf, " %ld-%ld                                        ",
1449                    (long) (start + 1), (long) (stop + 1));
1450           buf [21] = '\0';
1451           StringCat (tmp, buf);
1452           minus1 = (Boolean) (AlnMgr2GetNthStrand (salptmp, 1) == Seq_strand_minus);
1453           minus2 = (Boolean) (AlnMgr2GetNthStrand (salptmp, 2) == Seq_strand_minus);
1454           if (minus1 || minus2) {
1455             if (! (minus1 && minus2)) {
1456               StringCat (tmp, "c");
1457             }
1458           }
1459           ValNodeCopyStr (&head, 0, tmp);
1460         }
1461         SeqIdFree (id);
1462       }
1463       SeqIdFree (sip);
1464       salptmp = salptmp->next;
1465     }
1466     SeqAlignFree (salp);
1467   }
1468 
1469   if (head == NULL) return NULL;
1470 
1471   str = MergeFFValNodeStrs (head);
1472   ValNodeFreeData (head);
1473 
1474   return str;
1475 }
1476 
1477 static CharPtr tpaString = "THIRD PARTY ANNOTATION DATABASE: This TPA record uses data from DDBJ/EMBL/GenBank ";
1478 
1479 static CharPtr GetStrForTPA (
1480   UserObjectPtr uop,
1481   BioseqPtr bsp
1482 )
1483 
1484 {
1485   Char          ch;
1486   UserFieldPtr  curr;
1487   SeqHistPtr    hist;
1488   Int2          i;
1489   Char          id [41];
1490   Boolean       isRefSeq = FALSE;
1491   Boolean       isTsa = FALSE;
1492   Int2          j;
1493   size_t        len;
1494   ObjectIdPtr   oip;
1495   CharPtr       ptr;
1496   CharPtr       str;
1497   CharPtr       tmp;
1498   UserFieldPtr  ufp;
1499 
1500   if (uop == NULL) return NULL;
1501   if ((oip = uop->type) == NULL) return NULL;
1502   if (StringCmp (oip->str, "TpaAssembly") != 0) return NULL;
1503   if (bsp == NULL) return NULL;
1504   hist = bsp->hist;
1505   if (hist != NULL && hist->assembly != NULL) return NULL;
1506   if (! IsTpa (bsp, TRUE, &isRefSeq, &isTsa)) return NULL;
1507   if (isRefSeq) return NULL;
1508 
1509   len = StringLen (tpaString) + StringLen ("entries ") + StringLen ("and ") + 5;
1510   i = 0;
1511   for (curr = uop->data; curr != NULL; curr = curr->next) {
1512     if (curr->choice != 11) continue;
1513     for (ufp = curr->data.ptrvalue; ufp != NULL; ufp = ufp->next) {
1514       if (ufp->choice != 1) continue;
1515       oip = ufp->label;
1516       if (oip == NULL || StringICmp (oip->str, "accession") != 0) continue;
1517       str = (CharPtr) ufp->data.ptrvalue;
1518       if (StringHasNoText (str)) continue;
1519       len += StringLen (str) + 2;
1520       i++;
1521     }
1522   }
1523   if (i == 0) return NULL;
1524 
1525   ptr = (CharPtr) MemNew (len);
1526   if (ptr == NULL) return NULL;
1527   StringCpy (ptr, tpaString);
1528   if (i > 1) {
1529     StringCat (ptr, "entries ");
1530   } else {
1531     StringCat (ptr, "entry ");
1532   }
1533 
1534   j = 0;
1535   for (curr = uop->data; curr != NULL; curr = curr->next) {
1536     if (curr->choice != 11) continue;
1537     for (ufp = curr->data.ptrvalue; ufp != NULL; ufp = ufp->next) {
1538       if (ufp->choice != 1) continue;
1539       oip = ufp->label;
1540       if (oip == NULL || StringICmp (oip->str, "accession") != 0) continue;
1541       str = (CharPtr) ufp->data.ptrvalue;
1542       if (StringHasNoText (str)) continue;
1543       StringNCpy_0 (id, str, sizeof (id));
1544       tmp = id;
1545       ch = *tmp;
1546       while (ch != '\0') {
1547         if (IS_LOWER (ch)) {
1548           *tmp = TO_UPPER (ch);
1549         }
1550         tmp++;
1551         ch = *tmp;
1552       }
1553       if (j == i - 1 && i > 1) {
1554         StringCat (ptr, " and ");
1555       } else if (j > 0) {
1556         StringCat (ptr, ", ");
1557       }
1558       StringCat (ptr, id);
1559       j++;
1560     }
1561   }
1562 
1563   return ptr;
1564 }
1565 
1566 static CharPtr GetStrForGenome (
1567   UserObjectPtr uop,
1568   BioseqPtr bsp
1569 )
1570 
1571 {
1572   ObjectIdPtr  oip;
1573 
1574   if (uop == NULL) return NULL;
1575   if ((oip = uop->type) == NULL) return NULL;
1576   if (StringCmp (oip->str, "GenomeInfo") != 0) return NULL;
1577 
1578   /* !!! need to implement !!! */
1579 
1580   return NULL;
1581 }
1582 
1583 static CharPtr StrucCommentFFEndPrint (
1584   IntAsn2gbJobPtr ajp,
1585   StringItemPtr ffstring,
1586   FmtType format,
1587   Int2 gb_init_indent,
1588   Int2 gb_cont_indent,
1589   Int2 eb_init_indent,
1590   Int2 eb_cont_indent,
1591   CharPtr eb_line_prefix
1592 )
1593 {
1594   StringItemPtr temp = FFGetString(ajp);
1595   CharPtr result;
1596 
1597   if ( (ffstring == NULL) || (ajp == NULL) ) return NULL;
1598 
1599   if (format == GENBANK_FMT || format == GENPEPT_FMT) {
1600     FFLineWrap (temp, ffstring, gb_init_indent, gb_cont_indent, ASN2FF_GB_MAX - 12, NULL);
1601   } else {
1602     FFLineWrap (temp, ffstring, eb_init_indent, eb_cont_indent, ASN2FF_EMBL_MAX - 5, eb_line_prefix);
1603   }
1604   result = FFToCharPtr (temp);
1605   FFRecycleString (ajp, temp);
1606   return result;
1607 }
1608 
1609 static size_t ThresholdForStructuredCommentColumnarDisplay (
1610   FmtType format
1611 )
1612 {
1613   // We are trying to make those structured comments look pretty. However, if the first column gets
1614   //  too big, the printout starts to look ugly. This function attempts to define the first column
1615   //  extent at which pretty turns into ugly.
1616   
1617   const size_t MAX_COLUMN_WIDTH = 45;
1618   switch ( format ) {
1619   
1620     case GENBANK_FMT:
1621     case GENPEPT_FMT:
1622       return MIN( MAX_COLUMN_WIDTH, ASN2FF_GB_MAX - 12 );
1623       
1624     default:
1625       return MIN( MAX_COLUMN_WIDTH, ASN2FF_EMBL_MAX - 5 );
1626   }
1627 }
1628 
1629 static CharPtr GetStrForStructuredComment (
1630   Asn2gbWorkPtr awp,
1631   IntAsn2gbJobPtr ajp,
1632   UserObjectPtr uop,
1633   BioseqPtr bsp
1634 )
1635 
1636 {
1637   UserFieldPtr   curr;
1638   StringItemPtr  ffstring;
1639   CharPtr        field;
1640   ValNodePtr     head = NULL;
1641   size_t         len;
1642   size_t         max = 0;
1643   ObjectIdPtr    oip;
1644   CharPtr        prefix = NULL;
1645   CharPtr        str;
1646   CharPtr        suffix = NULL;
1647   CharPtr        tmp;
1648 
1649   if (awp == NULL || ajp == NULL || uop == NULL) return NULL;
1650   if ((oip = uop->type) == NULL) return NULL;
1651   if (StringCmp (oip->str, "StructuredComment") != 0) return NULL;
1652 
1653   ffstring = FFGetString (ajp);
1654   if (ffstring == NULL) return NULL;
1655 
1656   for (curr = uop->data; curr != NULL; curr = curr->next) {
1657    if (curr->choice != 1) continue;
1658     oip = curr->label;
1659     if (oip == NULL) continue;
1660     field = oip->str;
1661     if (StringHasNoText (field)) continue;
1662     if (StringCmp (field, "StructuredCommentPrefix") == 0) {
1663       str = (CharPtr) curr->data.ptrvalue;
1664       if (StringDoesHaveText (str)) {
1665         prefix = str;
1666       }
1667       continue;
1668     }
1669     if (StringCmp (field, "StructuredCommentSuffix") == 0) {
1670       str = (CharPtr) curr->data.ptrvalue;
1671       if (StringDoesHaveText (str)) {
1672         suffix = str;
1673       }
1674       continue;
1675     }
1676     len = StringLen (field);
1677     if (len > max) {
1678       max = len;
1679     }
1680   }
1681 
1682   if (StringHasNoText (prefix)) {
1683     prefix = "##Metadata-START##";
1684   }
1685   if (StringHasNoText (suffix)) {
1686     suffix = "##Metadata-END##";
1687   }
1688 
1689   if (StringDoesHaveText (prefix)) {
1690     tmp = (CharPtr) MemNew (StringLen (prefix) + 4);
1691     if (tmp != NULL) {
1692       sprintf (tmp, "%s\n", prefix);
1693       ValNodeAddStr (&head, 0, tmp);  
1694     }
1695   }
1696   if (max > ThresholdForStructuredCommentColumnarDisplay (awp->format)) {
1697     for (curr = uop->data; curr != NULL; curr = curr->next) {
1698      if (curr->choice != 1) continue;
1699       oip = curr->label;
1700       if (oip == NULL) continue;
1701       field = oip->str;
1702       if (StringHasNoText (field)) continue;
1703       if (StringCmp (field, "StructuredCommentPrefix") == 0) continue;
1704       if (StringCmp (field, "StructuredCommentSuffix") == 0) continue;
1705       str = (CharPtr) curr->data.ptrvalue;
1706       if (StringHasNoText (str)) continue;
1707       ValNodeCopyStr (&head, 0, field);
1708       ValNodeCopyStr (&head, 0, " ");
1709       ValNodeCopyStr (&head, 0, str);
1710       ValNodeCopyStr (&head, 0, "\n");
1711     }
1712   } else {
1713     for (curr = uop->data; curr != NULL; curr = curr->next) {
1714      if (curr->choice != 1) continue;
1715       oip = curr->label;
1716       if (oip == NULL) continue;
1717       field = oip->str;
1718       if (StringHasNoText (field)) continue;
1719       if (StringCmp (field, "StructuredCommentPrefix") == 0) continue;
1720       if (StringCmp (field, "StructuredCommentSuffix") == 0) continue;
1721       str = (CharPtr) curr->data.ptrvalue;
1722       if (StringHasNoText (str)) continue;
1723       len = max + StringLen (str) + 4;
1724       FFStartPrint (ffstring, GENBANK_FMT, 0, max + 1, field, max + 1, 0, max + 1, field, TRUE);
1725       if (GetWWW (ajp) && StringCmp (field, "GOLD Stamp ID") == 0 && StringNCmp (str, "Gi", 2) == 0) {
1726         FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
1727         FF_Add_NCBI_Base_URL (ffstring, link_gold_stamp_id);
1728         FFAddOneString (ffstring, str, FALSE, FALSE, TILDE_EXPAND);
1729         FFAddOneString (ffstring, ".html", FALSE, FALSE, TILDE_EXPAND);
1730         FFAddOneString (ffstring, "\">", FALSE, FALSE, TILDE_IGNORE);
1731         FFAddOneString (ffstring, str, FALSE, FALSE, TILDE_EXPAND);
1732         FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
1733       } else {
1734         FFAddOneString (ffstring, str, FALSE, FALSE, TILDE_EXPAND);
1735       }
1736       /*
1737       FFAddOneString (ffstring, "\n", FALSE, FALSE, TILDE_EXPAND);
1738       */
1739       tmp = StrucCommentFFEndPrint (ajp, ffstring, awp->format, max + 1, max + 1, 0, max + 1, NULL);
1740       ValNodeCopyStr (&head, 0, tmp);
1741       MemFree (tmp);
1742       FFRecycleString (ajp, ffstring);
1743       ffstring = FFGetString (ajp);
1744       /*
1745       tmp = (CharPtr) MemNew (len);
1746       if (tmp == NULL) continue;
1747       StringCpy (tmp, field);
1748       len = StringLen (tmp);
1749       while (len < max) {
1750         tmp [len] = ' ';
1751         len++;
1752       }
1753       tmp [len] = '\0';
1754       StringCat (tmp, " ");
1755       StringCat (tmp, str);
1756       StringCat (tmp, "\n");
1757       ValNodeCopyStr (&head, 0, tmp);
1758       MemFree (tmp);
1759       */
1760     }
1761   }
1762   if (StringDoesHaveText (suffix)) {
1763     tmp = (CharPtr) MemNew (StringLen (suffix) + 4);
1764     if (tmp != NULL) {
1765       sprintf (tmp, "%s\n", suffix);
1766       ValNodeAddStr (&head, 0, tmp);  
1767     }
1768   }
1769 
1770   if (head == NULL) return NULL;
1771 
1772   str = MergeFFValNodeStrs (head);
1773   ValNodeFreeData (head);
1774 
1775   FFRecycleString (ajp, ffstring);
1776 
1777   return str;
1778 }
1779 
1780 static void AddAltPrimaryBlock (
1781   Asn2gbWorkPtr awp
1782 )
1783 
1784 {
1785   IntAsn2gbJobPtr  ajp;
1786   Asn2gbSectPtr    asp;
1787   BaseBlockPtr     bbp = NULL;
1788   BioseqPtr        bsp;
1789   GBSeqPtr         gbseq;
1790   CharPtr          str;
1791   StringItemPtr    ffstring;
1792 
1793   if (awp == NULL) return;
1794   ajp = awp->ajp;
1795   if (ajp == NULL) return;
1796   bsp = awp->bsp;
1797   if (bsp == NULL) return;
1798   asp = awp->asp;
1799   if (asp == NULL) return;
1800 
1801   ffstring = FFGetString(ajp);
1802   if ( ffstring == NULL ) return;
1803 
1804   str = GetPrimaryStrForDelta (bsp);
1805   if (str != NULL) {
1806 
1807     bbp = (BaseBlockPtr) Asn2gbAddBlock (awp, PRIMARY_BLOCK, sizeof (BaseBlock));
1808     if (bbp != NULL) {
1809 
1810       FFStartPrint (ffstring, awp->format, 0, 12, "PRIMARY", 12, 5, 5, "PR", TRUE);
1811 
1812       FFAddOneString (ffstring, str, FALSE, FALSE, TILDE_EXPAND);
1813 
1814       bbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "PR");
1815 
1816       /* optionally populate gbseq for XML-ized GenBank format */
1817 
1818       if (ajp->gbseq) {
1819         gbseq = &asp->gbseq;
1820       } else {
1821         gbseq = NULL;
1822       }
1823 
1824       if (gbseq != NULL) {
1825         gbseq->primary = StringSave (str);
1826       }
1827 
1828       if (awp->afp != NULL) {
1829         DoImmediateFormat (awp->afp, (BaseBlockPtr) bbp);
1830       }
1831     }
1832     MemFree (str);
1833   }
1834 
1835   FFRecycleString(ajp, ffstring);
1836 }
1837 
1838 static CharPtr GeStrForTSA (
1839   UserObjectPtr uop
1840 )
1841 
1842 {
1843   Int4          asf, ast, prf, prt;
1844   Char          buf [80], tmp [80];
1845   UserFieldPtr  curr;
1846   Boolean       has_asf, has_ast, has_prf, has_prt;
1847   ValNodePtr    head = NULL;
1848   ObjectIdPtr   oip;
1849   CharPtr       pid;
1850   CharPtr       str;
1851   UserFieldPtr  ufp;
1852 
1853   if (uop == NULL) return NULL;
1854   if ((oip = uop->type) == NULL) return NULL;
1855   if (StringCmp (oip->str, "TSA") != 0) return NULL;
1856 
1857   for (curr = uop->data; curr != NULL; curr = curr->next) {
1858     if (curr->choice != 11) continue;
1859     asf = 0;
1860     ast = 0;
1861     prf = 0;
1862     prt = 0;
1863     pid = NULL;
1864     has_asf = FALSE;
1865     has_ast = FALSE;
1866     has_prf = FALSE;
1867     has_prt = FALSE;
1868     for (ufp = curr->data.ptrvalue; ufp != NULL; ufp = ufp->next) {
1869       oip = ufp->label;
1870       if (oip == NULL) continue;
1871       if (StringICmp (oip->str, "assembly from") == 0 && ufp->choice == 2) {
1872         asf = (Int4) ufp->data.intvalue;
1873         has_asf = TRUE;
1874       } else if (StringICmp (oip->str, "assembly to") == 0 && ufp->choice == 2) {
1875         ast = (Int4) ufp->data.intvalue;
1876         has_ast = TRUE;
1877       } else if (StringICmp (oip->str, "primary from") == 0 && ufp->choice == 2) {
1878         prf = (Int4) ufp->data.intvalue;
1879         has_prf = TRUE;
1880       } else if (StringICmp (oip->str, "primary to") == 0 && ufp->choice == 2) {
1881         prt = (Int4) ufp->data.intvalue;
1882         has_prt = TRUE;
1883       } else if (StringICmp (oip->str, "primary ID") == 0 && ufp->choice == 1) {
1884         pid = (CharPtr) ufp->data.ptrvalue;
1885       }
1886     }
1887     if (has_asf && has_ast && has_prf && has_prt && pid != NULL) {
1888       if (head == NULL) {
1889         ValNodeCopyStr (&head, 0, "TSA_SPAN            PRIMARY_IDENTIFIER PRIMARY_SPAN        COMP");
1890       }
1891       StringCpy (buf, pid);
1892       if (StringNCmp (pid, "gnl|ti|", 7) == 0) {
1893         StringCpy (buf, "TI");
1894         StringCat (buf, pid + 7);
1895       }
1896       sprintf (tmp, "~%ld-%ld                                        ",
1897                (long) (asf + 1), (long) (ast + 1));
1898       tmp [21] = '\0';
1899       StringCat (buf, "                                        ");
1900       buf [18] = '\0';
1901       StringCat (tmp, buf);
1902       sprintf (buf, " %ld-%ld                                        ",
1903                (long) (prf + 1), (long) (prt + 1));
1904       buf [21] = '\0';
1905       StringCat (tmp, buf);
1906       if (prf > prt) {
1907         StringCat (tmp, "c");
1908       }
1909       ValNodeCopyStr (&head, 0, tmp);
1910     }
1911   }
1912 
1913   if (head == NULL) return NULL;
1914 
1915   str = MergeFFValNodeStrs (head);
1916   ValNodeFreeData (head);
1917 
1918   return str;
1919 }
1920 
1921 static void AddTsaBlock (
1922   Asn2gbWorkPtr awp,
1923   UserObjectPtr uop
1924 )
1925 
1926 {
1927   IntAsn2gbJobPtr  ajp;
1928   Asn2gbSectPtr    asp;
1929   BaseBlockPtr     bbp = NULL;
1930   BioseqPtr        bsp;
1931   GBSeqPtr         gbseq;
1932   CharPtr          str;
1933   StringItemPtr    ffstring;
1934 
1935   if (awp == NULL) return;
1936   ajp = awp->ajp;
1937   if (ajp == NULL) return;
1938   bsp = awp->bsp;
1939   if (bsp == NULL) return;
1940   asp = awp->asp;
1941   if (asp == NULL) return;
1942 
1943   ffstring = FFGetString(ajp);
1944   if ( ffstring == NULL ) return;
1945 
1946   str = GeStrForTSA (uop);
1947   if (str != NULL) {
1948 
1949     bbp = (BaseBlockPtr) Asn2gbAddBlock (awp, PRIMARY_BLOCK, sizeof (BaseBlock));
1950     if (bbp != NULL) {
1951 
1952       FFStartPrint (ffstring, awp->format, 0, 12, "PRIMARY", 12, 5, 5, "PR", TRUE);
1953 
1954       FFAddOneString (ffstring, str, FALSE, FALSE, TILDE_EXPAND);
1955 
1956       bbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "PR");
1957 
1958       /* optionally populate gbseq for XML-ized GenBank format */
1959 
1960       if (ajp->gbseq) {
1961         gbseq = &asp->gbseq;
1962       } else {
1963         gbseq = NULL;
1964       }
1965 
1966       if (gbseq != NULL) {
1967         gbseq->primary = StringSave (str);
1968       }
1969 
1970       if (awp->afp != NULL) {
1971         DoImmediateFormat (awp->afp, (BaseBlockPtr) bbp);
1972       }
1973     }
1974     MemFree (str);
1975   }
1976 
1977   FFRecycleString(ajp, ffstring);
1978 }
1979 
1980 NLM_EXTERN void AddPrimaryBlock (
1981   Asn2gbWorkPtr awp
1982 )
1983 
1984 {
1985   IntAsn2gbJobPtr    ajp;
1986   Asn2gbSectPtr      asp;
1987   BaseBlockPtr       bbp = NULL;
1988   BioseqPtr          bsp;
1989   SeqMgrDescContext  dcontext;
1990   GBSeqPtr           gbseq;
1991   Boolean            has_tpa_assembly = FALSE;
1992   Boolean            has_tsa = FALSE;
1993   SeqHistPtr         hist;
1994   Boolean            isRefSeq = FALSE;
1995   Boolean            isTsa = FALSE;
1996   ObjectIdPtr        oip;
1997   SeqDescrPtr        sdp;
1998   CharPtr            str;
1999   UserObjectPtr      uop;
2000   StringItemPtr      ffstring;
2001 
2002   if (awp == NULL) return;
2003   ajp = awp->ajp;
2004   if (ajp == NULL) return;
2005   bsp = awp->bsp;
2006   if (bsp == NULL) return;
2007   asp = awp->asp;
2008   if (asp == NULL) return;
2009 
2010   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_user, &dcontext);
2011   while (sdp != NULL) {
2012     uop = (UserObjectPtr) sdp->data.ptrvalue;
2013     if (uop != NULL) {
2014       oip = uop->type;
2015       if (oip != NULL) {
2016         if (StringCmp (oip->str, "TpaAssembly") == 0) {
2017           has_tpa_assembly = TRUE;
2018         } else if (StringCmp (oip->str, "TSA") == 0) {
2019           has_tsa = TRUE;
2020         }
2021       }
2022     }
2023     if (has_tpa_assembly || has_tsa) {
2024       sdp = NULL;
2025     } else {
2026       sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_user, &dcontext);
2027     }
2028   }
2029 
2030   if (has_tsa) {
2031     AddTsaBlock (awp, uop);
2032     return;
2033   }
2034 
2035   hist = bsp->hist;
2036   if ((! IsTpa (bsp, has_tpa_assembly, &isRefSeq, &isTsa)) ||
2037       hist == NULL || hist->assembly == NULL) {
2038     if (awp->forcePrimaryBlock) {
2039       AddAltPrimaryBlock (awp);
2040     }
2041     return;
2042   }
2043 
2044   ffstring = FFGetString(ajp);
2045   if ( ffstring == NULL ) return;
2046 
2047   str = GetStrForTpaOrRefSeqHist (bsp, isRefSeq, isTsa);
2048   if (str != NULL) {
2049 
2050     bbp = (BaseBlockPtr) Asn2gbAddBlock (awp, PRIMARY_BLOCK, sizeof (BaseBlock));
2051     if (bbp != NULL) {
2052 
2053       if (has_tpa_assembly) {
2054         bbp->entityID = dcontext.entityID;
2055         bbp->itemID = dcontext.itemID;
2056         bbp->itemtype = OBJ_SEQDESC;
2057       }
2058 
2059       FFStartPrint (ffstring, awp->format, 0, 12, "PRIMARY", 12, 5, 5, "PR", TRUE);
2060 
2061       FFAddOneString (ffstring, str, FALSE, FALSE, TILDE_EXPAND);
2062 
2063       bbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "PR");
2064 
2065       /* optionally populate gbseq for XML-ized GenBank format */
2066 
2067       if (ajp->gbseq) {
2068         gbseq = &asp->gbseq;
2069       } else {
2070         gbseq = NULL;
2071       }
2072 
2073       if (gbseq != NULL) {
2074         gbseq->primary = StringSave (str);
2075       }
2076 
2077       if (awp->afp != NULL) {
2078         DoImmediateFormat (awp->afp, (BaseBlockPtr) bbp);
2079       }
2080     }
2081     MemFree (str);
2082   }
2083 
2084   FFRecycleString(ajp, ffstring);
2085 }
2086 
2087 static CharPtr reftxt32 = "It is defined by coordinates on the sequence of chromosome";
2088 static CharPtr reftxt33 = "from the";
2089 static CharPtr reftxt34 = "assembly of the human genome (NCBI build";
2090 static CharPtr reftxt35 = ").";
2091 
2092 /*
2093 static CharPtr GetDBLinkString (
2094   UserObjectPtr uop
2095 )
2096 
2097 {
2098   Char          buf [128];
2099   Int4Ptr       ip;
2100   ObjectIdPtr   oip;
2101   UserFieldPtr  ufp;
2102   Int4          val;
2103 
2104   if (uop == NULL) return NULL;
2105 
2106   for (ufp = uop->data; ufp != NULL; ufp = ufp->next) {
2107     oip = ufp->label;
2108     if (oip == NULL || oip->str == NULL || ufp->choice != 8) continue;
2109     if (StringICmp (oip->str, "Trace Assembly Archive") == 0) {
2110       ip = (Int4Ptr) ufp->data.ptrvalue;
2111       if (ufp->num > 0 && ip != NULL) {
2112         val = ip [0];
2113         if (val > 0) {
2114           sprintf (buf, "Trace Assembly Archive:%ld", (long) val);
2115           return StringSave (buf);
2116         }
2117       }
2118     }
2119   }
2120 
2121   return NULL;
2122 }
2123 */
2124 
2125 static CharPtr GetEncodeString (
2126   UserObjectPtr uop,
2127   BioseqPtr bsp
2128 )
2129 
2130 {
2131   CharPtr            assembly_date = NULL;
2132   BioSourcePtr       biop;
2133   CharPtr            chromosome = NULL;
2134   SeqMgrDescContext  dcontext;
2135   size_t             len;
2136   CharPtr            ncbi_annotation = NULL;
2137   ObjectIdPtr        oip;
2138   SeqDescrPtr        sdp;
2139   SubSourcePtr       ssp;
2140   CharPtr            str;
2141   UserFieldPtr       ufp;
2142 
2143   if (uop == NULL || bsp == NULL) return NULL;
2144 
2145   for (ufp = uop->data; ufp != NULL; ufp = ufp->next) {
2146     oip = ufp->label;
2147     if (oip == NULL || oip->str == NULL || ufp->choice != 1) continue;
2148     if (StringICmp (oip->str, "AssemblyDate") == 0) {
2149       assembly_date = (CharPtr) ufp->data.ptrvalue;
2150     } else if (StringICmp (oip->str, "NcbiAnnotation") == 0) {
2151       ncbi_annotation = (CharPtr) ufp->data.ptrvalue;
2152     }
2153   }
2154 
2155   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_source, &dcontext);
2156   if (sdp != NULL) {
2157     biop = (BioSourcePtr) sdp->data.ptrvalue;
2158     if (biop != NULL) {
2159       for (ssp = biop->subtype; ssp != NULL; ssp = ssp->next) {
2160         if (ssp->subtype == SUBSRC_chromosome) {
2161           chromosome = ssp->name;
2162         }
2163       }
2164     }
2165   }
2166 
2167   if (chromosome == NULL || assembly_date == NULL || ncbi_annotation == NULL) return NULL;
2168 
2169   if (StringHasNoText (chromosome)) {
2170     chromosome = "?";
2171   }
2172   if (StringHasNoText (assembly_date)) {
2173     assembly_date = "?";
2174   }
2175   if (StringHasNoText (ncbi_annotation)) {
2176     ncbi_annotation = "?";
2177   }
2178 
2179   len = StringLen (reftxt32) + StringLen (reftxt33) +
2180         StringLen (reftxt34) + StringLen (reftxt35) +
2181         StringLen (chromosome) +
2182         StringLen (assembly_date) +
2183         StringLen (ncbi_annotation);
2184 
2185   str = (CharPtr) MemNew (sizeof (Char) * (len + 10));
2186   if (str == NULL) return NULL;
2187 
2188   sprintf (str, "%s %s %s %s %s %s%s", reftxt32, chromosome, reftxt33,
2189            assembly_date, reftxt34, ncbi_annotation, reftxt35);
2190 
2191   return str;
2192 }
2193 
2194 NLM_EXTERN void AddCommentBlock (
2195   Asn2gbWorkPtr awp
2196 )
2197 
2198 {
2199   size_t             acclen;
2200   SeqMgrAndContext   acontext;
2201   AnnotDescPtr       adp;
2202   Boolean            annotDescCommentToComment;
2203   IntAsn2gbJobPtr    ajp;
2204   BioseqPtr          bsp;
2205   Char               buf [1024];
2206   CommentBlockPtr    cbp;
2207   Char               ch;
2208   Boolean            didGenome = FALSE;
2209   Boolean            didRefTrack = FALSE;
2210   Boolean            didTPA = FALSE;
2211   DbtagPtr           dbt;
2212   SeqMgrDescContext  dcontext;
2213   /*
2214   UserObjectPtr      dblinkUop = NULL;
2215   */
2216   DeltaSeqPtr        dsp;
2217   UserObjectPtr      encodeUop = NULL;
2218   Boolean            estEv = FALSE;
2219   /*
2220   SeqMgrFeatContext  fcontext;
2221   */
2222   Boolean            first = TRUE;
2223   GBBlockPtr         gbp;
2224   CharPtr            geneName = NULL;
2225   CharPtr            genomeBuildNumber = NULL;
2226   CharPtr            genomeVersionNumber = NULL;
2227   Int4               gi = 0;
2228   Int4               gsdbid = 0;
2229   Boolean            has_gaps = FALSE;
2230   Boolean            hasRefTrackStatus = FALSE;
2231   SeqHistPtr         hist;
2232   Boolean            is_collab = FALSE;
2233   Boolean            is_encode = FALSE;
2234   Boolean            is_other = FALSE;
2235   Boolean            is_tpa = FALSE;
2236   Boolean            is_wgs = FALSE;
2237   SeqLitPtr          litp;
2238   ObjectIdPtr        localID = NULL;
2239   Char               locusID [32];
2240   CharPtr            method = NULL;
2241   MolInfoPtr         mip;
2242   Boolean            mrnaEv = FALSE;
2243   CharPtr            name = NULL;
2244   ObjectIdPtr        ncbifileID = NULL;
2245   ObjectIdPtr        oip;
2246   Boolean            okay;
2247   BioseqPtr          parent;
2248   SeqDescrPtr        sdp;
2249   /*
2250   SeqFeatPtr         sfp;
2251   */
2252   Boolean            showGBBSource = FALSE;
2253   SeqIdPtr           sip;
2254   CharPtr            str;
2255   Char               taxID [32];
2256   Char               tmp [32];
2257   TextSeqIdPtr       tsip;
2258   UserFieldPtr       ufp;
2259   UserObjectPtr      uop = NULL;
2260   CharPtr            wgsaccn = NULL;
2261   CharPtr            wgsname = NULL;
2262   StringItemPtr      ffstring = NULL;
2263 
2264   if (awp == NULL) return;
2265   ajp = awp->ajp;
2266   if (ajp == NULL) return;
2267   bsp = awp->bsp;
2268   if (bsp == NULL) return;
2269 
2270   if (GetWWW (ajp) && awp->mode == ENTREZ_MODE && awp->afp != NULL &&
2271       (awp->format == GENBANK_FMT || awp->format == GENPEPT_FMT)) {
2272     sprintf (buf, "<a name=\"comment_%ld\"></a>", (long) awp->currGi);
2273     DoQuickLinkFormat (awp->afp, buf);
2274   }
2275 
2276   ffstring = FFGetString(ajp);
2277   if ( ffstring ==  NULL ) return;
2278 
2279   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_user, &dcontext);
2280   while (sdp != NULL) {
2281     uop = (UserObjectPtr) sdp->data.ptrvalue;
2282     if (uop != NULL) {
2283       str = GetStatusForRefTrack (uop);
2284       if (str != NULL) {
2285         hasRefTrackStatus = TRUE;
2286       }
2287       if (genomeBuildNumber == NULL) {
2288         genomeBuildNumber = GetGenomeBuildNumber (uop);
2289       }
2290       if (genomeVersionNumber == NULL) {
2291         genomeVersionNumber = GetGenomeVersionNumber (uop);
2292       }
2293       oip = uop->type;
2294       if (oip != NULL) {
2295         if (StringICmp (oip->str, "ENCODE") == 0) {
2296           is_encode = TRUE;
2297           encodeUop = uop;
2298         }
2299         /*
2300         if (StringICmp (oip->str, "DBLink") == 0) {
2301           dblinkUop = uop;
2302         }
2303         */
2304       }
2305     }
2306     sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_user, &dcontext);
2307   }
2308 
2309   /*
2310   if (dblinkUop != NULL) {
2311     str = GetDBLinkString (dblinkUop);
2312     if (StringDoesHaveText (str)) {
2313       cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
2314       if (cbp != NULL) {
2315 
2316         cbp->entityID = awp->entityID;
2317         cbp->first = first;
2318         first = FALSE;
2319 
2320         if (cbp->first) {
2321           FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
2322         } else {
2323           FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
2324         }
2325 
2326         FFAddOneString (ffstring, str, FALSE, FALSE, TILDE_EXPAND);
2327 
2328         cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
2329         FFRecycleString(ajp, ffstring);
2330         ffstring = FFGetString(ajp);
2331 
2332         if (awp->afp != NULL) {
2333           DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
2334         }
2335       }
2336     }
2337   }
2338   */
2339 
2340   for (sip = bsp->id; sip != NULL; sip = sip->next) {
2341     if (sip->choice == SEQID_OTHER) {
2342       tsip = (TextSeqIdPtr) sip->data.ptrvalue;
2343 
2344       if (tsip != NULL) {
2345         is_other = TRUE;
2346         if (StringNCmp (tsip->accession, "NC_", 3) == 0) {
2347           if (hasRefTrackStatus) {
2348             /* will print elsewhere */
2349           } else if (! StringHasNoText (genomeBuildNumber)) {
2350             cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
2351             if (cbp != NULL) {
2352 
2353               cbp->entityID = awp->entityID;
2354               cbp->first = first;
2355               first = FALSE;
2356 
2357               if (cbp->first) {
2358                 FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
2359               } else {
2360                 FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
2361               }
2362 
2363               FFAddOneString (ffstring, "GENOME ANNOTATION ", FALSE, FALSE, TILDE_IGNORE);
2364 
2365               if ( GetWWW(ajp) ) {
2366                 FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
2367                 FF_Add_NCBI_Base_URL (ffstring, ref_link);
2368                 FFAddOneString (ffstring, "\">", FALSE, FALSE, TILDE_IGNORE);
2369               }
2370               FFAddOneString (ffstring, "REFSEQ", FALSE, FALSE, TILDE_IGNORE);
2371               if ( GetWWW(ajp) ) {
2372                 FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
2373               }
2374               FFAddOneString (ffstring, ": ", FALSE, FALSE, TILDE_IGNORE);
2375 
2376               FFAddOneString (ffstring, reftxt22, FALSE, FALSE, TILDE_EXPAND);
2377               FFAddOneString (ffstring, genomeBuildNumber, FALSE, FALSE, TILDE_EXPAND);
2378               if (StringHasNoText (genomeVersionNumber)) {
2379                 genomeVersionNumber = "1";
2380               }
2381               FFAddOneString (ffstring, " version ", FALSE, FALSE, TILDE_EXPAND);
2382               FFAddOneString (ffstring, genomeVersionNumber, FALSE, FALSE, TILDE_EXPAND);
2383               FFAddOneString (ffstring, reftxt23, FALSE, FALSE, TILDE_EXPAND);
2384 
2385               FFAddOneString (ffstring, " [see ", FALSE, FALSE, TILDE_EXPAND);
2386 
2387               if ( GetWWW(ajp) ) {
2388                 FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
2389                 FF_Add_NCBI_Base_URL (ffstring, doc_link);
2390                 FFAddOneString (ffstring, "\">", FALSE, FALSE, TILDE_IGNORE);
2391               }
2392               FFAddOneString (ffstring, "documentation", FALSE, FALSE, TILDE_IGNORE);
2393               if ( GetWWW(ajp) ) {
2394                 FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
2395               }
2396 
2397               FFAddOneString (ffstring, "].", FALSE, FALSE, TILDE_EXPAND);
2398 
2399               cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
2400               FFRecycleString(ajp, ffstring);
2401               ffstring = FFGetString(ajp);
2402 
2403               if (awp->afp != NULL) {
2404                 DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
2405               }
2406             }
2407           }
2408 
2409         } else if (StringNCmp(tsip->accession, "NT_", 3) == 0 || StringNCmp(tsip->accession, "NW_", 3) == 0) {
2410 
2411           if (is_encode) {
2412             cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
2413             if (cbp != NULL) {
2414 
2415               cbp->entityID = awp->entityID;
2416               cbp->first = first;
2417               first = FALSE;
2418 
2419               if (cbp->first) {
2420                 FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
2421               } else {
2422                 FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
2423               }
2424 
2425               FFAddOneString (ffstring, "REFSEQ", FALSE, FALSE, TILDE_IGNORE);
2426               FFAddOneString (ffstring, ":  ", FALSE, FALSE, TILDE_IGNORE);
2427 
2428               FFAddOneString (ffstring, "This record was provided by the ", FALSE, FALSE, TILDE_EXPAND);
2429               if ( GetWWW(ajp) ) {
2430                 FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
2431                 FF_Add_NCBI_Base_URL (ffstring, link_encode);
2432                 FFAddOneString (ffstring, "\">", FALSE, FALSE, TILDE_IGNORE);
2433               }
2434               FFAddOneString (ffstring, "ENCODE", FALSE, FALSE, TILDE_EXPAND);
2435               if ( GetWWW(ajp) ) {
2436                 FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
2437               }
2438               FFAddOneString (ffstring, " project.", FALSE, FALSE, TILDE_EXPAND);
2439 
2440               str = GetEncodeString (encodeUop, bsp);
2441               if (str != NULL) {
2442                 FFAddOneString (ffstring, "  ", FALSE, FALSE, TILDE_EXPAND);
2443                 FFAddOneString (ffstring, str, FALSE, FALSE, TILDE_EXPAND);
2444               }
2445               MemFree (str);
2446 
2447               cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
2448               FFRecycleString(ajp, ffstring);
2449               ffstring = FFGetString(ajp);
2450 
2451               if (awp->afp != NULL) {
2452                 DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
2453               }
2454             }
2455 
2456           } else if (! hasRefTrackStatus) {
2457 
2458             cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
2459             if (cbp != NULL) {
2460 
2461               cbp->entityID = awp->entityID;
2462               cbp->first = first;
2463               first = FALSE;
2464 
2465               if (cbp->first) {
2466                 FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
2467               } else {
2468                 FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
2469               }
2470 
2471               FFAddOneString (ffstring, "GENOME ANNOTATION ", FALSE, FALSE, TILDE_IGNORE);
2472 
2473               if ( GetWWW(ajp) ) {
2474                 FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
2475                 FF_Add_NCBI_Base_URL (ffstring, ref_link);
2476                 FFAddOneString (ffstring, "\">", FALSE, FALSE, TILDE_IGNORE);
2477               }
2478               FFAddOneString (ffstring, "REFSEQ", FALSE, FALSE, TILDE_IGNORE);
2479               if ( GetWWW(ajp) ) {
2480                 FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
2481               }
2482               FFAddOneString (ffstring, ":  ", FALSE, FALSE, TILDE_IGNORE);
2483 
2484               if (! StringHasNoText (genomeBuildNumber)) {
2485                 FFAddOneString (ffstring, reftxt22, FALSE, FALSE, TILDE_EXPAND);
2486                 FFAddOneString (ffstring, genomeBuildNumber, FALSE, FALSE, TILDE_EXPAND);
2487                 if (StringHasNoText (genomeVersionNumber)) {
2488                   genomeVersionNumber = "1";
2489                 }
2490                 FFAddOneString (ffstring, " version ", FALSE, FALSE, TILDE_EXPAND);
2491                 FFAddOneString (ffstring, genomeVersionNumber, FALSE, FALSE, TILDE_EXPAND);
2492                 FFAddOneString (ffstring, reftxt23, FALSE, FALSE, TILDE_EXPAND);
2493 
2494                 FFAddOneString (ffstring, " [see ", FALSE, FALSE, TILDE_EXPAND);
2495 
2496                 if ( GetWWW(ajp) ) {
2497                   FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
2498                   FF_Add_NCBI_Base_URL (ffstring, doc_link);
2499                   FFAddOneString (ffstring, "\">", FALSE, FALSE, TILDE_IGNORE);
2500                 }
2501                 FFAddOneString (ffstring, "documentation", FALSE, FALSE, TILDE_IGNORE);
2502                 if ( GetWWW(ajp) ) {
2503                   FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
2504                 }
2505 
2506                 FFAddOneString (ffstring, "].", FALSE, FALSE, TILDE_EXPAND);
2507               } else {
2508 
2509                 FFAddOneString (ffstring, reftxt21, TRUE, FALSE, TILDE_EXPAND);
2510 
2511                 FFAddOneString (ffstring, "~Also see:~    ", FALSE, FALSE, TILDE_EXPAND);
2512 
2513                 if ( GetWWW(ajp) ) {
2514                   FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
2515                   FF_Add_NCBI_Base_URL (ffstring, doc_link);
2516                   FFAddOneString (ffstring, "\">", FALSE, FALSE, TILDE_IGNORE);
2517                 }
2518                 FFAddOneString (ffstring, "Documentation", FALSE, FALSE, TILDE_IGNORE);
2519                 if ( GetWWW(ajp) ) {
2520                   FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
2521                 }
2522 
2523                 FFAddOneString (ffstring, " of NCBI's Annotation Process~    ", FALSE, FALSE, TILDE_EXPAND);
2524               }
2525 
2526               cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
2527               FFRecycleString(ajp, ffstring);
2528               ffstring = FFGetString(ajp);
2529 
2530               if (awp->afp != NULL) {
2531                 DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
2532               }
2533             }
2534           }
2535 
2536         } else if (StringNCmp(tsip->accession, "XP_", 3) == 0 ||
2537                    StringNCmp(tsip->accession, "XM_", 3) == 0 ||
2538                    StringNCmp(tsip->accession, "XR_", 3) == 0 ||
2539                    StringNCmp(tsip->accession, "ZP_", 3) == 0) {
2540 
2541           name = NULL;
2542           method = NULL;
2543           mrnaEv = FALSE;
2544           estEv = FALSE;
2545           if (GetAnnotationComment (bsp, &name, &method, &mrnaEv, &estEv)) {
2546 
2547             cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
2548             if (cbp != NULL) {
2549 
2550               cbp->entityID = awp->entityID;
2551               cbp->first = first;
2552               first = FALSE;
2553 
2554               if (cbp->first) {
2555                 FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
2556               } else {
2557                 FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
2558               }
2559 
2560               FFAddOneString (ffstring, "MODEL ", FALSE, FALSE, TILDE_IGNORE);
2561 
2562               if ( GetWWW(ajp) ) {
2563                 FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
2564                 FF_Add_NCBI_Base_URL (ffstring, ref_link);
2565                 FFAddOneString (ffstring, "\">", FALSE, FALSE, TILDE_IGNORE);
2566               }
2567               FFAddOneString (ffstring, "REFSEQ", FALSE, FALSE, TILDE_IGNORE);
2568               if ( GetWWW(ajp) ) {
2569                 FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
2570               }
2571               FFAddOneString (ffstring, ":  ", FALSE, FALSE, TILDE_IGNORE);
2572 
2573               FFAddTextToString (ffstring, NULL, reftxt11, " (", FALSE, FALSE, TILDE_IGNORE);
2574 
2575               if ( GetWWW(ajp) ) {
2576                 FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
2577                 if (IS_ntdb_accession (name)) {
2578                   FF_Add_NCBI_Base_URL (ffstring, link_seqn);
2579                 } else {
2580                   FF_Add_NCBI_Base_URL (ffstring, link_seqp);
2581                 }
2582                 gi = 0;
2583                 if (ValidateAccnDotVer (name) == 0 && GetGiFromAccnDotVer (name, &gi)) {
2584                   sprintf (tmp, "%ld", (long) gi);
2585                   FFAddOneString (ffstring, tmp, FALSE, FALSE, TILDE_IGNORE);
2586                 } else {
2587                   FFAddOneString (ffstring, name, FALSE, FALSE, TILDE_IGNORE);
2588                 }
2589                 gi = 0;
2590                 FFAddOneString (ffstring, "?report=graph", FALSE, FALSE, TILDE_IGNORE);
2591                 FFAddOneString (ffstring, "\">", FALSE, FALSE, TILDE_IGNORE);
2592                 FFAddOneString (ffstring, name, FALSE, FALSE, TILDE_IGNORE);
2593                 FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
2594               } else {
2595                 FFAddOneString (ffstring, name, FALSE, FALSE, TILDE_IGNORE);
2596               }
2597 
2598               FFAddOneString (ffstring, ")", FALSE, FALSE, TILDE_IGNORE);
2599  
2600               if (method != NULL) {
2601                 FFAddOneString (ffstring, " ", FALSE, FALSE, TILDE_IGNORE);
2602                 FFAddOneString (ffstring, reftxt12, FALSE, FALSE, TILDE_IGNORE);
2603                 FFAddOneString (ffstring, " ", FALSE, FALSE, TILDE_IGNORE);
2604                 FFAddOneString (ffstring, method, FALSE, FALSE, TILDE_IGNORE);
2605               }
2606 
2607               if (mrnaEv || estEv) {
2608                 FFAddOneString (ffstring, ", supported by ", FALSE, FALSE, TILDE_IGNORE);
2609                 if (mrnaEv && estEv) {
2610                   FFAddOneString (ffstring, "mRNA and EST ", FALSE, FALSE, TILDE_IGNORE);
2611                 } else if (mrnaEv) {
2612                   FFAddOneString (ffstring, "mRNA ", FALSE, FALSE, TILDE_IGNORE);
2613                 } else {
2614                   FFAddOneString (ffstring, "EST ", FALSE, FALSE, TILDE_IGNORE);
2615                 }
2616                 geneName = NULL;
2617                 locusID [0] = '\0';
2618                 taxID [0] = '\0';
2619                 if ( GetWWW(ajp) && GetGeneAndLocus (bsp, &geneName, locusID, taxID)) {
2620                   FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
2621                   FF_Add_NCBI_Base_URL (ffstring, ev_link);
2622                   FFAddTextToString (ffstring, "contig=", name, NULL, FALSE, FALSE, TILDE_IGNORE);
2623                   FFAddTextToString (ffstring, "&gene=", geneName, NULL, FALSE, FALSE, TILDE_IGNORE);
2624                   FFAddTextToString (ffstring, "&lid=", locusID, NULL, FALSE, FALSE, TILDE_IGNORE);
2625                   if (! StringHasNoText (taxID)) {
2626                     FFAddTextToString (ffstring, "&taxid=", taxID, NULL, FALSE, FALSE, TILDE_IGNORE);
2627                   }
2628                   FFAddOneString (ffstring, "\">", FALSE, FALSE, TILDE_IGNORE);
2629                   FFAddOneString (ffstring, "evidence", FALSE, FALSE, TILDE_IGNORE);
2630                   FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
2631                 } else {
2632                   FFAddOneString (ffstring, "evidence", FALSE, FALSE, TILDE_IGNORE);
2633                 }
2634               }
2635 
2636               FFAddOneString (ffstring, ".", FALSE, FALSE, TILDE_IGNORE);
2637 
2638               FFAddOneString (ffstring, "~Also see:~    ", FALSE, FALSE, TILDE_EXPAND);
2639 
2640               if ( GetWWW(ajp) ) {
2641                 FFAddOneString (ffstring, "<a href=\"", FALSE, FALSE, TILDE_IGNORE);
2642                 FF_Add_NCBI_Base_URL (ffstring, doc_link);
2643                 FFAddOneString (ffstring, "\">", FALSE, FALSE, TILDE_IGNORE);
2644               }
2645               FFAddOneString (ffstring, "Documentation", FALSE, FALSE, TILDE_IGNORE);
2646               if ( GetWWW(ajp) ) {
2647                 FFAddOneString (ffstring, "</a>", FALSE, FALSE, TILDE_IGNORE);
2648               }
2649 
2650               FFAddOneString (ffstring, " of NCBI's Annotation Process~    ", FALSE, FALSE, TILDE_EXPAND);
2651 
2652               cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
2653               FFRecycleString(ajp, ffstring);
2654               ffstring = FFGetString(ajp);
2655 
2656               if (awp->afp != NULL) {
2657                 DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
2658               }
2659             }
2660           }
2661         } else {
2662           if (StringLen (tsip->accession) == 15) {
2663             is_wgs = TRUE;
2664             if (StringCmp (tsip->accession + 9, "000000") == 0) {
2665               wgsaccn = tsip->accession;
2666               wgsname = tsip->name; /* master accession has 8 zeroes, name has project version plus 6 zeroes */
2667             }
2668           }
2669         }
2670       }
2671 
2672     } else if (sip->choice == SEQID_TPG || sip->choice == SEQID_TPE || sip->choice == SEQID_TPD) {
2673 
2674       is_tpa = TRUE;
2675 
2676       tsip = (TextSeqIdPtr) sip->data.ptrvalue;
2677       if (tsip != NULL && tsip->accession != NULL) {
2678         acclen = StringLen (tsip->accession);
2679         if (acclen == 12) {
2680           is_wgs = TRUE;
2681           if (StringCmp (tsip->accession + 6, "000000") == 0) {
2682             wgsaccn = tsip->accession;
2683             wgsname = tsip->name; /* master accession has 8 zeroes, name has project version plus 6 zeroes */
2684           }
2685         } else if (acclen == 13) {
2686           is_wgs = TRUE;
2687           if (StringCmp (tsip->accession + 6, "0000000") == 0) {
2688             wgsaccn = tsip->accession;
2689             wgsname = tsip->name; /* master accession has 9 zeroes, name has project version plus 7 zeroes */
2690           }
2691         } else if (ajp->newSourceOrg && StringLen (tsip->accession) == 6) {
2692           ch = tsip->accession [0];
2693           if (ch == 'J' || ch == 'K' || ch == 'L' || ch == 'M') {
2694             showGBBSource = TRUE;
2695           }
2696         }
2697       }
2698 
2699     } else if (sip->choice == SEQID_GENBANK || sip->choice == SEQID_EMBL || sip->choice == SEQID_DDBJ) {
2700 
2701       is_collab = TRUE;
2702 
2703       tsip = (TextSeqIdPtr) sip->data.ptrvalue;
2704       if (tsip != NULL && tsip->accession != NULL) {
2705         acclen = StringLen (tsip->accession);
2706         if (acclen == 12) {
2707           is_wgs = TRUE;
2708           if (StringCmp (tsip->accession + 6, "000000") == 0) {
2709             wgsaccn = tsip->accession;
2710             wgsname = tsip->name; /* master accession has 8 zeroes, name has project version plus 6 zeroes */
2711           }
2712         } else if (acclen == 13) {
2713           is_wgs = TRUE;
2714           if (StringCmp (tsip->accession + 6, "0000000") == 0) {
2715             wgsaccn = tsip->accession;
2716             wgsname = tsip->name; /* master accession has 9 zeroes, name has project version plus 7 zeroes */
2717           }
2718         } else if (ajp->newSourceOrg && StringLen (tsip->accession) == 6) {
2719           ch = tsip->accession [0];
2720           if (ch == 'J' || ch == 'K' || ch == 'L' || ch == 'M') {
2721             showGBBSource = TRUE;
2722           }
2723         }
2724       }
2725 
2726     } else if (sip->choice == SEQID_GENERAL) {
2727       dbt = (DbtagPtr) sip->data.ptrvalue;
2728 
2729       /* show GSDB sequence identifier */
2730 
2731       if (dbt != NULL && StringCmp (dbt->db, "GSDB") == 0 && dbt->tag != NULL) {
2732         cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
2733         if (cbp != NULL) {
2734 
2735           cbp->entityID = awp->entityID;
2736           cbp->first = first;
2737           first = FALSE;
2738 
2739           /* string will be created after we know if there are additional comments */
2740 
2741           gsdbid = dbt->tag->id;
2742           sprintf (buf, "GSDB:S:%ld.", (long) gsdbid);
2743 
2744           if (cbp->first) {
2745             FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
2746           } else {
2747             FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
2748           }
2749 
2750           /* CheckEndPunctuation, ConvertDoubleQuotes, and ExpandTildes already taken into account */
2751 
2752           FFAddOneString (ffstring, buf, FALSE, FALSE, TILDE_IGNORE);
2753 
2754           cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
2755           FFRecycleString(ajp, ffstring);
2756           ffstring = FFGetString(ajp);
2757 
2758           if (awp->afp != NULL) {
2759             DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
2760           }
2761         }
2762       } else if (dbt != NULL && StringCmp (dbt->db, "NCBIFILE") == 0 && dbt->tag != NULL) {
2763         ncbifileID = dbt->tag;
2764       }
2765 
2766     } else if (sip->choice == SEQID_GI) {
2767       gi = (Int4) sip->data.intvalue;
2768 
2769     } else if (sip->choice == SEQID_LOCAL) {
2770       localID = (ObjectIdPtr) sip->data.ptrvalue;
2771     }
2772   }
2773 
2774   if (localID != NULL) {
2775     if (is_tpa || is_collab) {
2776       if (awp->mode == SEQUIN_MODE || awp->mode == DUMP_MODE) {
2777         buf [0] = '\0';
2778         if (! StringHasNoText (localID->str)) {
2779           if (StringLen (localID->str) < 1000) {
2780             sprintf (buf, "LocalID: %s", localID->str);
2781           } else {
2782             sprintf (buf, "LocalID string too large");
2783           }
2784         } else {
2785           sprintf (buf, "LocalID: %ld", (long) localID->id);
2786         }
2787 
2788         cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
2789         if (cbp != NULL) {
2790 
2791           cbp->entityID = awp->entityID;
2792           cbp->first = first;
2793           first = FALSE;
2794 
2795           if (cbp->first) {
2796             FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
2797           } else {
2798             FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
2799           }
2800 
2801           FFAddOneString (ffstring, buf, FALSE, FALSE, TILDE_EXPAND);
2802 
2803           cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12,5, 5, "CC");
2804           FFRecycleString(ajp, ffstring);
2805           ffstring = FFGetString(ajp);
2806 
2807           if (awp->afp != NULL) {
2808             DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
2809           }
2810         }
2811       }
2812     }
2813   }
2814 
2815   if (ncbifileID != NULL) {
2816     if (is_tpa || is_collab) {
2817       if (awp->mode == SEQUIN_MODE || awp->mode == DUMP_MODE) {
2818         buf [0] = '\0';
2819         if (! StringHasNoText (ncbifileID->str)) {
2820           if (StringLen (ncbifileID->str) < 1000) {
2821             sprintf (buf, "FileID: %s", ncbifileID->str);
2822           } else {
2823             sprintf (buf, "FileID string too large");
2824           }
2825         } else {
2826           sprintf (buf, "FileID: %ld", (long) ncbifileID->id);
2827         }
2828 
2829         cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
2830         if (cbp != NULL) {
2831 
2832           cbp->entityID = awp->entityID;
2833           cbp->first = first;
2834           first = FALSE;
2835 
2836           if (cbp->first) {
2837             FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
2838           } else {
2839             FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
2840           }
2841 
2842           FFAddOneString (ffstring, buf, FALSE, FALSE, TILDE_EXPAND);
2843 
2844           cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12,5, 5, "CC");
2845           FFRecycleString(ajp, ffstring);
2846           ffstring = FFGetString(ajp);
2847 
2848           if (awp->afp != NULL) {
2849             DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
2850           }
2851         }
2852       }
2853     }
2854   }
2855 
2856   /* RefSeq results in allocated comment string */
2857 
2858   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_user, &dcontext);
2859   while (sdp != NULL) {
2860 
2861     uop = (UserObjectPtr) sdp->data.ptrvalue;
2862     if (uop != NULL) {
2863 
2864       if (! didTPA) {
2865         str = GetStrForTPA (uop, bsp);
2866         if (str != NULL) {
2867 
2868           cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
2869           if (cbp != NULL) {
2870 
2871             cbp->entityID = dcontext.entityID;
2872             cbp->itemID = dcontext.itemID;
2873             cbp->itemtype = OBJ_SEQDESC;
2874             cbp->first = first;
2875             first = FALSE;
2876 
2877             if (cbp->first) {
2878               FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
2879             } else {
2880               FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
2881             }
2882 
2883             FFAddOneString (ffstring, str, FALSE, FALSE, TILDE_EXPAND);
2884 
2885             cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12,5, 5, "CC");
2886             FFRecycleString(ajp, ffstring);
2887             ffstring = FFGetString(ajp);
2888 
2889             if (awp->afp != NULL) {
2890               DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
2891             }
2892           }
2893           MemFree (str);
2894           didTPA = TRUE;
2895         }
2896       }
2897 
2898       if (! ajp->flags.hideBankItComment) {
2899         str = GetStrForBankit (uop);
2900         if (str != NULL) {
2901 
2902           cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
2903           if (cbp != NULL) {
2904 
2905             cbp->entityID = dcontext.entityID;
2906             cbp->itemID = dcontext.itemID;
2907             cbp->itemtype = OBJ_SEQDESC;
2908             cbp->first = first;
2909             first = FALSE;
2910 
2911             if (cbp->first) {
2912               FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
2913             } else {
2914               FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
2915             }
2916 
2917             FFAddOneString (ffstring, str, TRUE, FALSE, TILDE_EXPAND);
2918 
2919             cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12,5, 5, "CC");
2920             FFRecycleString(ajp, ffstring);
2921             ffstring = FFGetString(ajp);
2922 
2923             if (awp->afp != NULL) {
2924               DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
2925             }
2926           }
2927           MemFree (str);
2928         }
2929       }
2930 
2931       if (! didRefTrack) {
2932         str = GetStatusForRefTrack (uop);
2933         if (str != NULL) {
2934 
2935           cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
2936           if (cbp != NULL) {
2937 
2938             cbp->entityID = dcontext.entityID;
2939             cbp->itemID = dcontext.itemID;
2940             cbp->itemtype = OBJ_SEQDESC;
2941             cbp->first = first;
2942             first = FALSE;
2943 
2944             if (cbp->first) {
2945               FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
2946             } else {
2947               FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
2948             }
2949 
2950             if (StringICmp (str, "Pipeline ") != 0) {
2951               FFAddOneString (ffstring, str, FALSE, FALSE, TILDE_EXPAND);
2952             }
2953 
2954             AddStrForRefTrack (ajp, ffstring, uop, ISA_na (bsp->mol), genomeBuildNumber, genomeVersionNumber);
2955 
2956             cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12,5, 5, "CC");
2957             FFRecycleString(ajp, ffstring);
2958             ffstring = FFGetString(ajp);
2959 
2960             if (awp->afp != NULL) {
2961               DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
2962             }
2963           }
2964           /* do not free static str from GetStatusForRefTrack */
2965           didRefTrack = TRUE;
2966         }
2967       }
2968 
2969       if (! didGenome) {
2970         str = GetStrForGenome (uop, bsp);
2971         if (str != NULL) {
2972 
2973           cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
2974           if (cbp != NULL) {
2975 
2976             cbp->entityID = dcontext.entityID;
2977             cbp->itemID = dcontext.itemID;
2978             cbp->itemtype = OBJ_SEQDESC;
2979             cbp->first = first;
2980             first = FALSE;
2981 
2982             if (cbp->first) {
2983               FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
2984             } else {
2985               FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
2986             }
2987 
2988             FFAddOneString (ffstring, str, FALSE, FALSE, TILDE_EXPAND);
2989 
2990             cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
2991             FFRecycleString(ajp, ffstring);
2992             ffstring = FFGetString(ajp);
2993 
2994             if (awp->afp != NULL) {
2995               DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
2996             }
2997           }
2998           MemFree (str);
2999           didGenome = TRUE;
3000         }
3001       }
3002     }
3003     sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_user, &dcontext);
3004   }
3005 
3006   if (bsp->repr == Seq_repr_delta && bsp->seq_ext_type == 4 && is_wgs) {
3007     has_gaps = FALSE;
3008     for (dsp = (DeltaSeqPtr) bsp->seq_ext; dsp; dsp=dsp->next) {
3009       if (dsp->choice == 2) {
3010         litp = (SeqLitPtr) dsp->data.ptrvalue;
3011         if (litp != NULL) {
3012           if ((litp->seq_data == NULL || litp->seq_data_type == Seq_code_gap) &&
3013               litp->length > 0) {
3014             has_gaps = TRUE;
3015           }
3016         }
3017       }
3018     }
3019     if (has_gaps) {
3020       cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3021       if (cbp != NULL) {
3022 
3023         cbp->entityID = awp->entityID;
3024         cbp->first = first;
3025         first = FALSE;
3026 
3027         if (cbp->first) {
3028           FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
3029         } else {
3030           FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
3031         }
3032 
3033         if (is_wgs) {
3034           FFAddOneString (ffstring, nsWGSGapsString, TRUE, FALSE, TILDE_EXPAND);
3035         } else {
3036           FFAddOneString (ffstring, nsAreGapsString, TRUE, FALSE, TILDE_EXPAND);
3037         }
3038 
3039         cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
3040         FFRecycleString(ajp, ffstring);
3041         ffstring = FFGetString(ajp);
3042 
3043         if (awp->afp != NULL) {
3044           DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3045         }
3046       }
3047     }
3048   }
3049 
3050   /* Seq-hist results in allocated comment string */
3051 
3052   hist = bsp->hist;
3053   if (hist != NULL) {
3054 
3055     if (hist->replaced_by_ids != NULL && hist->replaced_by_date != NULL) {
3056 
3057       okay = TRUE;
3058       for (sip = hist->replaced_by_ids; sip != NULL; sip = sip->next) {
3059         if (sip->choice == SEQID_GI) {
3060           if (gi == (Int4) sip->data.intvalue) {
3061             okay = FALSE;
3062           }
3063         }
3064       }
3065 
3066       if (okay) {
3067         cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3068         if (cbp != NULL) {
3069 
3070           cbp->entityID = awp->entityID;
3071           cbp->first = first;
3072           first = FALSE;
3073 
3074           if (cbp->first) {
3075             FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
3076           } else {
3077             FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
3078           }
3079 
3080           AddHistCommentString (ajp, ffstring, "[WARNING] On", "this sequence was replaced by",
3081                                 hist->replaced_by_date, hist->replaced_by_ids, ISA_na (bsp->mol));
3082 
3083           cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
3084           FFRecycleString(ajp, ffstring);
3085           ffstring = FFGetString(ajp);
3086 
3087             if (awp->afp != NULL) {
3088               DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3089             }
3090         }
3091       }
3092     }
3093 
3094     if (hist->replace_ids != NULL && hist->replace_date != NULL && awp->mode != SEQUIN_MODE) {
3095 
3096       okay = TRUE;
3097       for (sip = hist->replace_ids; sip != NULL; sip = sip->next) {
3098         if (sip->choice == SEQID_GI) {
3099           if (gi == (Int4) sip->data.intvalue) {
3100             okay = FALSE;
3101           }
3102         }
3103       }
3104 
3105       if (okay) {
3106         cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3107         if (cbp != NULL) {
3108 
3109           cbp->entityID = awp->entityID;
3110           cbp->first = first;
3111           first = FALSE;
3112 
3113           if (cbp->first) {
3114             FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
3115           } else {
3116             FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
3117           }
3118 
3119           AddHistCommentString (ajp, ffstring, "On", "this sequence version replaced",
3120                                 hist->replace_date, hist->replace_ids, ISA_na (bsp->mol));
3121 
3122           cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
3123           FFRecycleString(ajp, ffstring);
3124           ffstring = FFGetString(ajp);
3125 
3126           if (awp->afp != NULL) {
3127             DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3128           }
3129         }
3130       }
3131     }
3132 
3133   }
3134 
3135   /* just save IDs for comment, maploc, and region descriptors */
3136 
3137   /*
3138   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_comment, &dcontext);
3139   while (sdp != NULL) {
3140     if (sdp->data.ptrvalue != NULL) {
3141       cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3142       if (cbp != NULL) {
3143         cbp->entityID = dcontext.entityID;
3144         cbp->itemID = dcontext.itemID;
3145         cbp->itemtype = OBJ_SEQDESC;
3146         cbp->first = first;
3147         first = FALSE;
3148 
3149         if (awp->afp != NULL) {
3150           DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3151         }
3152       }
3153     }
3154     sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_comment, &dcontext);
3155   }
3156   */
3157 
3158   /* WGS master comment goes before comment descriptors */
3159 
3160   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_molinfo, &dcontext);
3161   if (sdp != NULL) {
3162 
3163     mip = (MolInfoPtr) sdp->data.ptrvalue;
3164     if (mip != NULL) {
3165       if (mip->tech == MI_TECH_wgs) {
3166 
3167         if (wgsname != NULL) {
3168 
3169           cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3170           if (cbp != NULL) {
3171 
3172             /*
3173             cbp->entityID = dcontext.entityID;
3174             cbp->itemID = dcontext.itemID;
3175             cbp->itemtype = OBJ_SEQDESC;
3176             */
3177             cbp->entityID = awp->entityID;
3178             cbp->first = first;
3179             first = FALSE;
3180 
3181             if (cbp->first) {
3182               FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
3183             } else {
3184               FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
3185             }
3186 
3187             AddWGSMasterCommentString (ffstring, bsp, wgsaccn, wgsname);
3188 
3189             cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
3190             FFRecycleString(ajp, ffstring);
3191             ffstring = FFGetString(ajp);
3192 
3193             cbp->itemID = dcontext.itemID;
3194             cbp->itemtype = OBJ_SEQDESC;
3195             if (awp->afp != NULL) {              
3196               DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3197             }
3198             cbp->itemID = 0;
3199             cbp->itemtype = 0;
3200           }
3201         }
3202       }
3203     }
3204   }
3205 
3206   if (showGBBSource) {
3207     sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_genbank, &dcontext);
3208     if (sdp != NULL) {
3209       gbp = (GBBlockPtr) sdp->data.ptrvalue;
3210       if (gbp != NULL && (! StringHasNoText (gbp->source))) {
3211         cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3212         if (cbp != NULL) {
3213 
3214           cbp->entityID = dcontext.entityID;
3215           cbp->itemID = dcontext.itemID;
3216           cbp->itemtype = OBJ_SEQDESC;
3217           cbp->first = first;
3218           first = FALSE;
3219 
3220           if (cbp->first) {
3221             FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
3222           } else {
3223             FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
3224           }
3225 
3226           FFAddOneString (ffstring, "Original source text: ", FALSE, FALSE, TILDE_EXPAND);
3227           FFAddOneString (ffstring, gbp->source, TRUE, TRUE, TILDE_EXPAND);
3228 
3229           cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
3230           FFRecycleString(ajp, ffstring);
3231           ffstring = FFGetString(ajp);
3232 
3233           if (awp->afp != NULL) {
3234             DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3235           }
3236         }
3237       }
3238     }
3239   }
3240 
3241   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_comment, &dcontext);
3242   while (sdp != NULL) {
3243     if (StringDoesHaveText ((CharPtr)sdp->data.ptrvalue)) {
3244       cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3245       if (cbp != NULL) {
3246 
3247         cbp->entityID = dcontext.entityID;
3248         cbp->itemID = dcontext.itemID;
3249         cbp->itemtype = OBJ_SEQDESC;
3250         cbp->first = first;
3251         first = FALSE;
3252 
3253         if (awp->afp != NULL) {
3254           DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3255         }
3256       }
3257     }
3258     sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_comment, &dcontext);
3259   }
3260 
3261   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_maploc, &dcontext);
3262   while (sdp != NULL) {
3263     cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3264     if (cbp != NULL) {
3265 
3266       cbp->entityID = dcontext.entityID;
3267       cbp->itemID = dcontext.itemID;
3268       cbp->itemtype = OBJ_SEQDESC;
3269       cbp->first = first;
3270       first = FALSE;
3271 
3272       if (awp->afp != NULL) {
3273         DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3274       }
3275     }
3276     sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_maploc, &dcontext);
3277   }
3278 
3279   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_region, &dcontext);
3280   while (sdp != NULL) {
3281     if (sdp->data.ptrvalue != NULL) {
3282       cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3283       if (cbp != NULL) {
3284 
3285         cbp->entityID = dcontext.entityID;
3286         cbp->itemID = dcontext.itemID;
3287         cbp->itemtype = OBJ_SEQDESC;
3288         cbp->first = first;
3289         first = FALSE;
3290 
3291         if (awp->afp != NULL) {
3292           DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3293         }
3294       }
3295     }
3296     sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_region, &dcontext);
3297   }
3298 
3299   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_name, &dcontext);
3300   while (sdp != NULL) {
3301     if (sdp->data.ptrvalue != NULL) {
3302       cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3303       if (cbp != NULL) {
3304 
3305         cbp->entityID = dcontext.entityID;
3306         cbp->itemID = dcontext.itemID;
3307         cbp->itemtype = OBJ_SEQDESC;
3308         cbp->first = first;
3309         first = FALSE;
3310 
3311         if (awp->afp != NULL) {
3312           DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3313         }
3314       }
3315     }
3316     sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_name, &dcontext);
3317   }
3318 
3319   /* StructuredComment user object */
3320 
3321   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_user, &dcontext);
3322   while (sdp != NULL) {
3323 
3324     uop = (UserObjectPtr) sdp->data.ptrvalue;
3325     if (uop != NULL) {
3326 
3327       str = GetStrForStructuredComment (awp, ajp, uop, bsp);
3328       if (str != NULL) {
3329 
3330         cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3331         if (cbp != NULL) {
3332 
3333           cbp->entityID = dcontext.entityID;
3334           cbp->itemID = dcontext.itemID;
3335           cbp->itemtype = OBJ_SEQDESC;
3336           cbp->first = first;
3337           first = FALSE;
3338 
3339           if (cbp->first) {
3340             FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
3341           } else {
3342             FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
3343             FFAddOneString (ffstring, "\n", FALSE, FALSE, TILDE_EXPAND);
3344           }
3345 
3346           FFAddOneString (ffstring, str, FALSE, FALSE, TILDE_EXPAND);
3347 
3348           cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
3349           FFRecycleString(ajp, ffstring);
3350           ffstring = FFGetString(ajp);
3351 
3352           if (awp->afp != NULL) {
3353             DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3354           }
3355         }
3356         MemFree (str);
3357       }
3358     }
3359     sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_user, &dcontext);
3360   }
3361 
3362   /* HTGS results in allocated comment string */
3363 
3364   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_molinfo, &dcontext);
3365   if (sdp != NULL) {
3366 
3367     mip = (MolInfoPtr) sdp->data.ptrvalue;
3368     if (mip != NULL) {
3369       if (mip->completeness != 0 && is_other) {
3370 
3371         str = GetMolInfoCommentString (bsp, mip);
3372 
3373         if (str != NULL) {
3374           cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3375           if (cbp != NULL) {
3376 
3377             cbp->entityID = dcontext.entityID;
3378             cbp->itemID = dcontext.itemID;
3379             cbp->itemtype = OBJ_SEQDESC;
3380             cbp->first = first;
3381             first = FALSE;
3382 
3383             if (cbp->first) {
3384               FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
3385             } else {
3386               FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
3387             }
3388 
3389             FFAddOneString (ffstring, str, TRUE, FALSE, TILDE_EXPAND);
3390 
3391             cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
3392             FFRecycleString(ajp, ffstring);
3393             ffstring = FFGetString(ajp);
3394 
3395             if (awp->afp != NULL) {
3396               DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3397             }
3398           }
3399         }
3400 
3401       }
3402       if (mip->tech == MI_TECH_htgs_0 ||
3403           mip->tech == MI_TECH_htgs_1 ||
3404           mip->tech == MI_TECH_htgs_2) {
3405 
3406         cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3407         if (cbp != NULL) {
3408 
3409           /*
3410           cbp->entityID = dcontext.entityID;
3411           cbp->itemID = dcontext.itemID;
3412           cbp->itemtype = OBJ_SEQDESC;
3413           */
3414           cbp->entityID = awp->entityID;
3415           cbp->first = first;
3416           first = FALSE;
3417 
3418           if (cbp->first) {
3419             FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
3420           } else {
3421             FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
3422           }
3423           
3424           AddHTGSCommentString (ffstring, bsp, mip);
3425 
3426           cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
3427           FFRecycleString(ajp, ffstring);
3428           ffstring = FFGetString(ajp);
3429 
3430           if (awp->afp != NULL) {
3431             DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3432           }
3433         }
3434 
3435       } else {
3436         str = StringForSeqTech (mip->tech);
3437         if (! StringHasNoText (str)) {
3438 
3439           cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3440           if (cbp != NULL) {
3441 
3442             /*
3443             cbp->entityID = dcontext.entityID;
3444             cbp->itemID = dcontext.itemID;
3445             cbp->itemtype = OBJ_SEQDESC;
3446             */
3447             cbp->entityID = awp->entityID;
3448             cbp->first = first;
3449             first = FALSE;
3450 
3451             if (cbp->first) {
3452               FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
3453             } else {
3454               FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
3455             }
3456 
3457             FFAddTextToString (ffstring, "Method: ", str, NULL, TRUE, FALSE, TILDE_EXPAND);
3458 
3459             cbp->string = FFEndPrint(ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
3460             FFRecycleString(ajp, ffstring);
3461             ffstring = FFGetString(ajp);
3462 
3463             if (awp->afp != NULL) {
3464               DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3465             }
3466           }
3467         }
3468       }
3469     }
3470   }
3471 
3472   parent = awp->parent;
3473   if (parent == NULL) return;
3474 
3475   /* no longer adding comment features that are full length on appropriate segment */
3476 
3477   /*
3478   sfp = SeqMgrGetNextFeature (parent, NULL, SEQFEAT_COMMENT, 0, &fcontext);
3479   while (sfp != NULL) {
3480     if (fcontext.left == awp->from && fcontext.right == awp->to) {
3481       cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3482       if (cbp != NULL) {
3483 
3484         cbp->entityID = fcontext.entityID;
3485         cbp->itemID = fcontext.itemID;
3486         cbp->itemtype = OBJ_SEQFEAT;
3487         cbp->first = first;
3488         first = FALSE;
3489 
3490         if (awp->afp != NULL) {
3491           DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3492         }
3493       }
3494     }
3495     sfp = SeqMgrGetNextFeature (parent, sfp, SEQFEAT_COMMENT, 0, &fcontext);
3496   }
3497   */
3498 
3499   /* look for Seq-annot.desc.comment on annots packaged on current bioseq */
3500 
3501   annotDescCommentToComment = FALSE;
3502   adp = SeqMgrGetNextAnnotDesc (bsp, NULL, Annot_descr_user, &acontext);
3503   while (adp != NULL) {
3504     uop = (UserObjectPtr) adp->data.ptrvalue;
3505     if (uop != NULL) {
3506       oip = uop->type;
3507       if (oip != NULL) {
3508         if (StringCmp (oip->str, "AnnotDescCommentPolicy") == 0) {
3509           for (ufp = uop->data; ufp != NULL; ufp = ufp->next) {
3510             oip = ufp->label;
3511             if (oip == NULL || ufp->data.ptrvalue == NULL) continue;
3512             if (StringCmp (oip->str, "Policy") == 0) {
3513               if (StringICmp ((CharPtr) ufp->data.ptrvalue, "ShowInComment") == 0) {
3514                 annotDescCommentToComment = TRUE;
3515               }
3516             }
3517           }
3518         }
3519       }
3520     }
3521     adp = SeqMgrGetNextAnnotDesc (bsp, adp, Annot_descr_user, &acontext);
3522   }
3523 
3524   if (annotDescCommentToComment) {
3525     adp = SeqMgrGetNextAnnotDesc (bsp, NULL, Annot_descr_comment, &acontext);
3526     while (adp != NULL) {
3527       str = (CharPtr) adp->data.ptrvalue;
3528       if (StringDoesHaveText (str)) {
3529         cbp = (CommentBlockPtr) Asn2gbAddBlock (awp, COMMENT_BLOCK, sizeof (CommentBlock));
3530         if (cbp != NULL) {
3531 
3532           cbp->entityID = awp->entityID;
3533           cbp->first = first;
3534           first = FALSE;
3535 
3536           if (cbp->first) {
3537             FFStartPrint (ffstring, awp->format, 0, 12, "COMMENT", 12, 5, 5, "CC", TRUE);
3538           } else {
3539             FFStartPrint (ffstring, awp->format, 0, 12, NULL, 12, 5, 5, "CC", FALSE);
3540           }
3541 
3542           FFAddOneString (ffstring, str, TRUE, FALSE, TILDE_EXPAND);
3543 
3544           cbp->string = FFEndPrint (ajp, ffstring, awp->format, 12, 12, 5, 5, "CC");
3545           FFRecycleString (ajp, ffstring);
3546           ffstring = FFGetString (ajp);
3547 
3548           if (awp->afp != NULL) {
3549             DoImmediateFormat (awp->afp, (BaseBlockPtr) cbp);
3550           }
3551         }
3552       }
3553       adp = SeqMgrGetNextAnnotDesc (bsp, adp, Annot_descr_comment, &acontext);
3554     }
3555   }
3556 
3557   FFRecycleString(ajp, ffstring);
3558 }
3559 
3560 NLM_EXTERN void AddFeatHeaderBlock (
3561   Asn2gbWorkPtr awp
3562 )
3563 
3564 {
3565   IntAsn2gbJobPtr ajp;
3566   BaseBlockPtr    bbp;
3567   Char            buf [128];
3568   StringItemPtr   ffstring;
3569   CharPtr         suffix = NULL;
3570 
3571   if (awp == NULL) return;
3572   ajp = awp->ajp;
3573   if (ajp == NULL) return;
3574 
3575   bbp = Asn2gbAddBlock (awp, FEATHEADER_BLOCK, sizeof (BaseBlock));
3576   if (bbp == NULL) return;
3577 
3578   bbp->entityID = awp->entityID;
3579 
3580   if (GetWWW (ajp) && awp->mode == ENTREZ_MODE && awp->afp != NULL &&
3581       (awp->format == GENBANK_FMT || awp->format == GENPEPT_FMT)) {
3582     sprintf (buf, "<a name=\"feature_%ld\"></a>", (long) awp->currGi);
3583     DoQuickLinkFormat (awp->afp, buf);
3584   }
3585 
3586   if (awp->format != FTABLE_FMT) {
3587     ffstring = FFGetString(ajp);
3588     if ( ffstring == NULL ) return;
3589 
3590     FFStartPrint (ffstring, awp->format, 0, 12, "FEATURES", 21, 5, 0, "FH", TRUE);
3591 
3592     if (awp->format == EMBL_FMT || awp->format == EMBLPEPT_FMT) {
3593       FFAddOneString (ffstring, "Key", FALSE, FALSE, TILDE_IGNORE);
3594       FFAddNChar(ffstring, ' ', 13 , FALSE);
3595     }
3596 
3597     FFAddOneString (ffstring, "Location/Qualifiers", FALSE, FALSE, TILDE_TO_SPACES);
3598 
3599     if (awp->format == EMBL_FMT || awp->format == EMBLPEPT_FMT) {
3600       FFAddNewLine(ffstring);
3601       FFAddNewLine(ffstring);
3602     }
3603 
3604     suffix = FFEndPrint(ajp, ffstring, awp->format, 12, 21, 5, 0, "FH");
3605     FFRecycleString(ajp, ffstring);
3606   }
3607 
3608   bbp->string = suffix;
3609 
3610   if (awp->afp != NULL) {
3611     DoImmediateFormat (awp->afp, bbp);
3612   }
3613 }
3614 
3615 static Uint2 ComputeSourceHash (
3616   CharPtr key,
3617   Uint2 start
3618 )
3619 
3620 {
3621   Uint4  h;
3622   Uint2  M;
3623   Uint2  S;
3624 
3625   if (key == NULL) return start;
3626 
3627   M = 101; /* prime key */
3628   S = 256; /* size of alphabet */
3629 
3630   for (h = start; *key != '\0'; key++) {
3631     h = (S * h + *key) % M;
3632   }
3633 
3634   return (Uint2) h;
3635 }
3636 
3637 static BaseBlockPtr AddSource (
3638   Asn2gbWorkPtr awp,
3639   ValNodePtr PNTR head,
3640   BioSourcePtr biop,
3641   CharPtr comment
3642 )
3643 
3644 {
3645   BaseBlockPtr    bbp;
3646   DbtagPtr        dbt;
3647   Uint2           hash;
3648   SourceType      idx;
3649   IntSrcBlockPtr  isp;
3650   ObjectIdPtr     oip;
3651   OrgModPtr       omp;
3652   OrgNamePtr      onp;
3653   OrgRefPtr       orp;
3654   SubSourcePtr    ssp;
3655   CharPtr         str;
3656   Uint1           subtype;
3657   Char            tmp [16];
3658   ValNodePtr      vnp;
3659 
3660   if (awp == NULL || head == NULL || biop == NULL) return NULL;
3661 
3662   bbp = (BaseBlockPtr) MemNew (sizeof (IntSrcBlock));
3663   if (bbp == NULL) return NULL;
3664   bbp->blocktype = SOURCEFEAT_BLOCK;
3665   bbp->section = awp->currsection;
3666 
3667   ValNodeAddPointer (head, 0, bbp);
3668 
3669   isp = (IntSrcBlockPtr) bbp;
3670   isp->biop = biop;
3671   isp->is_focus = biop->is_focus;
3672   if (biop->origin == 5) {
3673     isp->is_synthetic = TRUE;
3674   }
3675 
3676   orp = biop->org;
3677   if (orp == NULL) return bbp;
3678 
3679   if (StringICmp (orp->taxname, "synthetic construct") == 0) {
3680     isp->is_synthetic = TRUE;
3681   }
3682 
3683   isp->orghash = ComputeSourceHash (orp->taxname, 0);
3684   isp->taxname = orp->taxname;
3685 
3686   hash = 0;
3687   onp = orp->orgname;
3688   if (onp != NULL) {
3689     if (StringICmp (onp->div, "SYN") == 0) {
3690       isp->is_synthetic = TRUE;
3691     }
3692     isp->omp = onp->mod;
3693     for (omp = onp->mod; omp != NULL; omp = omp->next) {
3694       subtype = omp->subtype;
3695       if (subtype == 253) {
3696         subtype = 35;
3697       } else if (subtype == 254) {
3698         subtype = 36;
3699       } else if (subtype == 255) {
3700         subtype = 37;
3701       }
3702       if (subtype < 38) {
3703         idx = orgModToSourceIdx [subtype];
3704         if (idx > 0 && idx < ASN2GNBK_TOTAL_SOURCE) {
3705           str = asn2gnbk_source_quals [idx].name;
3706           hash = ComputeSourceHash (str, hash);
3707           hash = ComputeSourceHash (omp->subname, hash);
3708         }
3709       }
3710     }
3711   }
3712   if (comment != NULL) {
3713     hash = ComputeSourceHash ("note", hash);
3714     hash = ComputeSourceHash (comment, hash);
3715   }
3716   isp->modhash = hash;
3717 
3718   hash = 0;
3719   for (ssp = biop->subtype; ssp != NULL; ssp = ssp->next) {
3720     subtype = ssp->subtype;
3721     if (subtype == 255) {
3722       subtype = 38;
3723     }
3724     if (subtype < 39) {
3725       idx = subSourceToSourceIdx [subtype];
3726       if (idx > 0 && idx < ASN2GNBK_TOTAL_SOURCE) {
3727         str = asn2gnbk_source_quals [idx].name;
3728         hash = ComputeSourceHash (str, hash);
3729         hash = ComputeSourceHash (ssp->name, hash);
3730       }
3731     }
3732   }
3733   isp->subhash = hash;
3734   isp->ssp = biop->subtype;
3735 
3736   hash = 0;
3737   for (vnp = orp->db; vnp != NULL; vnp = vnp->next) {
3738     dbt = (DbtagPtr) vnp->data.ptrvalue;
3739     if (dbt != NULL) {
3740       hash = ComputeSourceHash (dbt->db, hash);
3741       oip = dbt->tag;
3742       if (oip != NULL) {
3743         if (oip->str != NULL) {
3744           hash = ComputeSourceHash (oip->str, hash);
3745         } else {
3746           sprintf (tmp, "%ld", (long) oip->id);
3747           hash = ComputeSourceHash (tmp, hash);
3748         }
3749       }
3750     }
3751   }
3752   isp->xrfhash = hash;
3753   isp->vnp = orp->db;
3754 
3755   return bbp;
3756 }
3757 
3758 static int LIBCALLBACK SortSourcesByHash (
3759   VoidPtr ptr1,
3760   VoidPtr ptr2
3761 )
3762 
3763 {
3764   Int4            diff;
3765   IntSrcBlockPtr  isp1;
3766   IntSrcBlockPtr  isp2;
3767   ValNodePtr      vnp1;
3768   ValNodePtr      vnp2;
3769 
3770   if (ptr1 == NULL || ptr2 == NULL) return 0;
3771   vnp1 = *((ValNodePtr PNTR) ptr1);
3772   vnp2 = *((ValNodePtr PNTR) ptr2);
3773   if (vnp1 == NULL || vnp2 == NULL) return 0;
3774   isp1 = (IntSrcBlockPtr) vnp1->data.ptrvalue;
3775   isp2 = (IntSrcBlockPtr) vnp2->data.ptrvalue;
3776   if (isp1 == NULL || isp2 == NULL) return 0;
3777 
3778   if (isp1->is_focus && (! isp2->is_focus)) return -1;
3779   if (isp2->is_focus && (! isp1->is_focus)) return 1;
3780 
3781   diff = isp1->orghash - isp2->orghash;
3782   if (diff > 0) return -1;
3783   if (diff < 0) return 1;
3784 
3785   diff = isp1->xrfhash - isp2->xrfhash;
3786   if (diff > 0) return -1;
3787   if (diff < 0) return 1;
3788 
3789   /* sort so that sources with modifiers come first */
3790 
3791   diff = isp1->modhash - isp2->modhash;
3792   if (diff > 0) return -1;
3793   if (diff < 0) return 1;
3794 
3795   diff = isp1->subhash - isp2->subhash;
3796   if (diff > 0) return -1;
3797   if (diff < 0) return 1;
3798 
3799   /* if all hashes are equal, descriptor comes first */
3800 
3801   if (isp1->is_descriptor && (! isp2->is_descriptor)) {
3802     return -1;
3803   } else if (isp2->is_descriptor && (! isp1->is_descriptor)) {
3804     return 1;
3805   }
3806 
3807   /* now sort identical sources by position, to only fuse abutting ones */
3808   /* feature with smallest left extreme is first */
3809 
3810   if (isp1->left > isp2->left) {
3811     return 1;
3812   } else if (isp1->left < isp2->left) {
3813     return -1;
3814   }
3815 
3816   /* if same left extreme, shortest source feature is first just for flatfile */
3817 
3818   if (isp1->right > isp2->right) {
3819     return 1;
3820   } else if (isp1->right < isp2->right) {
3821     return -1;
3822   }
3823 
3824   return 0;
3825 }
3826 
3827 static int LIBCALLBACK SortSourcesByPos (
3828   VoidPtr ptr1,
3829   VoidPtr ptr2
3830 )
3831 
3832 {
3833   IntSrcBlockPtr  isp1;
3834   IntSrcBlockPtr  isp2;
3835   ValNodePtr      vnp1;
3836   ValNodePtr      vnp2;
3837 
3838   if (ptr1 == NULL || ptr2 == NULL) return 0;
3839   vnp1 = *((ValNodePtr PNTR) ptr1);
3840   vnp2 = *((ValNodePtr PNTR) ptr2);
3841   if (vnp1 == NULL || vnp2 == NULL) return 0;
3842   isp1 = (IntSrcBlockPtr) vnp1->data.ptrvalue;
3843   isp2 = (IntSrcBlockPtr) vnp2->data.ptrvalue;
3844   if (isp1 == NULL || isp2 == NULL) return 0;
3845 
3846   /* descriptor always goes first */
3847 
3848   if (isp1->is_descriptor && (! isp2->is_descriptor)) {
3849     return -1;
3850   } else if (isp2->is_descriptor && (! isp1->is_descriptor)) {
3851     return 1;
3852   }
3853 
3854   /* feature with smallest left extreme is first */
3855 
3856   if (isp1->left > isp2->left) {
3857     return 1;
3858   } else if (isp1->left < isp2->left) {
3859     return -1;
3860   }
3861 
3862   /* if same left extreme, shortest source feature is first just for flatfile */
3863 
3864   if (isp1->right > isp2->right) {
3865     return 1;
3866   } else if (isp1->right < isp2->right) {
3867     return -1;
3868   }
3869 
3870   return 0;
3871 }
3872 
3873 /*                                                                   */
3874 /* s_isFuzzyLoc () -- Determines is a location has fuzzy coordinates */
3875 /*                                                                   */
3876 
3877 static Boolean s_isFuzzyLoc ( SeqLocPtr pLocation )
3878 {
3879   SeqIntPtr pIntLocation;
3880 
3881   if (pLocation == NULL)
3882     return FALSE;
3883 
3884   if (pLocation->choice != SEQLOC_INT)
3885     return FALSE;
3886 
3887   if (pLocation->data.ptrvalue == NULL)
3888     return FALSE;
3889 
3890   pIntLocation = (SeqIntPtr) pLocation->data.ptrvalue;
3891 
3892   if ((pIntLocation->if_from != NULL) && (pIntLocation->if_from->choice == 2))
3893     return TRUE;
3894 
3895   if ((pIntLocation->if_to != NULL) && (pIntLocation->if_to->choice == 2))
3896     return TRUE;
3897 
3898   return FALSE;
3899 }
3900 
3901 static void GetSourcesOnBioseq (
3902   Asn2gbWorkPtr awp,
3903   BioseqPtr target,
3904   BioseqPtr bsp,
3905   Int4 from,
3906   Int4 to
3907 )
3908 
3909 {
3910   IntAsn2gbJobPtr    ajp;
3911   BaseBlockPtr       bbp;
3912   BioSourcePtr       biop;
3913   SeqMgrDescContext  dcontext;
3914   SeqMgrFeatContext  fcontext;
3915   Boolean            hasNulls;
3916   Int4               left;
3917   Boolean            loop = FALSE;
3918   Int2               idx;
3919   IntSrcBlockPtr     isp;
3920   Int4Ptr            ivals;
3921   SeqLocPtr          newloc;
3922   Boolean            noLeft;
3923   Boolean            noRight;
3924   Int2               numivals;
3925   Boolean            okay;
3926   Int4               right;
3927   SeqDescrPtr        sdp;
3928   SeqFeatPtr         sfp;
3929   SeqInt             sint;
3930   SeqIdPtr           sip;
3931   Boolean            split;
3932   Int4               start;
3933   Int4               stop;
3934   Uint1              strand;
3935   ValNode            vn;
3936   ValNodePtr         vnp;
3937 
3938   if (awp == NULL || target == NULL || bsp == NULL) return;
3939   ajp = awp->ajp;
3940   if (ajp == NULL) return;
3941 
3942   if (awp->format != FTABLE_FMT || awp->mode == DUMP_MODE) {
3943 
3944     /* full length loc for descriptors */
3945   
3946     sint.from = 0;
3947     if (ajp->ajp.slp != NULL) {
3948       sint.to = SeqLocLen (ajp->ajp.slp) - 1;
3949     } else {
3950       sint.to = bsp->length - 1;
3951     }
3952     sint.strand = Seq_strand_plus;
3953     sint.id = SeqIdStripLocus (SeqIdDup (SeqIdFindBest (bsp->id, 0)));
3954     sint.if_from = NULL;
3955     sint.if_to = NULL;
3956   
3957     vn.choice = SEQLOC_INT;
3958     vn.data.ptrvalue = (Pointer) &sint;
3959     vn.next = NULL;
3960   
3961     /* if SWISS-PROT, may have multiple source descriptors */
3962   
3963     if (ISA_aa (bsp->mol)) {
3964       for (sip = bsp->id; sip != NULL; sip = sip->next) {
3965         if (sip->choice == SEQID_SWISSPROT) {
3966           loop = TRUE;
3967         }
3968       }
3969     }
3970   
3971     sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_source, &dcontext);
3972     while (sdp != NULL) {
3973   
3974       /* check if descriptor on part already added on segmented bioseq */
3975   
3976       okay = TRUE;
3977       for (vnp = awp->srchead; vnp != NULL && okay; vnp = vnp->next) {
3978         bbp = (BaseBlockPtr) vnp->data.ptrvalue;
3979         if (bbp != NULL) {
3980           if (bbp->entityID == dcontext.entityID &&
3981               bbp->itemID == dcontext.itemID &&
3982               bbp->itemtype == OBJ_SEQDESC) {
3983             okay = FALSE;
3984           }
3985         }
3986       }
3987   
3988       if (okay) {
3989         biop = (BioSourcePtr) sdp->data.ptrvalue;
3990         bbp = AddSource (awp, &(awp->srchead), biop, NULL);
3991         if (bbp != NULL) {
3992   
3993           bbp->entityID = dcontext.entityID;
3994           bbp->itemID = dcontext.itemID;
3995           bbp->itemtype = OBJ_SEQDESC;
3996   
3997           isp = (IntSrcBlockPtr) bbp;
3998           isp->loc = SeqLocMerge (target, &vn, NULL, FALSE, TRUE, FALSE);
3999           isp->left = 0;
4000           isp->right = bsp->length - 1;
4001           isp->is_descriptor = TRUE;
4002         }
4003       }
4004   
4005       /* if SWISS-PROT, loop through multiple source descriptors */
4006   
4007       if (loop) {
4008         sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_source, &dcontext);
4009       } else {
4010         sdp = NULL;
4011       }
4012     }
4013   
4014     SeqIdFree (sint.id);
4015   }
4016 
4017   if ((! awp->contig) || awp->showconsource) {
4018 
4019     /* features are indexed on parent if segmented */
4020 
4021     bsp = awp->parent;
4022 
4023     sfp = SeqMgrGetNextFeature (bsp, NULL, SEQFEAT_BIOSRC, 0, &fcontext);
4024     while (sfp != NULL) {
4025       ivals = fcontext.ivals;
4026       numivals = fcontext.numivals;
4027       if (ivals != NULL && numivals > 0) {
4028 
4029         idx = (numivals - 1) * 2;
4030         start = ivals [idx];
4031         stop = ivals [idx + 1];
4032         if (stop >= from && stop <= to && (ajp->ajp.slp == NULL || SeqLocCompare (sfp->location, ajp->ajp.slp) > 0)) {
4033 
4034           biop = (BioSourcePtr) sfp->data.value.ptrvalue;
4035           bbp = AddSource (awp, &(awp->srchead), biop, sfp->comment);
4036           if (bbp != NULL) {
4037 
4038             bbp->entityID = fcontext.entityID;
4039             bbp->itemID = fcontext.itemID;
4040             bbp->itemtype = OBJ_SEQFEAT;
4041 
4042             isp = (IntSrcBlockPtr) bbp;
4043             if (sfp->location != NULL && sfp->location->choice == SEQLOC_PNT) {
4044               isp->loc = AsnIoMemCopy ((Pointer) sfp->location,
4045                                        (AsnReadFunc) SeqLocAsnRead,
4046                                        (AsnWriteFunc) SeqLocAsnWrite);
4047             } else if (s_isFuzzyLoc (sfp->location)) {
4048               isp->loc = AsnIoMemCopy ((Pointer) sfp->location,
4049                                       (AsnReadFunc) SeqLocAsnRead,
4050                                       (AsnWriteFunc) SeqLocAsnWrite);
4051             } else if (SeqLocId(sfp->location) == NULL) {
4052               isp->loc = AsnIoMemCopy ((Pointer) sfp->location,
4053                                        (AsnReadFunc) SeqLocAsnRead,
4054                                        (AsnWriteFunc) SeqLocAsnWrite);
4055             } else {
4056               CheckSeqLocForPartial (sfp->location, &noLeft, &noRight);
4057               hasNulls = LocationHasNullsBetween (sfp->location);
4058               isp->loc = SeqLocMerge (target, sfp->location, NULL, FALSE, TRUE, hasNulls);
4059               SetSeqLocPartial (isp->loc, noLeft, noRight);
4060             }
4061             isp->left = fcontext.left;
4062             isp->right = fcontext.right;
4063             isp->comment = sfp->comment;
4064             if (ajp->ajp.slp != NULL) {
4065               sip = SeqIdParse ("lcl|dummy");
4066               left = GetOffsetInBioseq (ajp->ajp.slp, bsp, SEQLOC_LEFT_END);
4067               right = GetOffsetInBioseq (ajp->ajp.slp, bsp, SEQLOC_RIGHT_END);
4068               strand = SeqLocStrand (ajp->ajp.slp);
4069               split = FALSE;
4070               newloc = SeqLocReMapEx (sip, ajp->ajp.slp, isp->loc, 0, FALSE, ajp->masterStyle);
4071               /*
4072               newloc = SeqLocCopyRegion (sip, isp->loc, bsp, left, right, strand, &split);
4073               */
4074               SeqIdFree (sip);
4075               if (newloc != NULL) {
4076                 A2GBSeqLocReplaceID (newloc, ajp->ajp.slp);
4077                 isp->loc = SeqLocFree (isp->loc);
4078                 isp->loc = newloc;
4079                 isp->left = left;
4080                 isp->right = right;
4081               }
4082             }
4083           }
4084         }
4085       }
4086 
4087       sfp = SeqMgrGetNextFeature (bsp, sfp, SEQFEAT_BIOSRC, 0, &fcontext);
4088     }
4089   }
4090 }
4091 
4092 static Boolean LIBCALLBACK GetSourcesOnSeg (
4093   SeqLocPtr slp,
4094   SeqMgrSegmentContextPtr context
4095 )
4096 
4097 {
4098   Asn2gbWorkPtr  awp;
4099   BioseqPtr      bsp;
4100   Int4           from;
4101   SeqLocPtr      loc;
4102   SeqEntryPtr    oldscope;
4103   SeqEntryPtr    sep;
4104   SeqIdPtr       sip;
4105   Int4           to;
4106 
4107   if (slp == NULL || context == NULL) return FALSE;
4108   awp = (Asn2gbWorkPtr) context->userdata;
4109 
4110   from = context->cumOffset;
4111   to = from + context->to - context->from;
4112 
4113   sip = SeqLocId (slp);
4114   if (sip == NULL) {
4115     loc = SeqLocFindNext (slp, NULL);
4116     if (loc != NULL) {
4117       sip = SeqLocId (loc);
4118     }
4119   }
4120   if (sip == NULL) return TRUE;
4121 
4122   /* biosource descriptors only on parts within entity */
4123 
4124   sep = GetTopSeqEntryForEntityID (awp->entityID);
4125   oldscope = SeqEntrySetScope (sep);
4126   bsp = BioseqFind (sip);
4127   SeqEntrySetScope (oldscope);
4128 
4129   if (bsp != NULL) {
4130     GetSourcesOnBioseq (awp, awp->target, bsp, from, to);
4131     return TRUE;
4132   }
4133 
4134   /* if we ever want to fetch remote sources, code goes here */
4135 
4136 #if 0
4137   Uint2          entityID;
4138 
4139   /* may remote fetch genome component if not already in memory */
4140 
4141   bsp = BioseqLockById (sip);
4142 
4143   if (bsp == NULL) return TRUE;
4144 
4145   entityID = ObjMgrGetEntityIDForPointer (bsp);
4146 
4147   if (entityID != awp->entityID) {
4148 
4149     /* if segment not packaged in record, may need to feature index it */
4150 
4151     if (SeqMgrFeaturesAreIndexed (entityID) == 0) {
4152       SeqMgrIndexFeatures (entityID, NULL);
4153     }
4154 
4155     /* collect features indexed on the remote bioseq */
4156 
4157     from = 0;
4158     to = bsp->length - 1;
4159   }
4160 
4161   GetSourcesOnBioseq (awp, awp->target, bsp, from, to);
4162 
4163   BioseqUnlock (bsp);
4164 #endif
4165 
4166   return TRUE;
4167 }
4168 
4169 /* isIdenticalSource() -- Checks to see if two sources are identical */
4170 /*                        by comparing the actual values in the      */
4171 /*                        fields.  This only gets called if the two  */
4172 /*                        sources hashed the same -- it's a double-  */
4173 /*                        check since two non-identical things will  */
4174 /*                        occassionally hash to the same value.      */
4175 /*                        Now checks for adjacent or overlapping.    */
4176 
4177 static Boolean isIdenticalSource (IntSrcBlockPtr isp1, IntSrcBlockPtr isp2)
4178 {
4179   OrgModPtr     omp1;
4180   OrgModPtr     omp2;
4181   SubSourcePtr  ssp1;
4182   SubSourcePtr  ssp2;
4183   ValNodePtr    vnp1;
4184   ValNodePtr    vnp2;
4185   ObjectIdPtr   oip1;
4186   ObjectIdPtr   oip2;
4187   DbtagPtr      dbt1;
4188   DbtagPtr      dbt2;
4189 
4190   if (isp1->is_focus != isp2->is_focus)
4191     return FALSE;
4192 
4193   /* Compare the taxonomy names */
4194 
4195   if (StringICmp(isp1->taxname,isp2->taxname) != 0)
4196     return FALSE;
4197 
4198   /* Compare the comment */
4199 
4200   if (StringICmp(isp1->comment,isp2->comment) != 0)
4201     return FALSE;
4202 
4203   /* Compare the org mods */
4204 
4205   omp1 = isp1->omp;
4206   omp2 = isp2->omp;
4207   while (omp1 != NULL && omp2 != NULL)
4208     {
4209       if (omp1->subtype != omp2->subtype)
4210         return FALSE;
4211       if (StringICmp (omp1->subname, omp2->subname) != 0)
4212         return FALSE;
4213       omp1 = omp1->next;
4214       omp2 = omp2->next;
4215     }
4216 
4217   if (omp1 != NULL || omp2 != NULL)
4218     return FALSE;
4219 
4220   /* Compare the subtypes */
4221 
4222   ssp1 = isp1->ssp;
4223   ssp2 = isp2->ssp;
4224 
4225   while (ssp1 != NULL && ssp2 != NULL)
4226     {
4227       if (ssp1->subtype != ssp2->subtype)
4228         return FALSE;
4229       if (StringICmp(ssp1->name, ssp2->name) != 0)
4230         return FALSE;
4231       ssp1 = ssp1->next;
4232       ssp2 = ssp2->next;
4233     }
4234 
4235   if (ssp1 != NULL || ssp2 != NULL)
4236     return FALSE;
4237 
4238   /* Compare the DB tags */
4239 
4240   vnp1 = isp1->vnp;
4241   vnp2 = isp2->vnp;
4242 
4243   while (vnp1 != NULL && vnp2 != NULL)
4244     {
4245       dbt1 = (DbtagPtr) vnp1->data.ptrvalue;
4246       dbt2 = (DbtagPtr) vnp2->data.ptrvalue;
4247 
4248       if ((dbt1 != NULL) && (dbt2 != NULL)) {
4249         if (StringCmp (dbt1->db, dbt2->db) != 0)
4250           return FALSE;
4251 
4252         oip1 = dbt1->tag;
4253         oip2 = dbt2->tag;
4254         if ((oip1 != NULL) && (oip2 != NULL)) {
4255           if (oip1->str != NULL) {
4256             if (StringICmp(oip1->str, oip2->str) != 0)
4257               return FALSE;
4258           } else  {
4259             if (oip1->id != oip2->id)
4260               return FALSE;
4261           }
4262         }
4263         else if (oip1 != NULL)
4264           return FALSE;
4265         else if (oip2 != NULL)
4266           return FALSE;
4267       }
4268       else if (dbt1 != NULL)
4269         return FALSE;
4270       else if (dbt2 != NULL)
4271         return FALSE;
4272 
4273       vnp1 = vnp1->next;
4274       vnp2 = vnp2->next;
4275     }
4276 
4277   if (vnp1 != NULL || vnp2 != NULL)
4278     return FALSE;
4279 
4280   /* now check for not adjacent or overlapping */
4281 
4282   if (isp2->right + 1 < isp1->left) return FALSE;
4283 
4284   /* If it passed all checks, then they */
4285   /* are the same, so return true.      */
4286 
4287   return TRUE;
4288 }
4289 
4290 static void CleanupPackedSeqInt (SeqLocPtr location)
4291 
4292 {
4293   SeqLocPtr  head = NULL;
4294   SeqIntPtr  loc;
4295   SeqIntPtr  sintp;
4296   SeqLocPtr  slp;
4297 
4298   if (location == NULL || location->choice != SEQLOC_PACKED_INT || location->data.ptrvalue == NULL) return;
4299 
4300   slp = SeqLocFindNext (location, NULL);
4301   while (slp != NULL) {
4302     if (slp->choice == SEQLOC_INT) {
4303       sintp = (SeqIntPtr) slp->data.ptrvalue;
4304       if (sintp != NULL) {
4305         loc = AsnIoMemCopy (sintp, (AsnReadFunc) SeqIntAsnRead,
4306                             (AsnWriteFunc) SeqIntAsnWrite);
4307         ValNodeAddPointer (&head, SEQLOC_INT, loc);
4308       }
4309     }
4310     slp = SeqLocFindNext (location, slp);
4311   }
4312   if (head == NULL) return;
4313 
4314   location->data.ptrvalue = SeqLocFree (location->data.ptrvalue);
4315   location->data.ptrvalue = head;
4316 
4317   slp = location->data.ptrvalue;
4318   if (slp == NULL || slp->next != NULL) return;
4319     /* here seqloc_packed_int points to a single location element, so no need for seqloc_packed_int parent */
4320     location->choice = slp->choice;
4321     location->data.ptrvalue = (Pointer) slp->data.ptrvalue;
4322     MemFree (slp);
4323 }
4324 
4325 NLM_EXTERN void AddSourceFeatBlock (
4326   Asn2gbWorkPtr awp
4327 )
4328 
4329 {
4330   IntAsn2gbJobPtr    ajp;
4331   Asn2gbSectPtr      asp;
4332   BaseBlockPtr       bbp;
4333   BioseqPtr          bsp;
4334   SeqFeatPtr         cds;
4335   SeqMgrFeatContext  context;
4336   BioseqPtr          dna;
4337   SeqLocPtr          duploc;
4338   Boolean            excise;
4339   GBFeaturePtr       gbfeat = NULL;
4340   GBSeqPtr           gbseq;
4341   ValNodePtr         head = NULL;
4342   IntSrcBlockPtr     isp;
4343   IntSrcBlockPtr     lastisp;
4344   IntSrcBlockPtr     descrIsp;
4345   ValNodePtr         next;
4346   ValNodePtr         PNTR prev;
4347   SeqInt             sint;
4348   SeqLocPtr          slp;
4349   CharPtr            str;
4350   BioseqPtr          target;
4351   ValNode            vn;
4352   ValNodePtr         vnp;
4353   Boolean            descHasFocus = FALSE;
4354   StringItemPtr      ffstring;
4355 
4356   if (awp == NULL) return;
4357   ajp = awp->ajp;
4358   if (ajp == NULL) return;
4359   asp = awp->asp;
4360   if (asp == NULL) return;
4361   bsp = awp->bsp;
4362   if (bsp == NULL) return;
4363 
4364   ffstring = FFGetString(ajp);
4365   if ( ffstring == NULL ) return;
4366 
4367 
4368   /* collect biosources on bioseq */
4369 
4370   awp->srchead = NULL;
4371   GetSourcesOnBioseq (awp, bsp, bsp, awp->from, awp->to);
4372   target = bsp;
4373 
4374   if (bsp->repr == Seq_repr_seg) {
4375 
4376     /* collect biosource descriptors on local parts */
4377 
4378     SeqMgrExploreSegments (bsp, (Pointer) awp, GetSourcesOnSeg);
4379     target = awp->target;
4380   }
4381 
4382   if (awp->srchead == NULL && ISA_aa (bsp->mol)) {
4383 
4384     /* if protein with no sources, get sources applicable to DNA location of CDS */
4385 
4386     cds = SeqMgrGetCDSgivenProduct (bsp, &context);
4387     if (cds != NULL) {
4388       dna = BioseqFindFromSeqLoc (cds->location);
4389       if (dna != NULL) {
4390         GetSourcesOnBioseq (awp, dna, dna, context.left, context.right);
4391         target = dna;
4392       }
4393     }
4394   }
4395 
4396   head = awp->srchead;
4397   awp->srchead = NULL;
4398 
4399   if (head == NULL && (awp->format != FTABLE_FMT || awp->mode == DUMP_MODE)) {
4400 
4401     if (ajp->gbseq) {
4402       gbseq = &asp->gbseq;
4403     } else {
4404       gbseq = NULL;
4405     }
4406 
4407     sint.from = 0;
4408     sint.to = bsp->length - 1;
4409     sint.strand = Seq_strand_plus;
4410     sint.id = SeqIdStripLocus (SeqIdDup (SeqIdFindBest (bsp->id, 0)));
4411     sint.if_from = NULL;
4412     sint.if_to = NULL;
4413 
4414     vn.choice = SEQLOC_INT;
4415     vn.data.ptrvalue = (Pointer) &sint;
4416     vn.next = NULL;
4417 
4418     FFStartPrint (ffstring, awp->format, 5, 21, NULL, 0, 5, 21, "FT", FALSE);
4419     FFAddOneString(ffstring, "source", FALSE, FALSE, TILDE_IGNORE);
4420     FFAddNChar(ffstring, ' ', 21 - 5 - StringLen("source"), FALSE);
4421 
4422     if (gbseq != NULL) {
4423       gbfeat = GBFeatureNew ();
4424       if (gbfeat != NULL) {
4425         gbfeat->key = StringSave ("source");
4426       }
4427     }
4428 
4429     str = FFFlatLoc (ajp, bsp, &vn, (Boolean) (awp->style == MASTER_STYLE));
4430     if ( GetWWW(ajp) ) {
4431       FF_www_featloc (ffstring, str);
4432     } else {
4433       FFAddOneString (ffstring, str, FALSE, FALSE, TILDE_IGNORE);
4434     }
4435 
4436     if (gbseq != NULL) {
4437       if (gbfeat != NULL) {
4438         if (! StringHasNoText (str)) {
4439           gbfeat->location = StringSave (str);
4440         } else {
4441           gbfeat->location = StringSave ("");
4442         }
4443       }
4444     }
4445 
4446     MemFree (str);
4447 
4448     if (ajp->flags.needOrganismQual) {
4449       FFAddNewLine(ffstring);
4450       FFAddTextToString (ffstring, "/organism=\"", "unknown", "\"", FALSE, TRUE, TILDE_TO_SPACES);
4451 #ifdef ASN2GNBK_PRINT_UNKNOWN_ORG
4452     } else {
4453       FFAddNewLine(ffstring);
4454       FFAddTextToString (ffstring, "/organism=\"", "unknown", "\"", FALSE, TRUE, TILDE_TO_SPACES);
4455 #endif
4456     }
4457 
4458     str = GetMolTypeQual (bsp);
4459     if (StringICmp (str, "ncRNA") == 0) {
4460       str = "other RNA";
4461     }
4462     if (str == NULL) {
4463       switch (bsp->mol) {
4464         case Seq_mol_dna :
4465           str = "unassigned DNA";
4466           break;
4467         case Seq_mol_rna :
4468           str = "unassigned RNA";
4469           break;
4470         case Seq_mol_aa :
4471           break;
4472         default :
4473           str = "unassigned DNA";
4474           break;
4475       }
4476     }
4477     if (str != NULL) {
4478       FFAddNewLine(ffstring);
4479       FFAddTextToString (ffstring, "/mol_type=\"", str, "\"", FALSE, TRUE, TILDE_TO_SPACES);
4480     }
4481 
4482     str = FFEndPrint(ajp, ffstring, awp->format, 5, 21, 5, 21, "FT");
4483 
4484     bbp = (BaseBlockPtr) Asn2gbAddBlock (awp, SOURCEFEAT_BLOCK, sizeof (IntSrcBlock));
4485     if (bbp != NULL) {
4486       bbp->section = awp->currsection;
4487       bbp->string = str;
4488     } else {
4489       MemFree(str);
4490     }
4491     FFRecycleString(ajp, ffstring);
4492 
4493     if (awp->afp != NULL) {
4494       DoImmediateFormat (awp->afp, (BaseBlockPtr) bbp);
4495     }
4496 
4497     /* optionally populate gbseq for XML-ized GenBank format */
4498 
4499     if (gbseq != NULL) {
4500       if (gbfeat != NULL) {
4501         AddFeatureToGbseq (gbseq, gbfeat, str, NULL);
4502       }
4503     }
4504   }
4505 
4506   if (head == NULL) return;
4507 
4508   /* sort by hash values */
4509 
4510   head = SortValNode (head, SortSourcesByHash);
4511 
4512   /* unique sources, excise duplicates from list */
4513 
4514   prev = &(head);
4515   vnp = head;
4516   lastisp = NULL;
4517   while (vnp != NULL) {
4518     excise = FALSE;
4519     next = vnp->next;
4520     isp = (IntSrcBlockPtr) vnp->data.ptrvalue;
4521     if (isp->is_descriptor && isp->is_focus)
4522       descHasFocus = TRUE;
4523     if (lastisp != NULL) {
4524       if (isp != NULL) {
4525         if (lastisp->is_focus == isp->is_focus &&
4526             lastisp->orghash == isp->orghash &&
4527             lastisp->xrfhash == isp->xrfhash) {
4528 
4529           /* check for identical modifiers */
4530 
4531           if (lastisp->modhash == isp->modhash &&
4532               lastisp->subhash == isp->subhash) {
4533 
4534             excise = isIdenticalSource (isp, lastisp);
4535 
4536           /* or modifiers only in lastisp (e.g., on part bioseq) */
4537 
4538           } else if (isp->modhash == 0 && isp->subhash == 0) {
4539             excise = isIdenticalSource (isp, lastisp);
4540           }
4541         }
4542       }
4543     }
4544     if (awp->mode == DUMP_MODE) {
4545       excise = FALSE;
4546     }
4547     /* does not fuse equivalent source features for local, general, refseq, and 2+6 genbank ids */
4548     if (excise && awp->sourcePubFuse) {
4549       *prev = vnp->next;
4550       vnp->next = NULL;
4551 
4552       /* combine locations of duplicate sources */
4553 
4554       if (lastisp != NULL) {
4555         slp = SeqLocMerge (target, lastisp->loc, isp->loc, FALSE, TRUE, FALSE);
4556         lastisp->loc = SeqLocFree (lastisp->loc);
4557         lastisp->loc = slp;
4558         lastisp->left = MIN (lastisp->left,isp->left);
4559         lastisp->right = MAX (lastisp->right, isp->right);
4560       }
4561 
4562       /* and remove duplicate source */
4563 
4564       SeqLocFree (isp->loc);
4565       MemFree (isp);
4566       ValNodeFree (vnp);
4567 
4568     } else {
4569 
4570       prev = &(vnp->next);
4571       lastisp = isp;
4572     }
4573     vnp = next;
4574   }
4575 
4576   /* Sort again, by location this time */
4577 
4578   head = SortValNode (head, SortSourcesByPos);
4579 
4580   /* If the descriptor has a focus, then subtract */
4581   /* out all the other source locations.          */
4582 
4583   descrIsp = (IntSrcBlockPtr) head->data.ptrvalue; /* Sorted 1st by now */
4584 
4585   if ((descHasFocus) && (! descrIsp->is_synthetic)) {
4586 
4587     vnp = head;
4588     duploc = AsnIoMemCopy ((Pointer) descrIsp->loc,
4589                            (AsnReadFunc) SeqLocAsnRead,
4590                            (AsnWriteFunc) SeqLocAsnWrite);
4591     vnp = vnp->next;
4592     while (vnp != NULL) {
4593       isp = (IntSrcBlockPtr) vnp->data.ptrvalue;
4594       if (SeqLocAinB (descrIsp->loc, isp->loc) >= 0) {
4595         vnp = NULL; /* break the chain */
4596         descrIsp->loc = SeqLocFree (descrIsp->loc);
4597         descrIsp->loc = duploc;
4598         duploc = NULL;
4599       } else {
4600         descrIsp->loc = SeqLocSubtract (descrIsp->loc, isp->loc);
4601         vnp = vnp->next;
4602       }
4603     }
4604     CleanupPackedSeqInt (descrIsp->loc);
4605     descrIsp->left  = SeqLocStart (descrIsp->loc);
4606     descrIsp->right = SeqLocStop (descrIsp->loc);
4607     SeqLocFree (duploc);
4608   }
4609 
4610   /* if features completely subtracted descriptor
4611      intervals, suppress in release, entrez modes */
4612 
4613   if (descrIsp->loc == NULL && ajp->flags.hideEmptySource && head->next != NULL) {
4614     vnp = head->next;
4615     head->next = NULL;
4616     ValNodeFreeData (head);
4617     head = vnp;
4618   }
4619 
4620   /* finally link into blocks for current section */
4621 
4622   ValNodeLink (&(awp->lastblock), head);
4623   vnp = awp->lastblock;
4624   if (vnp == NULL) return;
4625   while (vnp->next != NULL) {
4626     vnp = vnp->next;
4627   }
4628 
4629   awp->lastblock = vnp;
4630   if (awp->blockList == NULL) {
4631     awp->blockList = vnp;
4632   }
4633   FFRecycleString(ajp, ffstring);
4634 
4635   if (awp->afp != NULL) {
4636     for (vnp = head; vnp != NULL; vnp = vnp->next) {
4637       isp = (IntSrcBlockPtr) vnp->data.ptrvalue;
4638       if (isp == NULL) continue;
4639       DoImmediateFormat (awp->afp, (BaseBlockPtr) isp);
4640     }
4641   }
4642 
4643 }
4644 
4645 static Boolean IsCDD (
4646   SeqFeatPtr sfp
4647 )
4648 
4649 {
4650   DbtagPtr    dbt;
4651   ValNodePtr  vnp;
4652 
4653   for (vnp = sfp->dbxref; vnp != NULL; vnp = vnp->next) {
4654     dbt = (DbtagPtr) vnp->data.ptrvalue;
4655     if (dbt != NULL && StringCmp (dbt->db, "CDD") == 0) return TRUE;
4656   }
4657 
4658   return FALSE;
4659 }
4660 
4661 static void GetFeatsOnCdsProduct (
4662   SeqFeatPtr cds,
4663   BioseqPtr nbsp,
4664   BioseqPtr pbsp,
4665   IntAsn2gbJobPtr ajp,
4666   Asn2gbWorkPtr awp
4667 )
4668 
4669 {
4670   FeatBlockPtr       fbp;
4671   IntFeatBlockPtr    ifp;
4672   Boolean            isRefSeq;
4673   Int4               lastleft;
4674   Int4               lastright;
4675   SeqAnnotPtr        lastsap;
4676   SeqFeatPtr         lastsfp;
4677   SeqLocPtr          location;
4678   SeqLocPtr          newloc;
4679   SeqMgrFeatContext  pcontext;
4680   SeqFeatPtr         prt;
4681   SeqIdPtr           sip;
4682   SeqLocPtr          slp;
4683   Boolean            suppress;
4684 
4685   if (cds == NULL || ajp == NULL || awp == NULL) return;
4686   if (nbsp == NULL || pbsp == NULL || (! ISA_aa (pbsp->mol))) return;
4687 
4688   if (awp->hideCdsProdFeats) return;
4689 
4690   isRefSeq = FALSE;
4691   for (sip = nbsp->id; sip != NULL; sip = sip->next) {
4692     if (sip->choice == SEQID_OTHER) {
4693       isRefSeq = TRUE;
4694     }
4695   }
4696 
4697   /* explore mat_peptides, sites, etc. */
4698 
4699   lastsfp = NULL;
4700   lastsap = NULL;
4701   lastleft = 0;
4702   lastright = 0;
4703 
4704   prt = SeqMgrGetNextFeature (pbsp, NULL, 0, 0, &pcontext);
4705   while (prt != NULL) {
4706 
4707     if (pcontext.featdeftype == FEATDEF_REGION ||
4708         pcontext.featdeftype == FEATDEF_SITE ||
4709         pcontext.featdeftype == FEATDEF_BOND ||
4710         pcontext.featdeftype == FEATDEF_mat_peptide_aa ||
4711         pcontext.featdeftype == FEATDEF_sig_peptide_aa ||
4712         pcontext.featdeftype == FEATDEF_transit_peptide_aa ||
4713         (pcontext.featdeftype == FEATDEF_preprotein /* && isRefSeq */)) {
4714 
4715       if (awp->hideSitesBondsRegions && (pcontext.featdeftype == FEATDEF_REGION ||
4716                                          pcontext.featdeftype == FEATDEF_SITE ||
4717                                          pcontext.featdeftype == FEATDEF_BOND)) {
4718 
4719         /* hide site, bond, and region features */
4720 
4721       } else if (awp->hideCddFeats && pcontext.featdeftype == FEATDEF_REGION && IsCDD (prt)) {
4722 
4723         /* passing this test prevents mapping of COG CDD region features */
4724 
4725       } else if (pcontext.dnaStop >= awp->from && pcontext.dnaStop <= awp->to) {
4726 
4727         /* suppress duplicate features (on protein) */
4728 
4729         suppress = FALSE;
4730         if (lastsfp != NULL && lastsap != NULL) {
4731           if (lastsfp->idx.subtype == prt->idx.subtype &&
4732               lastleft == pcontext.left &&
4733               lastright == pcontext.right) {
4734               if (lastsap == pcontext.sap ||
4735                   (lastsap->desc == NULL && pcontext.sap->desc == NULL)) {
4736               if (AsnIoMemComp (lastsfp, prt, (AsnWriteFunc) SeqFeatAsnWrite)) {
4737                 suppress = TRUE;
4738               }
4739             }
4740           }
4741         }
4742 
4743         /* make sure feature maps within nucleotide sublocation */
4744 
4745         if (! suppress) {
4746           if (ajp->ajp.slp != NULL) {
4747             location = aaFeatLoc_to_dnaFeatLoc (cds, prt->location);
4748             slp = SeqLocMerge (nbsp, location, NULL, FALSE, TRUE, FALSE);
4749             if (slp != NULL) {
4750               sip = SeqIdParse ("lcl|dummy");
4751               newloc = SeqLocReMapEx (sip, ajp->ajp.slp, slp, 0, FALSE, ajp->masterStyle);
4752               SeqIdFree (sip);
4753               SeqLocFree (slp);
4754               if (newloc == NULL) {
4755                 suppress = TRUE;
4756               }
4757               SeqLocFree (newloc);
4758             } else {
4759               suppress = TRUE;
4760             }
4761             SeqLocFree (location);
4762           }
4763         }
4764 
4765         if (! suppress) {
4766 
4767           fbp = (FeatBlockPtr) Asn2gbAddBlock (awp, FEATURE_BLOCK, sizeof (IntFeatBlock));
4768           if (fbp != NULL) {
4769 
4770             fbp->entityID = pcontext.entityID;
4771             fbp->itemID = pcontext.itemID;
4772             fbp->itemtype = OBJ_SEQFEAT;
4773             fbp->featdeftype = pcontext.featdeftype;
4774             ifp = (IntFeatBlockPtr) fbp;
4775             ifp->mapToNuc = TRUE;
4776             ifp->mapToProt = FALSE;
4777             ifp->mapToGen = FALSE;
4778             ifp->mapToMrna = FALSE;
4779             ifp->mapToPep = FALSE;
4780             ifp->firstfeat = awp->firstfeat;
4781             awp->firstfeat = FALSE;
4782 
4783             if (awp->afp != NULL) {
4784               DoImmediateFormat (awp->afp, (BaseBlockPtr) fbp);
4785             }
4786           }
4787         }
4788 
4789         lastsfp = prt;
4790         lastsap = pcontext.sap;
4791         lastleft = pcontext.left;
4792         lastright = pcontext.right;
4793 
4794       }
4795     }
4796     prt = SeqMgrGetNextFeature (pbsp, prt, 0, 0, &pcontext);
4797   }
4798 }
4799 
4800 static void GetRemoteFeatsOnCdsProduct (
4801   SeqFeatPtr cds,
4802   BioseqPtr nbsp,
4803   BioseqPtr pbsp,
4804   IntAsn2gbJobPtr ajp,
4805   Asn2gbWorkPtr awp
4806 )
4807 
4808 {
4809   BioseqPtr        bsp;
4810   FeatBlockPtr     fbp;
4811   ValNodePtr       head = NULL;
4812   IntFeatBlockPtr  ifp;
4813   Boolean          isRefSeq;
4814   Int4             lastleft;
4815   Int4             lastright;
4816   SeqAnnotPtr      lastsap;
4817   SeqFeatPtr       lastsfp;
4818   SeqLocPtr        location;
4819   SeqLocPtr        newloc;
4820   SeqFeatPtr       prt;
4821   ValNodePtr       publist;
4822   Asn2gbFreeFunc   remotefree;
4823   Asn2gbLockFunc   remotelock;
4824   ValNodePtr       remotevnp;
4825   SeqAnnotPtr      sap;
4826   SeqFeatPtr       sfp;
4827   SeqIdPtr         sip;
4828   SeqLocPtr        slp;
4829   Boolean          suppress;
4830   ValNodePtr       vnp;
4831 
4832   if (cds == NULL || ajp == NULL || awp == NULL) return;
4833   if (nbsp == NULL || pbsp == NULL || (! ISA_aa (pbsp->mol))) return;
4834 
4835   if (awp->hideCdsProdFeats) return;
4836 
4837   if (ajp->remotelock == NULL) return;
4838 
4839   remotelock = ajp->remotelock;
4840   remotefree = ajp->remotefree;
4841 
4842   sip = SeqIdFindBest (pbsp->id, SEQID_GI);
4843   if (sip == NULL) return;
4844 
4845   remotevnp = remotelock (sip, ajp->remotedata);
4846   if (remotevnp == NULL) return;
4847 
4848   /* do cleanup of remotely fetched feature tables */
4849 
4850   for (vnp = remotevnp; vnp != NULL; vnp = vnp->next) {
4851     bsp = (BioseqPtr) vnp->data.ptrvalue;
4852     if (bsp == NULL) continue;
4853     for (sap = bsp->annot; sap != NULL; sap = sap->next) {
4854       if (sap->type != 1) continue;
4855       for (sfp = (SeqFeatPtr) sap->data; sfp != NULL; sfp = sfp->next) {
4856         publist = NULL;
4857         CleanUpSeqFeat (sfp, FALSE, FALSE, TRUE, TRUE, &publist);
4858         sfp->idx.subtype = FindFeatDefType (sfp);
4859         ValNodeFreeData (publist);
4860         ValNodeAddPointer (&head, 0, (Pointer) sfp);
4861       }
4862     }
4863   }
4864 
4865   if (head == NULL) return;
4866 
4867   isRefSeq = FALSE;
4868   for (sip = nbsp->id; sip != NULL; sip = sip->next) {
4869     if (sip->choice == SEQID_OTHER) {
4870       isRefSeq = TRUE;
4871     }
4872   }
4873 
4874   /* explore mat_peptides, sites, etc. */
4875 
4876   lastsfp = NULL;
4877   lastsap = NULL;
4878   lastleft = 0;
4879   lastright = 0;
4880 
4881   for (vnp = head; vnp != NULL; vnp = vnp->next) {
4882 
4883     prt = (SeqFeatPtr) vnp->data.ptrvalue;
4884     if (prt == NULL) continue;
4885 
4886     if (prt->idx.subtype == FEATDEF_REGION ||
4887         prt->idx.subtype == FEATDEF_SITE ||
4888         prt->idx.subtype == FEATDEF_BOND ||
4889         prt->idx.subtype == FEATDEF_mat_peptide_aa ||
4890         prt->idx.subtype == FEATDEF_sig_peptide_aa ||
4891         prt->idx.subtype == FEATDEF_transit_peptide_aa ||
4892         (prt->idx.subtype == FEATDEF_preprotein /* && isRefSeq */)) {
4893 
4894       if (awp->hideSitesBondsRegions && (prt->idx.subtype == FEATDEF_REGION ||
4895                                          prt->idx.subtype == FEATDEF_SITE ||
4896                                          prt->idx.subtype == FEATDEF_BOND)) {
4897 
4898         /* hide site, bond, and region features */
4899 
4900       } else if (awp->hideCddFeats && prt->idx.subtype == FEATDEF_REGION && IsCDD (prt)) {
4901 
4902         /* passing this test prevents mapping of COG CDD region features */
4903 
4904       } else {
4905 
4906         suppress = FALSE;
4907 
4908         /* make sure feature maps within nucleotide sublocation */
4909 
4910         if (! suppress) {
4911           if (ajp->ajp.slp != NULL) {
4912             location = aaFeatLoc_to_dnaFeatLoc (cds, prt->location);
4913             slp = SeqLocMerge (nbsp, location, NULL, FALSE, TRUE, FALSE);
4914             if (slp != NULL) {
4915               sip = SeqIdParse ("lcl|dummy");
4916               newloc = SeqLocReMapEx (sip, ajp->ajp.slp, slp, 0, FALSE, ajp->masterStyle);
4917               SeqIdFree (sip);
4918               SeqLocFree (slp);
4919               if (newloc == NULL) {
4920                 suppress = TRUE;
4921               }
4922               SeqLocFree (newloc);
4923             } else {
4924               suppress = TRUE;
4925             }
4926             SeqLocFree (location);
4927           }
4928         }
4929 
4930         if (! suppress) {
4931 
4932           fbp = (FeatBlockPtr) Asn2gbAddBlock (awp, FEATURE_BLOCK, sizeof (IntFeatBlock));
4933           if (fbp != NULL) {
4934 
4935             fbp->entityID = 0;
4936             fbp->itemID = 0;
4937             fbp->itemtype = OBJ_SEQFEAT;
4938             fbp->featdeftype = prt->idx.subtype;
4939             ifp = (IntFeatBlockPtr) fbp;
4940             ifp->mapToNuc = TRUE;
4941             ifp->mapToProt = FALSE;
4942             ifp->mapToGen = FALSE;
4943             ifp->mapToMrna = FALSE;
4944             ifp->mapToPep = FALSE;
4945             ifp->firstfeat = awp->firstfeat;
4946             awp->firstfeat = FALSE;
4947 
4948             if (awp->afp != NULL) {
4949               DoImmediateRemoteFeatureFormat (awp->afp, (BaseBlockPtr) fbp, prt);
4950             }
4951           }
4952         }
4953       }
4954     }
4955   }
4956 
4957   ValNodeFree (head);
4958 
4959   if (remotefree != NULL) {
4960     remotefree (remotevnp, ajp->remotedata);
4961   } else {
4962     /* otherwise free Bioseqs and ValNode chain ourselves */
4963     for (vnp = remotevnp; vnp != NULL; vnp = vnp->next) {
4964       bsp = (BioseqPtr) vnp->data.ptrvalue;
4965       if (bsp != NULL) {
4966         BioseqFree (bsp);
4967       }
4968     }
4969     ValNodeFree (remotevnp);
4970   }
4971 }
4972 
4973 static Boolean NotEMBLorDDBJ (
4974   BioseqPtr bsp
4975 )
4976 
4977 {
4978   SeqIdPtr  sip;
4979 
4980   if (bsp == NULL) return TRUE;
4981   for (sip = bsp->id; sip != NULL; sip = sip->next) {
4982     if (sip->choice == SEQID_EMBL || sip->choice == SEQID_TPE) return FALSE;
4983     if (sip->choice == SEQID_DDBJ || sip->choice == SEQID_TPD) return FALSE;
4984   }
4985   return TRUE;
4986 }
4987 
4988 static Boolean LIBCALLBACK GetFeatsOnBioseq (
4989   SeqFeatPtr sfp,
4990   SeqMgrFeatContextPtr fcontext
4991 )
4992 
4993 {
4994   IntAsn2gbJobPtr    ajp;
4995   Asn2gbSectPtr      asp;
4996   Asn2gbWorkPtr      awp;
4997   BioseqPtr          bsp;
4998   Char               buf [41];
4999   SeqFeatPtr         cds;
5000   SeqMgrFeatContext  cdscontext;
5001   FeatBlockPtr       fbp;
5002   SeqLocPtr          firstslp;
5003   GBQualPtr          gbq;
5004   SeqFeatPtr         gene;
5005   Int4               gi;
5006   GeneRefPtr         grp;
5007   Boolean            juststop = FALSE;
5008   IntCdsBlockPtr     icp;
5009   Int2               idx;
5010   IntFeatBlockPtr    ifp;
5011   IntPrtBlockPtr     ipp;
5012   Boolean            is_whole;
5013   Int4Ptr            ivals;
5014   Int2               j;
5015   SeqAnnotPtr        lastsap;
5016   SeqFeatPtr         lastsfp;
5017   SeqLocPtr          lastslp;
5018   SeqLocPtr          newloc;
5019   Int2               numivals;
5020   Boolean            okay;
5021   SeqEntryPtr        oldscope;
5022   BioseqPtr          parent;
5023   Boolean            partial5;
5024   Boolean            partial3;
5025   ValNodePtr         ppr;
5026   BioseqPtr          prod;
5027   ProtRefPtr         prp;
5028   Boolean            pseudo = FALSE;
5029   RNAGenPtr          rgp;
5030   RnaRefPtr          rrp;
5031   SeqEntryPtr        sep;
5032   SeqIntPtr          sintp;
5033   SeqIdPtr           sip;
5034   SeqLocPtr          slp;
5035   Int4               start;
5036   Int4               stop;
5037   TextSeqIdPtr       tsip;
5038   ValNodePtr         vnp;
5039   /*
5040   SeqMgrDescContext  dcontext;
5041   PubdescPtr         pdp;
5042   SeqDescrPtr        sdp;
5043   */
5044 
5045   if (sfp == NULL || fcontext == NULL) return FALSE;
5046   awp = (Asn2gbWorkPtr) fcontext->userdata;
5047   if (awp == NULL) return FALSE;
5048   ajp = awp->ajp;
5049   if (ajp == NULL) return FALSE;
5050   asp = awp->asp;
5051   if (asp == NULL) return FALSE;
5052   bsp = asp->bsp;
5053   if (bsp == NULL) return FALSE;
5054 
5055   if (fcontext->featdeftype == FEATDEF_PUB ||
5056       fcontext->featdeftype == FEATDEF_NON_STD_RESIDUE ||
5057       fcontext->featdeftype == FEATDEF_RSITE ||
5058       fcontext->featdeftype == FEATDEF_SEQ) return TRUE;
5059 
5060   if (fcontext->featdeftype == FEATDEF_BIOSRC) return TRUE;
5061 
5062   if (ajp->flags.validateFeats &&
5063       (fcontext->featdeftype == FEATDEF_BAD ||
5064        fcontext->featdeftype == FEATDEF_virion)) {
5065     return TRUE;
5066   }
5067 
5068   if (ISA_na (bsp->mol) && fcontext->featdeftype == FEATDEF_HET) return TRUE;
5069 
5070   /* check feature customization flags */
5071 
5072   if (awp->hideImpFeats && sfp->data.choice == SEQFEAT_IMP && fcontext->featdeftype != FEATDEF_operon) return TRUE;
5073   if (awp->hideVariations && fcontext->featdeftype == FEATDEF_variation) return TRUE;
5074   if (awp->hideRepeatRegions && fcontext->featdeftype == FEATDEF_repeat_region) return TRUE;
5075   if (awp->hideGaps && fcontext->featdeftype == FEATDEF_gap) return TRUE;
5076   if (ISA_aa (bsp->mol) && fcontext->featdeftype == FEATDEF_REGION &&
5077       awp->hideCddFeats && IsCDD (sfp)) return TRUE;
5078   if (awp->hideSitesBondsRegions && (fcontext->featdeftype == FEATDEF_REGION ||
5079                                      fcontext->featdeftype == FEATDEF_SITE ||
5080                                      fcontext->featdeftype == FEATDEF_BOND)) return TRUE;
5081 
5082   /* DDBJ does not want to show gene features */
5083 
5084   if (fcontext->seqfeattype == SEQFEAT_GENE && awp->hideGeneFeats) return TRUE;
5085 
5086   /* no longer suppressing comment features that are full length */
5087 
5088   /*
5089   if (fcontext->seqfeattype == SEQFEAT_COMMENT &&
5090       fcontext->left == awp->from && fcontext->right == awp->to) return TRUE;
5091   */
5092 
5093   ivals = fcontext->ivals;
5094   numivals = fcontext->numivals;
5095 
5096   /* check to see if last interval is on this awp->from - awp->to range */
5097 
5098   if (ivals != NULL && numivals > 0) {
5099     idx = (numivals - 1) * 2;
5100     start = ivals [idx];
5101     stop = ivals [idx + 1];
5102     if (stop < awp->from || stop > awp->to) {
5103 
5104       /* may need to map sig_peptide on a different segment */
5105 
5106       if (fcontext->seqfeattype == SEQFEAT_CDREGION) {
5107         sip = SeqLocIdForProduct (sfp->product);
5108         bsp = BioseqFind (sip);
5109         GetFeatsOnCdsProduct (sfp, asp->bsp, bsp, ajp, awp);
5110       }
5111 
5112       if (! awp->showAllFeats) return TRUE;
5113 
5114       /* if showing one segment, only show features covering this segment */
5115 
5116       if (fcontext->right < awp->from || fcontext->left > awp->to) return TRUE;
5117 
5118     } else if (fcontext->farloc && NotEMBLorDDBJ (awp->bsp)) {
5119 
5120       /* last interval may not have been mapped to bioseq if far */
5121 
5122       firstslp = NULL;
5123       lastslp = NULL;
5124 
5125       slp = SeqLocFindNext (sfp->location, NULL);
5126       while (slp != NULL) {
5127         if (slp->choice != SEQLOC_NULL) {
5128           lastslp = slp;
5129           if (firstslp == NULL) {
5130             firstslp = slp;
5131           }
5132         }
5133         slp = SeqLocFindNext (sfp->location, slp);
5134       }
5135 
5136       /* !!! EMBL may have different desired behavior on where to map !!! */
5137 
5138       if (firstslp != NULL && SeqLocStrand (firstslp) == Seq_strand_minus) {
5139         slp = firstslp;
5140       } else {
5141         slp = lastslp;
5142       }
5143 
5144       if (slp != NULL) {
5145         sip = SeqLocId (slp);
5146         if (sip != NULL) {
5147           bsp = BioseqFindCore (sip);
5148           if (bsp == NULL || (bsp != awp->parent && bsp != awp->bsp)) {
5149 
5150             return TRUE;
5151           }
5152         }
5153       }
5154     }
5155   }
5156 
5157   /* make sure feature is within sublocation */
5158 
5159   if (ajp->ajp.slp != NULL) {
5160     if (SeqLocCompare (sfp->location, ajp->ajp.slp) == SLC_NO_MATCH) {
5161       slp = SeqLocMerge (bsp, sfp->location, NULL, FALSE, TRUE, FALSE);
5162       if (slp == NULL) return TRUE;
5163       sip = SeqIdParse ("lcl|dummy");
5164       newloc = SeqLocReMapEx (sip, ajp->ajp.slp, slp, 0, FALSE, ajp->masterStyle);
5165       SeqIdFree (sip);
5166       SeqLocFree (slp);
5167       if (newloc == NULL) return TRUE;
5168       SeqLocFree (newloc);
5169     }
5170   }
5171 
5172   /* suppress duplicate features (on nucleotide) */
5173 
5174   lastsfp = awp->lastsfp;
5175   lastsap = awp->lastsap;
5176   if (lastsfp != NULL && lastsap != NULL) {
5177     if (lastsfp->idx.subtype == sfp->idx.subtype &&
5178         awp->lastleft == fcontext->left &&
5179         awp->lastright == fcontext->right) {
5180         if (lastsap == fcontext->sap ||
5181             (lastsap->desc == NULL && fcontext->sap->desc == NULL)) {
5182         if (AsnIoMemComp (lastsfp, sfp, (AsnWriteFunc) SeqFeatAsnWrite)) {
5183           return TRUE;
5184         }
5185       }
5186     }
5187   }
5188 
5189   /* if RELEASE_MODE, verify that features have all mandatory qualifiers */
5190 
5191   if (ajp->flags.needRequiredQuals) {
5192     okay = FALSE;
5193 
5194     switch (fcontext->featdeftype) {
5195 
5196     case FEATDEF_CDS:
5197       if (ajp->flags.checkCDSproductID) {
5198         /* non-pseudo CDS must have /product */
5199         if (sfp->pseudo) {
5200           pseudo = TRUE;
5201         }
5202         grp = SeqMgrGetGeneXref (sfp);
5203         if (grp == NULL) {
5204           sep = GetTopSeqEntryForEntityID (ajp->ajp.entityID);
5205           oldscope = SeqEntrySetScope (sep);
5206           gene = SeqMgrGetOverlappingGene (sfp->location, NULL);
5207           SeqEntrySetScope (oldscope);
5208           if (gene != NULL) {
5209             grp = (GeneRefPtr) gene->data.value.ptrvalue;
5210             if (gene->pseudo) {
5211               pseudo = TRUE;
5212             }
5213           }
5214         }
5215         if (grp != NULL && grp->pseudo) {
5216           pseudo = TRUE;
5217         }
5218         if (sfp->location != NULL) {
5219           if (CheckSeqLocForPartial (sfp->location, &partial5, &partial3)) {
5220             if (partial5 && (! partial3)) {
5221               if (SeqLocLen (sfp->location) <= 5) {
5222                 juststop = TRUE;
5223               }
5224             }
5225           }
5226         }
5227         if (pseudo || juststop) {
5228           okay = TRUE;
5229         } else if (sfp->product != NULL) {
5230           sip = SeqLocIdForProduct (sfp->product);
5231           if (sip != NULL) {
5232             if ((sip->choice == SEQID_GI && sip->data.intvalue > 0) ||
5233                 sip->choice == SEQID_LOCAL) {
5234               sep = GetTopSeqEntryForEntityID (ajp->ajp.entityID);
5235               oldscope = SeqEntrySetScope (sep);
5236               prod = BioseqFind (sip);
5237               SeqEntrySetScope (oldscope);
5238               if (prod != NULL) {
5239                 for (sip = prod->id; sip != NULL; sip = sip->next) {
5240                   if (sip->choice == SEQID_GENBANK ||
5241                      sip->choice == SEQID_EMBL ||
5242                       sip->choice == SEQID_DDBJ ||
5243                       sip->choice == SEQID_OTHER ||
5244                       sip->choice == SEQID_PATENT ||
5245                       sip->choice == SEQID_TPG ||
5246                       sip->choice == SEQID_TPE ||
5247                       sip->choice == SEQID_TPD ||
5248                       sip->choice == SEQID_GPIPE) {
5249                     tsip = (TextSeqIdPtr) sip->data.ptrvalue;
5250                     if (tsip != NULL && (StringDoesHaveText (tsip->accession))) {
5251                       if (ValidateAccn (tsip->accession) == 0)
5252                       okay = TRUE;
5253                     }
5254                   }
5255                 }
5256               } else if (sip->choice == SEQID_GI && sip->data.intvalue > 0) {
5257                 /* RELEASE_MODE requires that /protein_id is an accession */
5258                 gi = sip->data.intvalue;
5259                 if (GetAccnVerFromServer (gi, buf)) {
5260                   okay = TRUE;
5261                 } else {
5262                   sip = GetSeqIdForGI (gi);
5263                   if (sip != NULL) {
5264                     okay = TRUE;
5265                   }
5266                 }
5267               }
5268             } else if (sip->choice == SEQID_GENBANK ||
5269                        sip->choice == SEQID_EMBL ||
5270                        sip->choice == SEQID_DDBJ ||
5271                        sip->choice == SEQID_OTHER ||
5272                        sip->choice == SEQID_PATENT ||
5273                        sip->choice == SEQID_TPG ||
5274                        sip->choice == SEQID_TPE ||
5275                        sip->choice == SEQID_TPD ||
5276                        sip->choice == SEQID_GPIPE) {
5277               tsip = (TextSeqIdPtr) sip->data.ptrvalue;
5278               if (tsip != NULL && (StringDoesHaveText (tsip->accession))) {
5279                 if (ValidateAccn (tsip->accession) == 0)
5280                 okay = TRUE;
5281               }
5282             }
5283           }
5284         } else {
5285           if (sfp->excpt && (StringDoesHaveText (sfp->except_text))) {
5286             if (StringStr (sfp->except_text, "rearrangement required for product") != NULL) {
5287               okay = TRUE;
5288             }
5289           }
5290         }
5291       } else {
5292         okay = TRUE;
5293       }
5294       if (! okay) {
5295         ajp->relModeError = TRUE;
5296       }
5297       break;
5298 
5299     case FEATDEF_conflict:
5300       if (sfp->cit == NULL) {
5301         /* RefSeq allows conflict with accession in comment instead of sfp->cit */
5302         for (sip = bsp->id; sip != NULL; sip = sip->next) {
5303           if (sip->choice == SEQID_OTHER) {
5304             if (StringDoesHaveText (sfp->comment)) {
5305               okay = TRUE;
5306             }
5307           }
5308         }
5309       }
5310       /* continue on to old_sequence */
5311     case FEATDEF_old_sequence:
5312       /* conflict and old_sequence require a publication printable on the segment */
5313       vnp = sfp->cit;
5314 
5315       if (vnp != NULL && asp->referenceArray != NULL) {
5316         for (ppr = vnp->data.ptrvalue; ppr != NULL; ppr = ppr->next) {
5317           j = MatchRef (ppr, asp->referenceArray, asp->numReferences);
5318           if (j > 0) {
5319             okay = TRUE;
5320             break;
5321           }
5322         }
5323       }
5324       if (! okay) {
5325         /* compare qualifier can now substitute for citation qualifier */
5326         gbq = sfp->qual;
5327         while (gbq != NULL) {
5328           if (StringICmp (gbq->qual, "compare") == 0 && (StringDoesHaveText (gbq->val))) {
5329             okay = TRUE;
5330             break;
5331           }
5332           gbq = gbq->next;
5333         }
5334       }
5335       break;
5336 
5337     case FEATDEF_GENE:
5338       /* gene requires /gene or /locus_tag, but desc or syn can be mapped to /gene */
5339       grp = (GeneRefPtr) sfp->data.value.ptrvalue;
5340       if (grp != NULL) {
5341         if (StringDoesHaveText (grp->locus)) {
5342           okay = TRUE;
5343         }  else if (StringDoesHaveText (grp->locus_tag)) {
5344           okay = TRUE;
5345         } else if (StringDoesHaveText (grp->desc)) {
5346           okay = TRUE;
5347         } else {
5348           vnp = grp->syn;
5349           if (vnp != NULL) {
5350             if (StringDoesHaveText (vnp->data.ptrvalue)) {
5351               okay = TRUE;
5352             }
5353           }
5354         }
5355       }
5356       break;
5357 
5358     case FEATDEF_protein_bind:
5359     case FEATDEF_misc_binding:
5360       /* protein_bind or misc_binding require FTQUAL_bound_moiety */
5361       gbq = sfp->qual;
5362       while (gbq != NULL) {
5363         if (StringICmp (gbq->qual, "bound_moiety") == 0 && (StringDoesHaveText (gbq->val))) {
5364           okay = TRUE;
5365           break;
5366         }
5367         gbq = gbq->next;
5368       }
5369       break;
5370 
5371     case FEATDEF_modified_base:
5372       /* modified_base requires FTQUAL_mod_base */
5373       gbq = sfp->qual;
5374       while (gbq != NULL) {
5375         if (StringICmp (gbq->qual, "mod_base") == 0 && (StringDoesHaveText (gbq->val))) {
5376           okay = TRUE;
5377           break;
5378         }
5379         gbq = gbq->next;
5380       }
5381       break;
5382 
5383     case FEATDEF_gap:
5384       /* modified_base requires FTQUAL_estimated_length */
5385       gbq = sfp->qual;
5386       while (gbq != NULL) {
5387         if (StringICmp (gbq->qual, "estimated_length") == 0 && (StringDoesHaveText (gbq->val))) {
5388           okay = TRUE;
5389           break;
5390         }
5391         gbq = gbq->next;
5392       }
5393       break;
5394 
5395     case FEATDEF_operon:
5396       /* operon requires FTQUAL_operon */
5397       gbq = sfp->qual;
5398       while (gbq != NULL) {
5399         if (StringICmp (gbq->qual, "operon") == 0 && (StringDoesHaveText (gbq->val))) {
5400           okay = TRUE;
5401           break;
5402         }
5403         gbq = gbq->next;
5404       }
5405       break;
5406 
5407     case FEATDEF_ncRNA:
5408       /* ncRNA requires FTQUAL_ncRNA_class */
5409       gbq = sfp->qual;
5410       while (gbq != NULL) {
5411         if (StringICmp (gbq->qual, "ncRNA_class") == 0 && (StringDoesHaveText (gbq->val))) {
5412           okay = TRUE;
5413           break;
5414         }
5415         gbq = gbq->next;
5416       }
5417       rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
5418       if (rrp != NULL && rrp->ext.choice == 3) {
5419         rgp = (RNAGenPtr) rrp->ext.value.ptrvalue;
5420         if (rgp != NULL) {
5421           if (StringDoesHaveText (rgp->_class)) {
5422             okay = TRUE;
5423             break;
5424           }
5425         }
5426       }
5427       break;
5428 
5429     default:
5430       if (fcontext->featdeftype >= FEATDEF_GENE && fcontext->featdeftype < FEATDEF_MAX) {
5431         okay = TRUE;
5432       }
5433       break;
5434     }
5435 
5436     if (okay == FALSE) return TRUE;
5437   }
5438 
5439   /* if RELEASE_MODE, suppress features with location on near segmented Bioseq */
5440 
5441   if (ajp->flags.suppressSegLoc) {
5442     bsp = awp->parent;
5443     if (bsp != NULL && bsp->repr == Seq_repr_seg && SegHasParts (bsp)) {
5444       slp = SeqLocFindNext (sfp->location, NULL);
5445       while (slp != NULL) {
5446         sip = SeqLocId (slp);
5447         if (sip != NULL) {
5448           if (SeqIdIn (sip, bsp->id)) return TRUE;
5449         }
5450         slp = SeqLocFindNext (sfp->location, slp);
5451       }
5452     }
5453   }
5454 
5455   awp->lastsfp = sfp;
5456   awp->lastsap = fcontext->sap;
5457   awp->lastleft = fcontext->left;
5458   awp->lastright = fcontext->right;
5459 
5460   if (fcontext->seqfeattype == SEQFEAT_CDREGION) {
5461     fbp = (FeatBlockPtr) Asn2gbAddBlock (awp, FEATURE_BLOCK, sizeof (IntCdsBlock));
5462   } else if (fcontext->seqfeattype == SEQFEAT_PROT) {
5463     fbp = (FeatBlockPtr) Asn2gbAddBlock (awp, FEATURE_BLOCK, sizeof (IntPrtBlock));
5464   } else {
5465     fbp = (FeatBlockPtr) Asn2gbAddBlock (awp, FEATURE_BLOCK, sizeof (IntFeatBlock));
5466   }
5467   if (fbp == NULL) return TRUE;
5468 
5469   fbp->entityID = fcontext->entityID;
5470   fbp->itemID = fcontext->itemID;
5471   fbp->itemtype = OBJ_SEQFEAT;
5472   fbp->featdeftype = fcontext->featdeftype;
5473   ifp = (IntFeatBlockPtr) fbp;
5474   ifp->mapToNuc = FALSE;
5475   ifp->mapToProt = FALSE;
5476   ifp->mapToGen = FALSE;
5477   ifp->mapToMrna = FALSE;
5478   ifp->mapToPep = FALSE;
5479   ifp->firstfeat = awp->firstfeat;
5480   awp->firstfeat = FALSE;
5481   /* this allows remote SNP, CDD, MGC, etc., not to be treated as local annotation */
5482   if (awp->entityID != fbp->entityID || fbp->itemID <= awp->localFeatCount) {
5483     awp->featseen = TRUE;
5484   }
5485   awp->featjustseen = TRUE;
5486 
5487   if (fcontext->seqfeattype == SEQFEAT_PROT) {
5488 
5489     /* set calculated molecular weight flags for proteins */
5490 
5491     ifp->isPrt = TRUE;
5492     ipp = (IntPrtBlockPtr) fbp;
5493     prp = (ProtRefPtr) sfp->data.value.ptrvalue;
5494     if (prp != NULL) {
5495       if (prp->processed < 2) {
5496         is_whole = FALSE;
5497         slp = sfp->location;
5498         if (slp != NULL) {
5499           if (slp->choice == SEQLOC_WHOLE) {
5500             is_whole = TRUE;
5501           } else if (slp->choice == SEQLOC_INT) {
5502             sintp = (SeqIntPtr) slp->data.ptrvalue;
5503             if (sintp != NULL && 
5504                 bsp != NULL &&
5505                 sintp->from == 0 &&
5506                 sintp->to == bsp->length - 1) {
5507               is_whole = TRUE;
5508             }
5509           }
5510         }
5511         if (is_whole) {
5512           ipp->is_whole_loc = TRUE;
5513           if (awp->has_sig_peptide) {
5514             if (awp->has_mat_peptide) {
5515               ipp->suppress_mol_wt = TRUE;
5516             } else if (awp->sig_pept_trim_len > 0) {
5517               ipp->sig_pept_trim_len = awp->sig_pept_trim_len;
5518             }
5519           } else {
5520             ipp->trim_initial_met = TRUE;
5521           }
5522         }
5523       }
5524     }
5525   }
5526 
5527   if (awp->afp != NULL) {
5528     DoImmediateFormat (awp->afp, (BaseBlockPtr) fbp);
5529   }
5530 
5531   /* optionally map CDS from cDNA onto genomic */
5532 
5533   if (awp->isGPS && bsp != NULL && ISA_na (bsp->mol) && awp->copyGpsCdsUp &&
5534       fcontext->featdeftype == FEATDEF_mRNA) {
5535     sip = SeqLocIdForProduct (sfp->product);
5536     bsp = BioseqFind (sip);
5537     if (bsp != NULL && ISA_na (bsp->mol)) {
5538       cds = SeqMgrGetNextFeature (bsp, NULL, SEQFEAT_CDREGION, 0, &cdscontext);
5539       if (cds != NULL) {
5540         fbp = (FeatBlockPtr) Asn2gbAddBlock (awp, FEATURE_BLOCK, sizeof (IntCdsBlock));
5541         if (fbp != NULL) {
5542 
5543           fbp->entityID = cdscontext.entityID;
5544           fbp->itemID = cdscontext.itemID;
5545           fbp->itemtype = OBJ_SEQFEAT;
5546           fbp->featdeftype = cdscontext.featdeftype;
5547           ifp = (IntFeatBlockPtr) fbp;
5548           ifp->mapToNuc = FALSE;
5549           ifp->mapToProt = FALSE;
5550           ifp->mapToGen = TRUE;
5551           ifp->mapToMrna = FALSE;
5552           ifp->mapToPep = FALSE;
5553           ifp->firstfeat = awp->firstfeat;
5554           awp->firstfeat = FALSE;
5555 
5556           if (awp->afp != NULL) {
5557             DoImmediateFormat (awp->afp, (BaseBlockPtr) fbp);
5558           }
5559         }
5560       }
5561     }
5562   }
5563 
5564   if (fcontext->seqfeattype != SEQFEAT_CDREGION) return TRUE;
5565 
5566   /* if feature table format, do not get features from protein product */
5567 
5568   if (awp->format == FTABLE_FMT) return TRUE;
5569 
5570   /* if CDS, collect more information from product protein bioseq - may be part */
5571 
5572   sip = SeqLocIdForProduct (sfp->product);
5573   bsp = BioseqFind (sip);
5574   if (bsp == NULL || (! ISA_aa (bsp->mol))) return TRUE;
5575 
5576   ifp->isCDS = TRUE;
5577   icp = (IntCdsBlockPtr) ifp;
5578 
5579   /* first explore pubs to pick up figure and maploc - no longer shown */
5580 
5581   /*
5582   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_pub, &dcontext);
5583   while (sdp != NULL) {
5584     pdp = (PubdescPtr) sdp->data.ptrvalue;
5585     if (pdp != NULL) {
5586       if (icp->fig == NULL) {
5587         icp->fig = StringSaveNoNull (pdp->fig);
5588       }
5589       if (icp->maploc == NULL) {
5590         icp->maploc = StringSaveNoNull (pdp->maploc);
5591       }
5592     }
5593     sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_pub, &dcontext);
5594   }
5595   */
5596 
5597   /* product may be segmented part, and remaining features are indexed on parent */
5598 
5599   parent = SeqMgrGetParentOfPart (bsp, NULL);
5600   if (parent != NULL) {
5601     bsp = parent;
5602   }
5603 
5604   /* then explore mat_peptides, sites, etc. */
5605 
5606   GetFeatsOnCdsProduct (sfp, asp->bsp, bsp, ajp, awp);
5607 
5608   GetRemoteFeatsOnCdsProduct (sfp, asp->bsp, bsp, ajp, awp);
5609 
5610   return TRUE;
5611 }
5612 
5613 /*
5614 static Boolean TestGetAccnVerFromServer (Int4 gi, CharPtr buf)
5615 
5616 {
5617   Char      accn [64];
5618   SeqIdPtr  sip;
5619 
5620   if (buf == NULL) return FALSE;
5621   *buf = '\0';
5622   sip = GetSeqIdForGI (gi);
5623   if (sip == NULL) return FALSE;
5624   SeqIdWrite (sip, accn, PRINTID_TEXTID_ACC_VER, sizeof (accn) - 1);
5625   SeqIdFree (sip);
5626   if (StringLen (accn) < 40) {
5627     StringCpy (buf, accn);
5628   }
5629   return TRUE;
5630 }
5631 */
5632 
5633 static WgsAccnPtr GetWgsNode (
5634   Asn2gbWorkPtr awp,
5635   CharPtr accn
5636 )
5637 
5638 {
5639   ValNodePtr  vnp;
5640   WgsAccnPtr  wap = NULL;
5641 
5642   if (awp == NULL || StringHasNoText (accn)) return NULL;
5643 
5644   for (vnp = awp->wgsaccnlist; vnp != NULL; vnp = vnp->next) {
5645     wap = (WgsAccnPtr) vnp->data.ptrvalue;
5646     if (wap == NULL) continue;
5647     if (StringCmp (accn, wap->accn) == 0) return wap;
5648   }
5649   wap = (WgsAccnPtr) MemNew (sizeof (WgsAccn));
5650   if (wap == NULL) return NULL;
5651   StringCpy (wap->accn, accn);
5652   ValNodeAddPointer (&(awp->wgsaccnlist), 0, (Pointer) wap);
5653   return wap;
5654 }
5655 
5656 static Boolean LIBCALLBACK GetFeatsOnSeg (
5657   SeqLocPtr slp,
5658   SeqMgrSegmentContextPtr context
5659 )
5660 
5661 {
5662   Char             accn [41];
5663   Uint4            accntype;
5664   IntAsn2gbJobPtr  ajp;
5665   Asn2gbWorkPtr    awp;
5666   BioseqPtr        bsp;
5667   time_t           currTime;
5668   Uint2            entityID;
5669   Int4             from;
5670   Int4             gi;
5671   Int4             left;
5672   SeqLocPtr        loc;
5673   CharPtr          ptr;
5674   Int4             right;
5675   SeqIdPtr         sip;
5676   Int4             to;
5677   WgsAccnPtr       wap = NULL;
5678 
5679   if (slp == NULL || context == NULL) return FALSE;
5680   awp = (Asn2gbWorkPtr) context->userdata;
5681   if (awp == NULL) return FALSE;
5682   ajp = awp->ajp;
5683   if (ajp == NULL) return FALSE;
5684 
5685   /* do not fetch outside of desired component */
5686 
5687   if (ajp->ajp.slp != NULL) {
5688     left = GetOffsetInBioseq (ajp->ajp.slp, awp->parent, SEQLOC_LEFT_END);
5689     right = GetOffsetInBioseq (ajp->ajp.slp, awp->parent, SEQLOC_RIGHT_END);
5690 
5691     from = context->cumOffset;
5692     to = from + context->to - context->from;
5693 
5694     if (left > to) return TRUE;
5695     if (right < from) return TRUE;
5696   }
5697  
5698   from = awp->from;
5699   to = awp->to;
5700 
5701   sip = SeqLocId (slp);
5702   if (sip == NULL) {
5703     loc = SeqLocFindNext (slp, NULL);
5704     if (loc != NULL) {
5705       sip = SeqLocId (loc);
5706     }
5707   }
5708   if (sip == NULL) return TRUE;
5709 
5710   /* if Web Entrez WGS */
5711 
5712   if (awp->farFeatTimeLimit) {
5713     if (sip->choice == SEQID_GI) {
5714       gi = sip->data.intvalue;
5715       if (GetAccnVerFromServer (gi, accn)) {
5716         ptr = StringChr (accn, '.');
5717         if (ptr != NULL) {
5718           *ptr = '\0';
5719         }
5720         accntype = WHICH_db_accession (accn);
5721         if (ACCN_IS_WGS (accntype)) {
5722           accn [4] = '\0';
5723           wap = GetWgsNode (awp, accn);
5724           if (wap != NULL) {
5725             (wap->count)++;
5726             if (wap->count > 50) {
5727               if (! wap->hasfeats) return TRUE;
5728             }
5729           }
5730         }
5731       }
5732     }
5733     if (! awp->featseen) {
5734       currTime = GetSecs ();
5735       if (currTime - awp->farFeatStartTime > 25) return FALSE;
5736     }
5737   }
5738 
5739   /* may want to remote fetch genome component if not already in memory */
5740 
5741   bsp = BioseqLockById (sip);
5742 
5743   if (bsp == NULL) return TRUE;
5744 
5745   entityID = ObjMgrGetEntityIDForPointer (bsp);
5746 
5747   if (entityID != awp->entityID) {
5748 
5749     /* if segment not packaged in record, may need to feature index it */
5750 
5751     if (SeqMgrFeaturesAreIndexed (entityID) == 0) {
5752       SeqMgrIndexFeatures (entityID, NULL);
5753     }
5754 
5755     /* collect features indexed on the remote bioseq */
5756 
5757     awp->from = 0;
5758     awp->to = bsp->length - 1;
5759   }
5760 
5761   awp->lastsfp = NULL;
5762   awp->lastsap = NULL;
5763   awp->lastleft = 0;
5764   awp->lastright = 0;
5765 
5766   awp->featjustseen = FALSE;
5767 
5768   if (context->strand == Seq_strand_minus) {
5769     SeqMgrExploreFeaturesRev (bsp, (Pointer) awp, GetFeatsOnBioseq, /* awp->slp */ slp, NULL, NULL);
5770   } else {
5771     SeqMgrExploreFeatures (bsp, (Pointer) awp, GetFeatsOnBioseq, /* awp->slp */ slp, NULL, NULL);
5772   }
5773 
5774   if (awp->featjustseen && wap != NULL) {
5775     wap->hasfeats = TRUE;
5776   }
5777 
5778   /* restore original from and to */
5779 
5780   awp->from = from;
5781   awp->to = to;
5782 
5783   BioseqUnlock (bsp);
5784 
5785   return TRUE;
5786 }
5787 
5788 NLM_EXTERN void AddFeatureBlock (
5789   Asn2gbWorkPtr awp
5790 )
5791 
5792 {
5793   IntAsn2gbJobPtr    ajp;
5794   BioseqPtr          bsp;
5795   SeqFeatPtr         cds;
5796   SeqMgrDescContext  dcontext;
5797   SeqMgrFeatContext  fcontext;
5798   FeatBlockPtr       fbp;
5799   SeqFeatPtr         gene;
5800   IntFeatBlockPtr    ifp;
5801   Boolean            is_other;
5802   MolInfoPtr         mip;
5803   SeqFeatPtr         mrna;
5804   SeqFeatPtr         prot;
5805   SeqDescrPtr        sdp;
5806   SeqIdPtr           sip;
5807   SeqLocPtr          slp;
5808 
5809   if (awp == NULL) return;
5810   ajp = awp->ajp;
5811   if (ajp == NULL) return;
5812   bsp = awp->parent;
5813   if (bsp == NULL) return;
5814 
5815   awp->lastsfp = NULL;
5816   awp->lastsap = NULL;
5817   awp->lastleft = 0;
5818   awp->lastright = 0;
5819 
5820   /* for protein molecular weight calculation, need sig_peptide, etc. */
5821 
5822   awp->has_mat_peptide = FALSE;
5823   awp->has_sig_peptide = FALSE;
5824   awp->sig_pept_trim_len = 0;
5825 
5826   if (awp->format == GENPEPT_FMT && ISA_aa (bsp->mol)) {
5827     prot = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &fcontext);
5828     while (prot != NULL) {
5829       if (fcontext.featdeftype == FEATDEF_sig_peptide_aa ||
5830           fcontext.featdeftype == FEATDEF_transit_peptide_aa) {
5831         awp->has_sig_peptide = TRUE;
5832         if (fcontext.left == 0 && fcontext.right < bsp->length - 1) {
5833           awp->sig_pept_trim_len = fcontext.right + 1;
5834         }
5835       } else if (fcontext.featdeftype == FEATDEF_mat_peptide_aa) {
5836         awp->has_mat_peptide = TRUE;
5837       }
5838 
5839       prot = SeqMgrGetNextFeature (bsp, prot, 0, 0, &fcontext);
5840     }
5841   }
5842 
5843   /* optionally map gene from genomic onto cDNA */
5844 
5845   if (awp->isGPS && ISA_na (bsp->mol) && awp->copyGpsGeneDown) {
5846     sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_molinfo, &dcontext);
5847     if (sdp != NULL && sdp->choice == Seq_descr_molinfo) {
5848       mip = (MolInfoPtr) sdp->data.ptrvalue;
5849       if (mip != NULL) {
5850         if (mip->biomol == MOLECULE_TYPE_MRNA) {
5851           mrna = SeqMgrGetRNAgivenProduct (bsp, NULL);
5852           if (mrna != NULL) {
5853             gene = SeqMgrGetOverlappingGene (mrna->location, &fcontext);
5854             if (gene != NULL && gene->data.choice == SEQFEAT_GENE) {
5855 
5856               fbp = (FeatBlockPtr) Asn2gbAddBlock (awp, FEATURE_BLOCK, sizeof (IntCdsBlock));
5857               if (fbp != NULL) {
5858 
5859                 fbp->entityID = fcontext.entityID;
5860                 fbp->itemID = fcontext.itemID;
5861                 fbp->itemtype = OBJ_SEQFEAT;
5862                 fbp->featdeftype = fcontext.featdeftype;
5863                 ifp = (IntFeatBlockPtr) fbp;
5864                 ifp->mapToNuc = FALSE;
5865                 ifp->mapToProt = FALSE;
5866                 ifp->mapToGen = FALSE;
5867                 ifp->mapToMrna = TRUE;
5868                 ifp->mapToPep = FALSE;
5869                 ifp->isCDS = TRUE;
5870                 ifp->firstfeat = awp->firstfeat;
5871                 awp->firstfeat = FALSE;
5872 
5873                 if (awp->afp != NULL) {
5874                   DoImmediateFormat (awp->afp, (BaseBlockPtr) fbp);
5875                 }
5876               }
5877             }
5878           }
5879         }
5880       }
5881     }
5882   }
5883 
5884   awp->farFeatTimeLimit = FALSE;
5885   if (bsp->repr == Seq_repr_seg || bsp->repr == Seq_repr_delta) {
5886     if (awp->mode == ENTREZ_MODE) {
5887       awp->farFeatTimeLimit = TRUE;
5888     }
5889     /*
5890     if (GetWWW (ajp) && awp->mode == ENTREZ_MODE) {
5891       sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_molinfo, &dcontext);
5892       if (sdp != NULL && sdp->choice == Seq_descr_molinfo && sdp->data.ptrvalue != NULL) {
5893         mip = (MolInfoPtr) sdp->data.ptrvalue;
5894         if (mip->tech == MI_TECH_wgs || mip->tech == MI_TECH_composite_wgs_htgs) {
5895           awp->farFeatTimeLimit = TRUE;
5896         }
5897       }
5898     }
5899     */
5900   }
5901 
5902   if (! awp->onlyNearFeats) {
5903     if (awp->farFeatsSuppress) {
5904 
5905       if (bsp->repr == Seq_repr_seg || bsp->repr == Seq_repr_delta) {
5906 
5907         /* get start time for 25 second timeout in Web Entrez far WGS records */
5908 
5909         if (awp->farFeatTimeLimit) {
5910           awp->farFeatStartTime = GetSecs ();
5911         }
5912 
5913         /* if farFeatsSuppress first collect features on remote segments in MASTER_STYLE */
5914 
5915         SeqMgrExploreSegments (bsp, (Pointer) awp, GetFeatsOnSeg);
5916 
5917         awp->wgsaccnlist = ValNodeFreeData (awp->wgsaccnlist);
5918       }
5919     }
5920   }
5921 
5922   if ((! awp->farFeatsSuppress) || (! awp->featseen)) {
5923 
5924     /* reminder - features on near parts are indexed on segmented Bioseq */
5925 
5926     slp = ajp->ajp.slp;
5927     if (slp != NULL && SeqLocStrand (slp) == Seq_strand_minus) {
5928       SeqMgrExploreFeaturesRev (bsp, (Pointer) awp, GetFeatsOnBioseq, awp->slp, NULL, NULL);
5929     } else {
5930       SeqMgrExploreFeatures (bsp, (Pointer) awp, GetFeatsOnBioseq, awp->slp, NULL, NULL);
5931     }
5932   }
5933 
5934 
5935   if (awp->format == GENPEPT_FMT && ISA_aa (bsp->mol)) {
5936     cds = SeqMgrGetCDSgivenProduct (bsp, &fcontext);
5937     if (cds != NULL && cds->data.choice == SEQFEAT_CDREGION) {
5938 
5939       if (fcontext.entityID > 0 && fcontext.itemID > 0) {
5940 
5941         fbp = (FeatBlockPtr) Asn2gbAddBlock (awp, FEATURE_BLOCK, sizeof (IntCdsBlock));
5942         if (fbp != NULL) {
5943 
5944           fbp->entityID = fcontext.entityID;
5945           fbp->itemID = fcontext.itemID;
5946           fbp->itemtype = OBJ_SEQFEAT;
5947           fbp->featdeftype = fcontext.featdeftype;
5948           ifp = (IntFeatBlockPtr) fbp;
5949           ifp->mapToNuc = FALSE;
5950           ifp->mapToProt = TRUE;
5951           ifp->mapToGen = FALSE;
5952           ifp->mapToMrna = FALSE;
5953           ifp->mapToPep = FALSE;
5954           ifp->isCDS = TRUE;
5955           ifp->firstfeat = awp->firstfeat;
5956           awp->firstfeat = FALSE;
5957 
5958           if (awp->afp != NULL) {
5959             DoImmediateFormat (awp->afp, (BaseBlockPtr) fbp);
5960           }
5961         }
5962       } else if (cds->idx.entityID > 0 && cds->idx.itemID > 0) {
5963 
5964         /* if protein bioseq and cds feature but no nucleotide, handle as special case */
5965 
5966         fbp = (FeatBlockPtr) Asn2gbAddBlock (awp, FEATURE_BLOCK, sizeof (IntCdsBlock));
5967         if (fbp != NULL) {
5968 
5969           fbp->entityID = cds->idx.entityID;
5970           fbp->itemID = cds->idx.itemID;
5971           fbp->itemtype = OBJ_SEQFEAT;
5972           fbp->featdeftype = FEATDEF_CDS;
5973           ifp = (IntFeatBlockPtr) fbp;
5974           ifp->mapToNuc = FALSE;
5975           ifp->mapToProt = TRUE;
5976           ifp->mapToGen = FALSE;
5977           ifp->mapToMrna = FALSE;
5978           ifp->mapToPep = FALSE;
5979           ifp->isCDS = TRUE;
5980           ifp->firstfeat = awp->firstfeat;
5981           awp->firstfeat = FALSE;
5982 
5983           if (awp->afp != NULL) {
5984             DoImmediateFormat (awp->afp, (BaseBlockPtr) fbp);
5985           }
5986         }
5987       }
5988     }
5989     prot = SeqMgrGetPROTgivenProduct (bsp, &fcontext);
5990     if (prot != NULL && prot->data.choice == SEQFEAT_PROT) {
5991 
5992       is_other = FALSE;
5993       for (sip = bsp->id; sip != NULL; sip = sip->next) {
5994         if (sip->choice == SEQID_OTHER) {
5995           is_other = TRUE;
5996         }
5997       }
5998 
5999       /* for RefSeq records or GenBank not release_mode */
6000       if (is_other || (! ajp->flags.forGbRelease)) {
6001 
6002         fbp = (FeatBlockPtr) Asn2gbAddBlock (awp, FEATURE_BLOCK, sizeof (IntCdsBlock));
6003         if (fbp != NULL) {
6004 
6005           fbp->entityID = fcontext.entityID;
6006           fbp->itemID = fcontext.itemID;
6007           fbp->itemtype = OBJ_SEQFEAT;
6008           fbp->featdeftype = fcontext.featdeftype;
6009           ifp = (IntFeatBlockPtr) fbp;
6010           ifp->mapToNuc = FALSE;
6011           ifp->mapToProt = FALSE;
6012           ifp->mapToGen = FALSE;
6013           ifp->mapToMrna = FALSE;
6014           ifp->mapToPep = TRUE;
6015           ifp->firstfeat = awp->firstfeat;
6016           awp->firstfeat = FALSE;
6017 
6018           if (awp->afp != NULL) {
6019             DoImmediateFormat (awp->afp, (BaseBlockPtr) fbp);
6020           }
6021         }
6022       }
6023     }
6024   }
6025 
6026   if (awp->onlyNearFeats) return;
6027 
6028   if (awp->nearFeatsSuppress && awp->featseen) return;
6029 
6030   if (! awp->farFeatsSuppress) {
6031 
6032     if (bsp->repr == Seq_repr_seg || bsp->repr == Seq_repr_delta) {
6033 
6034       /* get start time for 25 second timeout in Web Entrez far WGS records */
6035 
6036       if (awp->farFeatTimeLimit) {
6037         awp->farFeatStartTime = GetSecs ();
6038       }
6039 
6040       /* if not farFeatsSuppress now collect features on remote segments in MASTER_STYLE */
6041 
6042       SeqMgrExploreSegments (bsp, (Pointer) awp, GetFeatsOnSeg);
6043 
6044       awp->wgsaccnlist = ValNodeFreeData (awp->wgsaccnlist);
6045     }
6046   }
6047 }
6048 
6049 NLM_EXTERN void AddFeatStatsBlock (
6050   Asn2gbWorkPtr awp
6051 )
6052 
6053 {
6054   IntAsn2gbJobPtr  ajp;
6055   BaseBlockPtr     bbp;
6056   BioseqPtr        bsp;
6057   StringItemPtr    ffstring;
6058 
6059   if (awp == NULL) return;
6060   ajp = awp->ajp;
6061   if ( ajp == NULL ) return;
6062   bsp = awp->bsp;
6063   if (bsp == NULL) return;
6064 
6065   if (awp->format == EMBL_FMT || awp->format == EMBLPEPT_FMT) return;
6066 
6067   bbp = Asn2gbAddBlock (awp, FEAT_STATS_BLOCK, sizeof (BaseBlock));
6068   if (bbp != NULL) {
6069     ffstring = FFGetString (ajp);
6070     if (ffstring != NULL) {
6071       FFStartPrint (ffstring, awp->format, 0, 12, "FEATSTATS", 12, 0, 0, NULL, FALSE);
6072     
6073       FFAddOneString (ffstring, "placeholder", FALSE, FALSE, TILDE_TO_SPACES);
6074   
6075       bbp->string = FFEndPrint (ajp, ffstring, awp->format, 12, 12, 0, 0, NULL);
6076       FFRecycleString(ajp, ffstring);
6077     }
6078 
6079     if (awp->afp != NULL) {
6080       DoImmediateFormat (awp->afp, bbp);
6081     }
6082   }
6083 }
6084 
6085 

source navigation ]   [ diff markup ]   [ identifier search ]   [ freetext search ]   [ file search ]  

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.