NCBI C Toolkit Cross Reference

C/sequin/sequin7.c


  1 /*   sequin7.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:  sequin7.c
 27 *
 28 * Author:  Jonathan Kans
 29 *
 30 * Version Creation Date:   1/3/98
 31 *
 32 * $Revision: 6.368 $
 33 *
 34 * File Description: 
 35 *
 36 * Modifications:  
 37 * --------------------------------------------------------------------------
 38 * Date     Name        Description of modification
 39 * -------  ----------  -----------------------------------------------------
 40 *
 41 *
 42 * ==========================================================================
 43 */
 44 
 45 #ifndef CODECENTER
 46 static char *date_of_compilation = __DATE__;
 47 static char *time_of_compilation = __TIME__;
 48 #else
 49 static char *date_of_compilation = "today";
 50 static char *time_of_compilation = "now";
 51 #endif
 52 
 53 #include "sequin.h"
 54 #include <gather.h>
 55 #include <edutil.h>
 56 #include <cdrgn.h>
 57 #include <subutil.h>
 58 #include <tofasta.h>
 59 #include <vsm.h>
 60 #include <document.h>
 61 #include <maputil.h>
 62 #include <asn2gnbp.h>
 63 #include <bspview.h>
 64 #include <findrepl.h>
 65 #include <toasn3.h>
 66 #include <toporg.h>
 67 #include <utilpub.h>
 68 #include <salsap.h>
 69 #include <salptool.h>
 70 #include <salutil.h>
 71 #include <saledit.h>
 72 #include <explore.h>
 73 #include <seqpanel.h>
 74 #include <alignmgr2.h>
 75 #include <actutils.h>
 76 #include <tax3api.h>
 77 #include <algo/blast/api/blast_options_api.h>
 78 #include <algo/blast/api/blast_seqalign.h>
 79 #include <algo/blast/api/blast_api.h>
 80 #include <salstruc.h>
 81 #include <valid.h> /* added for latloncountry conflict checking */
 82 
 83 #define CONVERT_TO_JOIN  1
 84 #define CONVERT_TO_ORDER 2
 85 #define DO_NOT_CONVERT   3
 86 
 87 NLM_EXTERN SeqEntryPtr FastaToSeqEntryInternal
 88 (
 89  VoidPtr input,          /* input pointer (file or memory) */
 90  Int4 type,              /* type of inquiry FASTA_MEM_IO or FASTA_FILE_IO */
 91  CharPtr PNTR last_char, /* returned pointer to next FASTA sequence */
 92  Boolean is_na,          /* type of sequence */
 93  CharPtr PNTR errormsg,  /* error messge for debugging */
 94  Boolean parseSeqId,     /* Parse SeqID from def line */
 95  CharPtr special_symbol     /* Returns special symbol if no SeqEntry */
 96  );
 97 
 98 NLM_EXTERN SeqEntryPtr SequinFastaToSeqEntryExEx
 99   (
100     FILE *fp,               /* file to get sequence from */ 
101     Boolean is_na,          /* type of sequence */
102     CharPtr PNTR errormsg,  /* error message for debugginq */
103     Boolean parseSeqId,     /* Parse SeqID from def line */
104     CharPtr special_symbol, /* Returns special symbol if no SeqEntry */
105     BoolPtr chars_stripped  /* set to TRUE if characters other than digits
106                              * were stripped from the FASTA sequence data */
107   )
108 {
109   BioseqPtr    bsp;
110   FileCache    fc;
111   Boolean      forceNuc = FALSE;
112   Boolean      forceProt = FALSE;
113   Pointer      dataptr;
114   Uint2        datatype;
115   Char         line [128];
116   Int4         pos;
117   SeqEntryPtr  sep = NULL;
118   CharPtr      str;
119 
120   if (errormsg != NULL) {
121     *errormsg = NULL;
122   }
123   if (special_symbol != NULL) {
124     *special_symbol = NULLB;
125   }
126   if (is_na) {
127     forceNuc = TRUE;
128   } else {
129     forceProt = TRUE;
130   }
131   dataptr = ReadAsnFastaOrFlatFileEx (fp, &datatype, NULL, forceNuc, forceProt, parseSeqId, FALSE, chars_stripped);
132   if (dataptr != NULL) {
133     if (datatype == OBJ_BIOSEQ) {
134       bsp = (BioseqPtr) dataptr;
135       sep = SeqMgrGetSeqEntryForData (bsp);
136       if (sep == NULL) {
137         sep = SeqEntryNew ();
138         if (sep != NULL) {
139           sep->choice = 1;
140           sep->data.ptrvalue = bsp;
141           SeqMgrSeqEntry (SM_BIOSEQ, (Pointer) bsp, sep);
142         }
143       }
144     }
145   } else if (special_symbol != NULL) {
146     /* look ahead to see what character caused inability to interpret line */
147     FileCacheSetup (&fc, fp);
148     /* pos = FileCacheTell (&fc); */
149     str = FileCacheReadLine (&fc, line, sizeof (line), NULL);
150     if (str != NULL && StringDoesHaveText (str)) {
151       TrimSpacesAroundString (str);
152     }
153     *special_symbol = line [0];
154     /* seek to start of next line after one that could not be interpreted */
155     pos = FileCacheTell (&fc);
156     FileCacheSetup (&fc, fp);
157     FileCacheSeek (&fc, pos);
158     fseek (fp, pos, SEEK_SET);
159   }
160   /* return FastaToSeqEntryInternal((void *)fp, 2, NULL,is_na, errormsg, parseSeqId, special_symbol); */
161   return sep;
162 }
163 
164 NLM_EXTERN SeqEntryPtr SequinFastaToSeqEntryEx 
165   (
166     FILE *fp,               /* file to get sequence from */ 
167     Boolean is_na,          /* type of sequence */
168     CharPtr PNTR errormsg,  /* error message for debugginq */
169     Boolean parseSeqId,     /* Parse SeqID from def line */
170     CharPtr special_symbol  /* Returns special symbol if no SeqEntry */
171   )
172 {
173   return SequinFastaToSeqEntryExEx (fp, is_na, errormsg, parseSeqId, special_symbol, NULL);    
174 }
175 
176 static FonT  titleFont = NULL;
177 
178 #ifndef WIN_MAC
179 void CreateSqnInitialFormMenus (WindoW w)
180 
181 {
182   BaseFormPtr   bfp;
183   MenU          m;
184 
185   bfp = (BaseFormPtr) GetObjectExtra (w);
186   if (bfp != NULL) {
187     m = PulldownMenu (w, "File");
188     AddAboutAndHelpMenuItems (m);
189     if (bfp->importform != NULL || bfp->exportform != NULL) {
190       if (bfp->importform != NULL) {
191         FormCommandItem (m, "Import...", bfp, VIB_MSG_IMPORT);
192       }
193       if (bfp->exportform != NULL) {
194         FormCommandItem (m, "Export...", bfp, VIB_MSG_EXPORT);
195       }
196       SeparatorItem (m);
197     }
198     FormCommandItem (m, "Quit", bfp, VIB_MSG_QUIT);
199     m = PulldownMenu (w, "Edit");
200     FormCommandItem (m, CUT_MENU_ITEM, bfp, VIB_MSG_CUT);
201     FormCommandItem (m, COPY_MENU_ITEM, bfp, VIB_MSG_COPY);
202     FormCommandItem (m, PASTE_MENU_ITEM, bfp, VIB_MSG_PASTE);
203     FormCommandItem (m, CLEAR_MENU_ITEM, bfp, VIB_MSG_DELETE);
204   }
205 }
206 #endif
207 
208 static void DefaultMessageProc (ForM f, Int2 mssg)
209 
210 {
211   StdEditorProcsPtr  sepp;
212 
213   sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
214   if (sepp != NULL) {
215     if (sepp->handleMessages != NULL) {
216       sepp->handleMessages (f, mssg);
217     }
218   }
219 }
220 
221 typedef struct startupform {
222   FORM_MESSAGE_BLOCK
223 } StartupForm, PNTR StartupFormPtr;
224 
225 static void ChangeDestination (GrouP g)
226 
227 {
228   Char  str [64];
229   Int2  val;
230 
231   val = GetValue (g);
232   switch (val) {
233     case 1 :
234       RemoveAppProperty ("SequinUseEMBLStyle");
235       RemoveAppProperty ("SequinUseDDBJStyle");
236       if (GetAppParam ("SEQUIN", "PREFERENCES", "DATABASE", NULL, str, sizeof (str))) {
237         if (! StringHasNoText (str)) {
238           if (StringICmp (str, "GenBank") != 0) {
239             WriteSequinAppParam ("PREFERENCES", "DATABASE", "GenBank");
240           }
241         }
242       }
243       break;
244     case 2 :
245       SetAppProperty ("SequinUseEMBLStyle", (void *) 1024);
246       RemoveAppProperty ("SequinUseDDBJStyle");
247       WriteSequinAppParam ("PREFERENCES", "DATABASE", "EMBL");
248       break;
249     case 3 :
250       RemoveAppProperty ("SequinUseEMBLStyle");
251       SetAppProperty ("SequinUseDDBJStyle", (void *) 1024);
252       WriteSequinAppParam ("PREFERENCES", "DATABASE", "DDBJ");
253       break;
254     default :
255       break;
256   }
257   SetupBioseqPageList ();
258 }
259 
260 static void CenterString (RectPtr rptr, CharPtr text, FonT fnt, Int2 inc)
261 
262 {
263   if (fnt != NULL) {
264     SelectFont (fnt);
265   }
266   rptr->bottom = rptr->top + LineHeight ();
267   DrawString (rptr, text, 'c', FALSE);
268   rptr->top = rptr->bottom + inc;
269 }
270 
271 extern void DrawAbout (PaneL p)
272 
273 {
274   RecT  r;
275 
276 
277   if (titleFont == NULL) {
278 #ifdef WIN_MAC
279     titleFont = GetFont ("Geneva", 18, TRUE, TRUE, FALSE, "");
280 #endif
281 #ifdef WIN_MSWIN
282     titleFont = GetFont ("Arial", 24, TRUE, TRUE, FALSE, "");
283 #endif
284 #ifdef WIN_MOTIF
285     titleFont = GetFont ("Courier", 24, TRUE, TRUE, FALSE, "");
286 #endif
287   }
288 
289   ObjectRect (p, &r);
290   InsetRect (&r, 4, 4);
291   r.top += 5;
292   Blue ();
293   CenterString (&r, "Sequin", titleFont, 5);
294   CenterString (&r, SEQUIN_VERSION, programFont, 5);
295   CenterString (&r, SEQUIN_SERVICES, programFont, 10);
296   CenterString (&r, "National Center for Biotechnology Information", systemFont, 5);
297   CenterString (&r, "National Library of Medicine", systemFont, 5);
298   CenterString (&r, "National Institutes of Health", systemFont, 10);
299   CenterString (&r, "(301) 496-2475", systemFont, 5);
300   CenterString (&r, "info@ncbi.nlm.nih.gov", systemFont, 0);
301 }
302 
303 extern Int2 AboutBoxWidth (void)
304 
305 {
306   Int2     max;
307   CharPtr  ptr;
308   Char     sequinServices [60];
309   Char     sequinVersion [60];
310   Int2     wid;
311 
312 
313   if (titleFont == NULL) {
314 #ifdef WIN_MAC
315     titleFont = GetFont ("Geneva", 18, TRUE, TRUE, FALSE, "");
316 #endif
317 #ifdef WIN_MSWIN
318     titleFont = GetFont ("Arial", 24, TRUE, TRUE, FALSE, "");
319 #endif
320 #ifdef WIN_MOTIF
321     titleFont = GetFont ("Courier", 24, TRUE, TRUE, FALSE, "");
322 #endif
323   }
324 
325   sprintf (sequinVersion, "Sequin Application Version %s", SEQUIN_APPLICATION);
326   ptr = "Standard Release";
327 /*#ifdef USE_ENTREZ*/
328   if (useEntrez || useBlast) {
329     ptr = "Network Aware";
330   }
331 /*#endif*/
332 /*#ifdef INTERNAL_NCBI_SEQUIN*/
333   if (indexerVersion) {
334     ptr = "Indexer Services";
335   }
336 /*#endif*/
337   if (genomeCenter != NULL) {
338     ptr = "Genome Center";
339   }
340   sprintf (sequinServices, "%s [%s]", ptr, date_of_compilation);
341 
342   SelectFont (titleFont);
343   max = StringWidth ("Sequin");
344   SelectFont (programFont);
345   wid = StringWidth (sequinVersion);
346   if (wid > max) {
347     max = wid;
348   }
349   wid = StringWidth (sequinServices);
350   if (wid > max) {
351     max = wid;
352   }
353   SelectFont (systemFont);
354   wid = StringWidth ("National Center for Biotechnology Information");
355   if (wid > max) {
356     max = wid;
357   }
358   max += 2 * stdCharWidth + 2;
359   return max;
360 }
361 
362 extern Int2 AboutBoxHeight (void)
363 
364 {
365   Int2  hgt;
366 
367   if (titleFont == NULL) {
368 #ifdef WIN_MAC
369     titleFont = GetFont ("Geneva", 18, TRUE, TRUE, FALSE, "");
370 #endif
371 #ifdef WIN_MSWIN
372     titleFont = GetFont ("Arial", 24, TRUE, TRUE, FALSE, "");
373 #endif
374 #ifdef WIN_MOTIF
375     titleFont = GetFont ("Courier", 24, TRUE, TRUE, FALSE, "");
376 #endif
377   }
378 
379   SelectFont (titleFont);
380   hgt = LineHeight () + 5;
381   SelectFont (programFont);
382   hgt += 2 * LineHeight () + 15;
383   SelectFont (systemFont);
384   hgt += 5 * LineHeight () + 25;
385   hgt += 18;
386   return hgt;
387 }
388 
389 extern ForM CreateStartupForm (Int2 left, Int2 top, CharPtr title,
390                                BtnActnProc startFa2htgs,
391                                BtnActnProc startPhrap,
392                                BtnActnProc buildContig,
393                                BtnActnProc startNew,
394                                BtnActnProc readExisting,
395                                BtnActnProc fetchFromNet,
396                                BtnActnProc showHelp,
397                                BtnActnProc createSubmissionTemplate,
398                                BtnActnProc quitProgram,
399                                WndActnProc activateForm)
400 
401 {
402   ButtoN          b;
403   GrouP           c;
404   GrouP           d;
405   GrouP           k;
406   PaneL           p;
407   StartupFormPtr  sfp;
408   Char            str [32];
409   WindoW          w;
410 #ifndef WIN_MAC
411   MenU            m;
412 #endif
413 
414   w = NULL;
415   sfp = MemNew (sizeof (StartupForm));
416   if (sfp != NULL) {
417     w = FixedWindow (left, top, -10, -10, title, NULL);
418     SetObjectExtra (w, sfp, StdCleanupFormProc);
419     sfp->form = (ForM) w;
420     sfp->formmessage = DefaultMessageProc;
421 
422 #ifndef WIN_MAC
423     m = PulldownMenu (w, "Misc");
424     CommandItem (m, "Net Configure...", NetConfigureProc);
425     if (useEntrez) {
426       /*
427       SeparatorItem (m);
428       CommandItem (m, "Entrez Query...", EntrezQueryProc);
429       SeparatorItem (m);
430       CommandItem (m, "Entrez2 Query...", Entrez2QueryProc);
431       */
432       if (extraServices) {
433         SeparatorItem (m);
434         CommandItem (m, "Process FASTA Nucleotide Updates", ParseInNucUpdates);
435       }
436     }
437     if (useDesktop) {
438       SeparatorItem (m);
439       VSMAddToMenu (m, VSM_DESKTOP);
440     }
441 #endif
442 
443     p = SimplePanel (w, AboutBoxWidth (), AboutBoxHeight (), DrawAbout);
444 
445     k = HiddenGroup (w, 4, 0, NULL);
446     SetGroupSpacing (k, 3, 10);
447     StaticPrompt (k, "Database for submission", 0, stdLineHeight, programFont, 'l');
448     d = HiddenGroup (k, 4, 0, ChangeDestination);
449     RadioButton (d, "GenBank");
450     RadioButton (d, "EMBL");
451     RadioButton (d, "DDBJ");
452     if (GetAppParam ("SEQUIN", "PREFERENCES", "DATABASE", NULL, str, sizeof (str))) {
453       if (StringICmp (str, "GenBank") == 0) {
454         SetValue (d, 1);
455       } else if (StringICmp (str, "EMBL") == 0) {
456         SetValue (d, 2);
457       } else if (StringICmp (str, "DDBJ") == 0) {
458         SetValue (d, 3);
459       } else {
460         SetValue (d, 1);
461       }
462     } else {
463       SetValue (d, 1);
464     }
465     ChangeDestination (d);
466 
467     c = HiddenGroup (w, 1, 0, NULL);
468     SetGroupSpacing (c, 10, 5);
469 
470     if (startFa2htgs != NULL) {
471       b = PushButton (c, "New FA2HTGS Submission", startFa2htgs);
472       SetObjectExtra (b, sfp, NULL);
473     }
474     if (startPhrap != NULL) {
475       b = PushButton (c, "New PHRAP Submission", startPhrap);
476       SetObjectExtra (b, sfp, NULL);
477     }
478     if (buildContig != NULL) {
479       b = PushButton (c, "Read CONTIG Instructions", buildContig);
480       SetObjectExtra (b, sfp, NULL);
481     }
482     b = PushButton (c, "Start New Submission", startNew);
483     SetObjectExtra (b, sfp, NULL);
484     b = PushButton (c, "Read Existing Record", readExisting);
485     SetObjectExtra (b, sfp, NULL);
486     if (fetchFromNet != NULL) {
487       b = PushButton (c, "Download From Entrez", fetchFromNet);
488       SetObjectExtra (b, sfp, NULL);
489     }
490     b = PushButton (c, "Show Help", showHelp);
491     SetObjectExtra (b, sfp, NULL);
492     if (createSubmissionTemplate != NULL)
493     {
494       b = PushButton (c, "Submission Template", createSubmissionTemplate);
495       SetObjectExtra (b, sfp, NULL);
496     }
497     b = PushButton (c, "Quit Program", quitProgram);
498     SetObjectExtra (b, sfp, NULL);
499 
500     AlignObjects (ALIGN_CENTER, (HANDLE) p, (HANDLE) c, (HANDLE) k, NULL);
501 
502     RealizeWindow (w);
503 
504     if (activateForm != NULL) {
505       SetActivate (w, activateForm);
506     }
507   }
508   return (ForM) w;
509 }
510 
511 typedef struct formatform {
512   FORM_MESSAGE_BLOCK
513 
514   GrouP           package;
515   GrouP           format;
516   GrouP           submType;
517   ButtoN          alignmentButton;
518   ButtoN          originalButton;
519   ButtoN          tpaButton;
520   TexT            numseqs;
521 
522   Int2            restoreFormatTo;
523 } FormatForm, PNTR FormatFormPtr;
524 
525 static Boolean allowGenomicPlusCDNA = FALSE;
526 
527 static void FormatBlockPtrToFormatForm (ForM f, Pointer data)
528 
529 {
530   FormatBlockPtr  fbp;
531   FormatFormPtr   ffp;
532   Char            str [32];
533 
534   ffp = (FormatFormPtr) GetObjectExtra (f);
535   fbp = (FormatBlockPtr) data;
536   if (ffp == NULL) return;
537   if (fbp != NULL) {
538     if (fbp->seqPackage > 0 && fbp->seqPackage <= NUM_SEQ_PKG) {
539       if ((! allowGenomicPlusCDNA) && fbp->seqPackage >= SEQ_PKG_GENOMICCDNA) {
540         SafeSetValue (ffp->package, fbp->seqPackage - 1);
541       } else {
542         SafeSetValue (ffp->package, fbp->seqPackage);
543       }
544       if (fbp->seqPackage <= SEQ_PKG_GENOMICCDNA || fbp->seqPackage == SEQ_PKG_GENBANK) {
545         SafeDisable (ffp->alignmentButton);
546       } else {
547         SafeEnable (ffp->alignmentButton);
548       }
549     } else {
550       SafeSetValue (ffp->package, SEQ_PKG_SINGLE);
551       SafeDisable (ffp->alignmentButton);
552     }
553     if (fbp->seqFormat > 0 && fbp->seqFormat <= NUM_SEQ_FMT) {
554       SafeSetValue (ffp->format, fbp->seqFormat);
555     } else {
556       SafeSetValue (ffp->format, SEQ_FMT_FASTA);
557     }
558     if (fbp->numSeqs > 0) {
559       IntToStr (fbp->numSeqs, str, 0, sizeof (str));
560       SafeSetTitle (ffp->numseqs, str);
561     } else {
562       SafeSetTitle (ffp->numseqs, "");
563     }
564   } else {
565     SafeSetValue (ffp->package, SEQ_PKG_SINGLE);
566     SafeDisable (ffp->alignmentButton);
567     SafeSetValue (ffp->format, SEQ_FMT_FASTA);
568     SafeSetTitle (ffp->numseqs, "");
569     ffp->restoreFormatTo = SEQ_FMT_FASTA;
570   }
571 }
572 
573 static Pointer FormatFormToFormatBlockPtr (ForM f)
574 
575 {
576   FormatBlockPtr  fbp;
577   FormatFormPtr   ffp;
578   Char            str [32];
579   Int2            val;
580 
581   fbp = NULL;
582   ffp = (FormatFormPtr) GetObjectExtra (f);
583   if (ffp == NULL) return NULL;
584   fbp = (FormatBlockPtr) MemNew (sizeof (FormatBlock));
585   if (fbp == NULL) return NULL;
586   fbp->seqPackage = GetValue (ffp->package);
587   if ((! allowGenomicPlusCDNA) && fbp->seqPackage >= SEQ_PKG_GENOMICCDNA) {
588     (fbp->seqPackage)++;
589   }
590   fbp->seqFormat = GetValue (ffp->format);
591   fbp->submType = GetValue (ffp->submType);
592   GetTitle (ffp->numseqs, str, sizeof (str));
593   if (StrToInt (str, &val) && val > 0) {
594     fbp->numSeqs = val;
595   } else {
596     fbp->numSeqs = 0;
597   }
598   return (Pointer) fbp;
599 }
600 
601 static void EnableOrDisableFormats (GrouP g)
602 
603 {
604   FormatFormPtr  ffp;
605   Int2           val;
606 
607   ffp = (FormatFormPtr) GetObjectExtra (g);
608   if (ffp == NULL) return;
609   val = GetValue (g);
610   if ((! allowGenomicPlusCDNA) && val >= SEQ_PKG_GENOMICCDNA) {
611     val++;
612   }
613   if (val <= SEQ_PKG_GENOMICCDNA || val == SEQ_PKG_GENBANK) {
614     if (Enabled (ffp->alignmentButton)) {
615       ffp->restoreFormatTo = GetValue (ffp->format);
616     }
617     SafeSetValue (ffp->format, SEQ_FMT_FASTA);
618     SafeDisable (ffp->alignmentButton);
619   } else {
620     if (! Enabled (ffp->alignmentButton)) {
621       SafeSetValue (ffp->format, ffp->restoreFormatTo);
622     }
623     SafeEnable (ffp->alignmentButton);
624   }
625 }
626 
627 static Boolean ExportTemplateMenu (ForM f, CharPtr filename)
628 {
629   WindoW                w;
630   GrouP                 h, g1, g2, c;
631   ButtoN                b;
632   DialoG                org_dlg;
633   TexT                  comment_txt;
634   ModalAcceptCancelData acd;
635   SeqEntryPtr           sep;
636   BioseqSetPtr          bssp;
637   BioSourcePtr          biop;
638   SeqDescrPtr           sdp;
639   CharPtr               org_name;
640   Boolean               done;
641   
642   if (ANS_NO == Message (MSG_YN, "Do you want to add an organism name and comment before saving the template?"))
643   {
644     bssp = BioseqSetNew ();
645     bssp->_class = BioseqseqSet_class_not_set;
646     sep = SeqEntryNew ();
647     sep->choice = 2;
648     sep->data.ptrvalue = bssp;
649        
650     done = ExportSubmitterBlockTemplate (sep, NULL);
651     if (!done)
652     {
653       /* if done were TRUE, sep would have been freed as part of the new SeqSubmit */
654       SeqEntryFree (sep);
655     }
656     return done;
657   }
658   
659   w = MovableModalWindow (-20, -13, -10, -10, "Submission Template", NULL);
660   h = HiddenGroup(w, -1, 0, NULL);
661   SetGroupSpacing (h, 10, 10);
662   
663   g1 = NormalGroup (h, 1, 0, "Organism Name", programFont, NULL);
664   org_dlg = OrganismSelectionDialog (g1, "");
665   g2 = NormalGroup (h, 2, 0, "Comment", programFont, NULL);
666   comment_txt = DialogText (g2, "", 30, NULL);  
667   
668   c = HiddenGroup (h, 2, 0, NULL);
669   b = PushButton (c, "Accept", ModalAcceptButton);
670   SetObjectExtra (b, &acd, NULL);
671   b = PushButton (c, "Cancel", ModalCancelButton);
672   SetObjectExtra (b, &acd, NULL);
673   
674   AlignObjects (ALIGN_CENTER, (HANDLE) g1, (HANDLE) g2,
675                               (HANDLE) c, (HANDLE) NULL);
676 
677   Show (w);
678   Select (w);
679   done = FALSE;
680   while (!done)
681   { 
682     acd.accepted = FALSE;
683     acd.cancelled = FALSE;
684     while (!acd.accepted && ! acd.cancelled)
685     {
686       ProcessExternalEvent ();
687       Update ();
688     }
689     ProcessAnEvent ();
690   
691     if (acd.cancelled)
692     {
693       done = TRUE;
694     }
695     else
696     {
697       bssp = BioseqSetNew ();
698       sep = SeqEntryNew ();
699       sep->choice = 2;
700       sep->data.ptrvalue = bssp;
701       bssp->_class = BioseqseqSet_class_not_set;
702     
703       org_name = DialogToPointer (org_dlg);
704       if (!StringHasNoText (org_name))
705       {
706         biop = BioSourceNew ();
707         biop->org = OrgRefNew ();
708         biop->org->taxname = org_name;
709         sdp = CreateNewDescriptor (sep, Seq_descr_source);
710         sdp->data.ptrvalue = biop;
711       }
712       else
713       {
714         org_name = MemFree (org_name);
715       }
716     
717       sdp = NULL;   
718       if (!TextHasNoText (comment_txt))
719       {
720         sdp = CreateNewDescriptor (sep, Seq_descr_comment);
721         sdp->data.ptrvalue = SaveStringFromText (comment_txt);
722       }
723     
724       done = ExportSubmitterBlockTemplate (sep, sdp);
725       if (!done)
726       {
727         /* if done were TRUE, sep would have been freed as part of the new SeqSubmit */
728         SeqEntryFree (sep);
729       }
730     }
731   }
732   Remove (w);
733   return acd.accepted;
734 }
735 
736 static void FormatFormMessage (ForM f, Int2 mssg)
737 
738 {
739   switch (mssg) {
740     case VIB_MSG_EXPORT :
741       ExportTemplateMenu (NULL, NULL);
742       break;
743     case VIB_MSG_CUT :
744       StdCutTextProc (NULL);
745       break;
746     case VIB_MSG_COPY :
747       StdCopyTextProc (NULL);
748       break;
749     case VIB_MSG_PASTE :
750       StdPasteTextProc (NULL);
751       break;
752     case VIB_MSG_DELETE :
753       StdDeleteTextProc (NULL);
754       break;
755     default :
756       DefaultMessageProc (f, mssg);
757       break;
758   }
759 }
760 
761 static void CreateFormatFormMenus (WindoW w)
762 {
763 #ifndef WIN_MAC  
764   BaseFormPtr   bfp;
765   MenU          m;
766 
767   bfp = (BaseFormPtr) GetObjectExtra (w);
768   if (bfp != NULL) {
769     m = PulldownMenu (w, "File");
770     FormCommandItem (m, "Export Template...", bfp, VIB_MSG_EXPORT);
771   }
772 #endif
773 }
774 
775 static void InitFormatFormActivate (WindoW w)
776 
777 {
778   IteM           exportItm;
779   FormatFormPtr  ffp;
780 
781   ffp = (FormatFormPtr) GetObjectExtra (w);
782   if (ffp != NULL) {
783     if (ffp->activate != NULL) {
784       ffp->activate (w);
785     }
786     exportItm = FindFormMenuItem ((BaseFormPtr) ffp, VIB_MSG_EXPORT);
787     SafeSetTitle (exportItm, "Export Template...");
788     SafeEnable (exportItm);
789   }
790 }
791 
792 extern ForM CreateFormatForm (Int2 left, Int2 top, CharPtr title,
793                               BtnActnProc goToNext,
794                               BtnActnProc goBack,
795                               WndActnProc activateForm)
796 
797 {
798   ButtoN         b;
799   GrouP          c;
800   FormatFormPtr  ffp;
801   GrouP          g1, g2, g3;
802   GrouP          h;
803   PrompT         ppt;
804   Char           str [32];
805   WindoW         w;
806 
807   w = NULL;
808   ffp = MemNew (sizeof (FormatForm));
809   if (ffp != NULL) {
810     w = FixedWindow (left, top, -10, -10, title, NULL);
811     SetObjectExtra (w, ffp, StdCleanupFormProc);
812     ffp->form = (ForM) w;
813     ffp->toform = FormatBlockPtrToFormatForm;
814     ffp->fromform = FormatFormToFormatBlockPtr;
815     ffp->formmessage = FormatFormMessage;
816     ffp->exportform = ExportTemplateMenu;
817 
818     SetGroupSpacing (w, 10, 10);
819 
820     CreateFormatFormMenus (w);
821 
822     h = HiddenGroup (w, -1, 0, NULL);
823     SetGroupSpacing (h, 3, 10);
824 
825     g1 = HiddenGroup (h, 2, 0, NULL);
826 
827     allowGenomicPlusCDNA = FALSE;
828     if (GetAppParam ("SEQUIN", "SETTINGS", "GENOMICPLUSTRANSCRIPTS", NULL, str, sizeof (str))) {
829       if (StringICmp (str, "TRUE") == 0) {
830         allowGenomicPlusCDNA = TRUE;
831       }
832     }
833 
834     ppt = StaticPrompt (g1, "Submission type", 0, 0, programFont, 'l');
835     ffp->package = HiddenGroup (g1, 2, 0, EnableOrDisableFormats);
836     SetObjectExtra (ffp->package, ffp, NULL);
837     RadioButton (ffp->package, "Single Sequence");
838     RadioButton (ffp->package, "Segmented Sequence");
839     RadioButton (ffp->package, "Gapped Sequence");
840     if (allowGenomicPlusCDNA) {
841       RadioButton (ffp->package, "Genomic + Transcripts");
842     }
843     RadioButton (ffp->package, "Population Study");
844     RadioButton (ffp->package, "Phylogenetic Study");
845     RadioButton (ffp->package, "Mutation Study");
846     RadioButton (ffp->package, "Environmental Samples");
847     RadioButton (ffp->package, "Batch Submission");
848     SetValue (ffp->package, SEQ_PKG_SINGLE);
849     AlignObjects (ALIGN_MIDDLE, (HANDLE) ppt, (HANDLE) ffp->package, NULL);
850 
851     g2 = HiddenGroup (h, 2, 0, NULL);
852 
853     ppt = StaticPrompt (g2, "Sequence data format", 0, 0, programFont, 'l');
854     ffp->format = HiddenGroup (g2, -1, 0, NULL);
855     SetObjectExtra (ffp->format, ffp, NULL);
856     RadioButton (ffp->format, "FASTA (no alignment)");
857     ffp->alignmentButton = RadioButton (ffp->format, "Alignment (FASTA+GAP, NEXUS, PHYLIP, etc.)");
858     Disable (ffp->alignmentButton);
859     SetValue (ffp->format, SEQ_FMT_FASTA);
860     ffp->restoreFormatTo = SEQ_FMT_FASTA;
861     AlignObjects (ALIGN_MIDDLE, (HANDLE) ppt, (HANDLE) ffp->format, NULL);
862 
863     g3 = HiddenGroup (h, 2, 0, NULL);
864 
865     ppt = StaticPrompt (g3, "Submission category", 0, 0, programFont, 'l');
866     ffp->submType = HiddenGroup (g3, -1, 0, NULL);
867     SetObjectExtra (ffp->submType, ffp, NULL);
868     ffp->originalButton = RadioButton (ffp->submType, "Original Submission");
869     ffp->tpaButton = RadioButton (ffp->submType, "Third Party Annotation");
870     SetValue (ffp->submType, SEQ_ORIG_SUBMISSION);
871     AlignObjects (ALIGN_MIDDLE, (HANDLE) ppt, (HANDLE) ffp->submType, NULL);
872 
873     c = HiddenGroup (w, 4, 0, NULL);
874     SetGroupSpacing (c, 10, 2);
875     b = PushButton (c, " << Prev Form ", goBack);
876     SetObjectExtra (b, ffp, NULL);
877     b = PushButton (c, " Next Form >> ", goToNext);
878     SetObjectExtra (b, ffp, NULL);
879 
880     AlignObjects (ALIGN_LEFT, (HANDLE) g1, (HANDLE) g2, (HANDLE) g3, NULL);
881     AlignObjects (ALIGN_CENTER, (HANDLE) h, (HANDLE) c, NULL);
882 
883     RealizeWindow (w);
884 
885     ffp->activate = activateForm;
886     SetActivate (w, InitFormatFormActivate);
887   }
888   return (ForM) w;
889 }
890 
891 extern SequinBlockPtr SequinBlockFree (SequinBlockPtr sbp)
892 
893 {
894   if (sbp != NULL) {
895     AuthorFree (sbp->contactperson);
896     AuthListFree (sbp->citsubauthors);
897     AffilFree (sbp->citsubaffil);
898     MemFree (sbp->citsubtitle);
899     DateFree (sbp->releasedate);
900   }
901   return NULL;
902 }
903 
904 extern void ExciseString (CharPtr str, CharPtr from, CharPtr to)
905 
906 {
907   Char     ch;
908   CharPtr  ptrf;
909   CharPtr  ptrt;
910 
911   if (str == NULL || from == NULL || to == NULL) return;
912   ptrf = StringISearch (str, from);
913   if (ptrf == NULL) return;
914   ptrt = StringISearch (ptrf, to);
915   if (ptrt == NULL) return;
916   ptrt += StringLen (to);
917   ch = *ptrt;
918   while (ch != '\0') {
919     *ptrf = ch;
920     ptrf++;
921     ptrt++;
922     ch = *ptrt;
923   }
924   *ptrf = '\0';
925 }
926 
927 typedef struct geneextendlist {
928   GeneRefPtr  grp;
929   SeqLocPtr   slp;
930   ObjMgrPtr   omp;
931   Boolean     rsult;
932   Char        label [41];
933 } GeneExtendList, PNTR GeneExtendPtr;
934 
935 static Boolean GeneExtendFunc (GatherContextPtr gcp)
936 
937 {
938   BioseqPtr      bsp;
939   GeneExtendPtr  gep;
940   GeneRefPtr     grp;
941   Boolean        hasNulls;
942   ObjMgrTypePtr  omtp;
943   SeqFeatPtr     sfp;
944   SeqLocPtr      slp;
945   Char           thislabel [41];
946 
947   if (gcp == NULL) return TRUE;
948 
949   gep = (GeneExtendPtr) gcp->userdata;
950   if (gep == NULL ) return TRUE;
951 
952   thislabel [0] = '\0';
953 
954   if (gcp->thistype == OBJ_SEQFEAT) {
955     sfp = (SeqFeatPtr) gcp->thisitem;
956     if (sfp != NULL && sfp->data.choice == SEQFEAT_GENE && sfp->data.value.ptrvalue != NULL) {
957       grp = (GeneRefPtr) sfp->data.value.ptrvalue;
958       omtp = ObjMgrTypeFind (gep->omp, gcp->thistype, NULL, NULL);
959       if (omtp == NULL) {
960         return TRUE;
961       }
962       if (omtp->labelfunc != NULL) {
963         (*(omtp->labelfunc)) (gcp->thisitem, thislabel, 40, OM_LABEL_CONTENT);
964       }
965       if (thislabel [0] != '\0') {
966         if (StringICmp (thislabel, gep->label) == 0) {
967           if (SeqLocCompare (gep->slp, sfp->location) != SLC_NO_MATCH) {
968             bsp = GetBioseqGivenSeqLoc (sfp->location, gcp->entityID);
969             if (bsp != NULL) {
970               slp = SeqLocMerge (bsp, sfp->location, gep->slp, TRUE, FALSE, FALSE);
971               if (slp != NULL) {
972                 sfp->location = SeqLocFree (sfp->location);
973                 sfp->location = slp;
974                 if (bsp->repr == Seq_repr_seg) {
975                   slp = SegLocToPartsEx (bsp, sfp->location, TRUE);
976                   sfp->location = SeqLocFree (sfp->location);
977                   sfp->location = slp;
978                   hasNulls = LocationHasNullsBetween (sfp->location);
979                   sfp->partial = (sfp->partial || hasNulls);
980                 }
981                 FreeAllFuzz (slp);
982                 gep->rsult = TRUE;
983               }
984             }
985           }
986           return FALSE;
987         }
988       }
989     }
990   }
991   return TRUE;
992 }
993 
994 extern Boolean ExtendGene (GeneRefPtr grp, SeqEntryPtr nsep, SeqLocPtr slp)
995 
996 {
997   GeneExtendList  gel;
998   GatherScope     gs;
999   ObjMgrTypePtr   omtp;
1000   SeqFeatPtr      sfp;
1001 
1002   if (grp == NULL || nsep == NULL || slp == NULL) return FALSE;
1003   gel.grp = grp;
1004   gel.slp = slp;
1005   gel.omp = ObjMgrGet ();
1006   gel.label [0] = '\0';
1007   gel.rsult = FALSE;
1008   omtp = ObjMgrTypeFind (gel.omp, OBJ_SEQFEAT, NULL, NULL);
1009   if (omtp != NULL && omtp->labelfunc != NULL) {
1010     sfp = SeqFeatNew ();
1011     if (sfp != NULL) {
1012       sfp->data.choice = SEQFEAT_GENE;
1013       sfp->data.value.ptrvalue = (Pointer) grp;
1014       (*(omtp->labelfunc)) ((Pointer) sfp, gel.label, 40, OM_LABEL_CONTENT);
1015       sfp->data.value.ptrvalue = NULL;
1016       SeqFeatFree (sfp);
1017     }
1018   }
1019   MemSet ((Pointer)(&gs), 0, sizeof (GatherScope));
1020   gs.seglevels = 1;
1021   gs.get_feats_location = TRUE;
1022   MemSet((Pointer)(gs.ignore), (int)(TRUE), (size_t)(OBJ_MAX * sizeof(Boolean)));
1023   gs.ignore[OBJ_BIOSEQ] = FALSE;
1024   gs.ignore[OBJ_BIOSEQ_SEG] = FALSE;
1025   gs.ignore[OBJ_SEQFEAT] = FALSE;
1026   gs.ignore[OBJ_SEQANNOT] = FALSE;
1027   GatherSeqEntry (nsep, (Pointer) &gel, GeneExtendFunc, &gs);
1028   return gel.rsult;
1029 }
1030 
1031 /*=====================================================================*/
1032 /*                                                                     */
1033 /* CreateGeneAndProtFeats() -                                          */
1034 /*                                                                     */
1035 /*=====================================================================*/
1036 
1037 static void CreateGeneAndProtFeats (SeqEntryPtr nsep, SeqEntryPtr psep,
1038                                     SeqLocPtr slp, CdRegionPtr crp, CharPtr title,
1039                                     CharPtr best, size_t maxsize, CharPtr PNTR ttl)
1040 
1041 {
1042   BioseqPtr   nbsp;
1043   BioseqPtr   pbsp;
1044   SeqFeatPtr  sfp;
1045   ProtRefPtr  prp = NULL;
1046   Boolean     partial5, partial3;
1047 
1048   if (nsep != NULL && psep != NULL && slp != NULL && crp != NULL && title != NULL) {
1049     if (best != NULL) {
1050       best [0] = '\0';
1051     }
1052     if (IS_Bioseq (nsep) && IS_Bioseq (psep)) {
1053       nbsp = (BioseqPtr) nsep->data.ptrvalue;
1054       pbsp = (BioseqPtr) psep->data.ptrvalue;
1055       if (nbsp != NULL && pbsp != NULL) {
1056 
1057         AddGeneFeatureFromTitle (nsep, title, slp);
1058       
1059         sfp = AddProteinFeatureFromDefline (psep, title);
1060         if (sfp != NULL && sfp->data.choice == SEQFEAT_PROT) {
1061           prp = sfp->data.value.ptrvalue;
1062           CheckSeqLocForPartial (slp, &partial5, &partial3);
1063           SetSeqLocPartial (sfp->location, partial5, partial3);
1064           sfp->partial = partial5 | partial3;
1065         }
1066           
1067         if (prp != NULL && best != NULL)
1068         {
1069           if (prp->name != NULL && !StringHasNoText (prp->name->data.ptrvalue))
1070           {
1071                   StringNCpy_0 (best, prp->name->data.ptrvalue, maxsize);
1072           }
1073           else if (!StringHasNoText (prp->desc))
1074           {
1075                   StringNCpy_0 (best, prp->desc, maxsize);
1076           }
1077         }
1078 
1079         AddCodingRegionFieldsFromProteinTitle (crp, title, ttl);
1080       }
1081     }
1082   }
1083 }
1084 
1085 static Boolean  intBoxUp;
1086 static Boolean  intBoxRsult;
1087 
1088 static void AcceptAskProc (ButtoN b)
1089 
1090 {
1091   intBoxRsult = TRUE;
1092   intBoxUp = FALSE;
1093 }
1094 
1095 static void CancelAskProc (ButtoN b)
1096 
1097 {
1098   intBoxRsult = FALSE;
1099   intBoxUp = FALSE;
1100 }
1101 
1102 static SeqLocPtr AskForInterval (SeqEntryPtr sep, BioseqPtr nuc, BioseqPtr prot)
1103 
1104 {
1105   GrouP       c;
1106   DialoG      d;
1107   GrouP       g;
1108   GrouP       m;
1109   SeqIdPtr    sip;
1110   SeqLocPtr   slp;
1111   Char        str [128];
1112   ValNodePtr  vnp;
1113   WindoW      w;
1114 
1115   slp = NULL;
1116   if (sep == NULL || nuc == NULL || prot == NULL) return NULL;
1117 
1118   if (GetAppParam ("SEQUIN", "PREFERENCES", "ASKIFSUGGESTFAILED", NULL, str, sizeof (str))) {
1119     if (StringICmp (str, "FALSE") == 0) {
1120       sip = SeqIdFindWorst (prot->id);
1121       SeqIdWrite (sip, str, PRINTID_REPORT, sizeof (str));
1122       Message (MSG_POSTERR, "Suggest failure for %s", str);
1123       return NULL;
1124     }
1125   }
1126 
1127   w = MovableModalWindow (-50, -33, -10, -10, "Enter coding region interval", NULL);
1128   g = HiddenGroup (w, -1, 0, NULL);
1129   m = NULL;
1130   SetGroupSpacing (g, 3, 10);
1131   if (prot->descr != NULL) {
1132     vnp = ValNodeFindNext (prot->descr, NULL, Seq_descr_title);
1133     if (vnp != NULL && vnp->data.ptrvalue != NULL) {
1134       m = MultiLinePrompt (g, (CharPtr) vnp->data.ptrvalue, stdCharWidth * 28, programFont);
1135     }
1136   }
1137   d = CreateIntervalEditorDialog (g, NULL, 4, 2, sep, TRUE, FALSE);
1138   c = HiddenGroup (g, 2, 0, NULL);
1139   SetGroupSpacing (c, 10, 2);
1140   DefaultButton (c, "Accept", AcceptAskProc);
1141   PushButton (c, "Cancel", CancelAskProc);
1142   AlignObjects (ALIGN_CENTER, (HANDLE) d, (HANDLE) c, (HANDLE) m, NULL);
1143   Show (w);
1144   Select (w);
1145   intBoxUp = TRUE;
1146   intBoxRsult = FALSE;
1147   while (intBoxUp) {
1148     ProcessEventOrIdle ();
1149   }
1150   ProcessAnEvent ();
1151   if (intBoxRsult) {
1152     slp = (SeqLocPtr) DialogToPointer (d);
1153   }
1154   Remove (w);
1155   return slp;
1156 }
1157 
1158 extern Boolean AutomaticProteinProcess (SeqEntryPtr esep, SeqEntryPtr psep,
1159                                         Int2 code, Boolean makeMRNA, SeqLocPtr use_this)
1160 
1161 {
1162   SeqFeatPtr   cds;
1163   CdRegionPtr  crp;
1164   Char         mRnaName [128];
1165   BioseqPtr    nbsp;
1166   SeqEntryPtr  nsep;
1167   BioseqPtr    pbsp;
1168   SeqFeatPtr   rna;
1169   RnaRefPtr    rrp;
1170   SeqLocPtr    slp;
1171   CharPtr      ttl;
1172   ValNodePtr   vnp;
1173   CharPtr      vnpstr;
1174   Boolean      partial5, partial3;
1175 
1176   if (esep == NULL || psep == NULL) return FALSE;
1177 
1178   nsep = FindNucSeqEntry (esep);
1179   if (nsep == NULL || (! IS_Bioseq (nsep)) || (! IS_Bioseq (psep))) return FALSE;
1180 
1181   nbsp = (BioseqPtr) nsep->data.ptrvalue;
1182   pbsp = (BioseqPtr) psep->data.ptrvalue;
1183   if (nbsp == NULL || pbsp == NULL) return FALSE;
1184 
1185   cds = NULL;
1186   WatchCursor ();
1187   Update ();
1188   if (use_this == NULL) {
1189     slp = PredictCodingRegion (nbsp, pbsp, code);
1190     if (slp == NULL) {
1191       ArrowCursor ();
1192       Update ();
1193       slp = AskForInterval (nsep, nbsp, pbsp);
1194     }
1195   } else {
1196     slp = use_this;
1197   }
1198   if (slp == NULL) return FALSE;
1199 
1200   mRnaName [0] = '\0';
1201   ttl = NULL;
1202   crp = CreateNewCdRgn (0, FALSE, code);
1203   if (crp != NULL) {
1204     if (pbsp->descr != NULL) {
1205       vnp = ValNodeFindNext (pbsp->descr, NULL, Seq_descr_title);
1206       if (vnp != NULL && vnp->data.ptrvalue != NULL) {
1207         vnpstr = (CharPtr) vnp->data.ptrvalue;
1208         CreateGeneAndProtFeats (nsep, psep, slp, crp, vnpstr, mRnaName, sizeof (mRnaName), &ttl);
1209         TrimSpacesAroundString (vnpstr);
1210         if (StringHasNoText (vnpstr)) {
1211           ValNodeExtract (&(pbsp->descr), Seq_descr_title);
1212         }
1213       }
1214     }
1215     if (makeMRNA) {
1216       rrp = RnaRefNew ();
1217       if (rrp != NULL) {
1218         rrp->type = 2;
1219         if (! StringHasNoText (mRnaName)) {
1220           rrp->ext.choice = 1;
1221           rrp->ext.value.ptrvalue = StringSave (mRnaName);
1222         }
1223         rna = CreateNewFeature (nsep, NULL, SEQFEAT_RNA, NULL);
1224         if (rna != NULL) {
1225           rna->data.value.ptrvalue = (Pointer) rrp;
1226           rna->location = SeqLocFree (rna->location);
1227           rna->location = AsnIoMemCopy ((Pointer) slp,
1228                                         (AsnReadFunc) SeqLocAsnRead,
1229                                         (AsnWriteFunc) SeqLocAsnWrite);
1230         }
1231       }
1232     }
1233     cds = CreateNewFeature (nsep, NULL, SEQFEAT_CDREGION, NULL);
1234     if (cds != NULL) {
1235       cds->data.value.ptrvalue = (Pointer) crp;
1236       cds->location = SeqLocFree (cds->location);
1237       cds->location = slp;
1238       slp = NULL;
1239       CheckSeqLocForPartial (cds->location, &partial5, &partial3);
1240       cds->partial |= partial5 | partial3;
1241       SetSeqFeatProduct (cds, pbsp);
1242       if (! StringHasNoText (ttl)) {
1243         cds->comment = ttl;
1244       }
1245     }
1246   }
1247 
1248   SeqLocFree (slp);
1249   return TRUE;
1250 }
1251 
1252 typedef struct fa2htgsform {
1253   FORM_MESSAGE_BLOCK
1254 
1255   SeqSubmitPtr       ssp;
1256   SeqEntryPtr        sep;
1257 
1258   GrouP              templateblock;
1259   GrouP              fastablock;
1260   GrouP              orderblock;
1261   GrouP              controlblock;
1262   GrouP              contigtype;
1263 
1264   DialoG             contigorder;
1265   EnumFieldAssocPtr  alists [1];
1266   GrouP              htgsphase;
1267   ButtoN             draft;
1268   ButtoN             fulltop;
1269   ButtoN             activefin;
1270   TexT               orgname;
1271   TexT               seqname;
1272   ButtoN             update;
1273   TexT               accession;
1274   TexT               knownlength;
1275   TexT               gaplength;
1276   TexT               remark;
1277   TexT               clone;
1278   TexT               strain;
1279   TexT               cultivar;
1280   TexT               chromosome;
1281   TexT               title;
1282   DialoG             secondaries;
1283 
1284   SeqEntryPtr        seplist;
1285 
1286   ButtoN             okBtn;
1287   BtnActnProc        finish;
1288   BtnActnProc        cancel;
1289   Boolean            readPhrap;
1290   Boolean            buildContig;
1291 
1292 } Fa2htgsForm, PNTR Fa2htgsFormPtr;
1293 
1294 /*------------- MakeAc2GBSeqId() -----------------------*/
1295 /***************************************************************
1296 *   MakeAc2GBSeqId:
1297 *   -- return NULL if acnum == null
1298 *                                             Hsiu-Chuan 4-18-97
1299 ****************************************************************/
1300 static SeqIdPtr  SqnMakeAc2GBSeqId(CharPtr accession)
1301 {
1302    TextSeqIdPtr tsip;
1303    SeqIdPtr sip;
1304 
1305    if (accession == NULL || *accession == '\0')
1306       return NULL;
1307 
1308    sip = ValNodeNew(NULL);
1309    sip->choice = SEQID_GENBANK;
1310    tsip = TextSeqIdNew();
1311    sip->data.ptrvalue = tsip;
1312    tsip->accession = StringSave(accession);
1313 
1314    return sip;
1315 
1316 } /* MakeAc2GBSeqId */
1317 
1318 /*----------- AddExtraAc2Entry() ----------------------------*/
1319 /***************************************************************
1320 *   AddExtraAc2Entry:
1321 *                                             Hsiu-Chuan 4-11-97, modified by JK
1322 ****************************************************************/
1323 static void SqnAddDraft2Entry (SeqEntryPtr entry, CharPtr keyword)
1324 
1325 {
1326    BioseqPtr  bsp;
1327    ValNodePtr vnp;
1328    GBBlockPtr gbp;
1329 
1330    if (entry == NULL) return;
1331 
1332    bsp = (BioseqPtr)(entry->data.ptrvalue);
1333 
1334    for (gbp= NULL, vnp = bsp->descr; vnp != NULL; vnp = vnp->next)
1335    {
1336        if (vnp->choice == Seq_descr_genbank)
1337        {
1338           gbp = vnp->data.ptrvalue;
1339           break;
1340        }
1341    }
1342 
1343    if (gbp == NULL)
1344    {
1345       vnp = (ValNodePtr) NewDescrOnSeqEntry (entry, Seq_descr_genbank);
1346       gbp = GBBlockNew();
1347       vnp->data.ptrvalue = (Pointer)gbp;
1348    }
1349 
1350    if (gbp != NULL) {
1351       ValNodeCopyStr (&gbp->keywords, 0, keyword);
1352    }
1353 }
1354 
1355 static Boolean SqnAddExtraAc2Entry (SeqEntryPtr entry , ValNodePtr extra_accs )
1356 {
1357    BioseqPtr  bsp;
1358    ValNodePtr vnp;
1359    GBBlockPtr gbp;
1360    Char       acnum[17];
1361    CharPtr    p;
1362    Int4       i, j;
1363    SeqHistPtr shp;
1364    SeqIdPtr   sip;
1365    ValNodePtr tmp;
1366 
1367    if ((entry == NULL) || (extra_accs == NULL))
1368       return FALSE;
1369 
1370    bsp = (BioseqPtr)(entry->data.ptrvalue);
1371 
1372    for (gbp= NULL, vnp = bsp->descr; vnp != NULL; vnp = vnp->next)
1373    {
1374        if (vnp->choice == Seq_descr_genbank)
1375        {
1376           gbp = vnp->data.ptrvalue;
1377           break;
1378        }
1379    }
1380 
1381    shp = bsp->hist; 
1382 
1383    if (gbp == NULL)
1384    {
1385       vnp = (ValNodePtr) NewDescrOnSeqEntry (entry, Seq_descr_genbank);
1386       gbp = GBBlockNew();
1387       vnp->data.ptrvalue = (Pointer)gbp;
1388    }
1389    
1390    for (tmp = extra_accs; tmp != NULL; tmp = tmp->next)
1391    {
1392        p = (CharPtr) tmp->data.ptrvalue;
1393        if (p == NULL) continue;
1394        for (i = 0; isalnum((Int4)(*p)) && *p != '\0'; ++p, ++i)
1395            acnum[i] = *p;
1396        acnum[i] = '\0'; 
1397                /* check one_letter+5digits or two_letter+6digits */
1398        if (i == 6 || i == 8)
1399        {
1400           if (!isalpha((Int4)(acnum[0])) || (!(isdigit((Int4)(acnum[1])) && i == 6) &&
1401               !(isalpha((Int4)(acnum[1])) && i == 8)))
1402           {
1403              ErrPostEx(SEV_ERROR,0,0,
1404  "Invalid accession (one_letter+5digits or two_letter+6digits): %s",
1405                                                            acnum);
1406              return FALSE;
1407           }
1408 
1409           for (j = 2; j < i; ++j)
1410           {
1411               if (!(isdigit((Int4)(acnum[j]))))
1412               {
1413                  ErrPostEx(SEV_ERROR,0,0,
1414  "Invalid accession (one_letter+5digits or two_letter+6digits): %s",
1415                                                            acnum);
1416                  return FALSE;
1417               }
1418           }
1419 
1420           ValNodeCopyStr(&gbp->extra_accessions, 0, acnum);
1421           sip = SqnMakeAc2GBSeqId (acnum);
1422           if (shp == NULL)
1423           {
1424              shp = SeqHistNew();
1425              bsp->hist = shp;
1426           }
1427           ValNodeLink(&shp->replace_ids, sip);
1428        }
1429        else
1430        {
1431           ErrPostEx(SEV_ERROR,0,0,
1432  "Invalid accession (one_letter+5digits or two_letter+6digits): %s",
1433                                                            acnum);
1434           return FALSE;
1435        }
1436 
1437        while (!isalnum((Int4)(*p)) && *p != '\0')
1438            ++p;
1439    }
1440 
1441    return TRUE;
1442 
1443 } /* AddExtraAc2Entry */
1444 
1445 static void RescueSeqGraphs (BioseqPtr bsp, Int2 index, ValNodePtr PNTR vnpp)
1446 
1447 {
1448   SeqAnnotPtr   nextsap;
1449   SeqGraphPtr   nextsgp;
1450   Pointer PNTR  prevsap;
1451   Pointer PNTR  prevsgp;
1452   SeqAnnotPtr   sap;
1453   SeqGraphPtr   sgp;
1454 
1455   if (bsp == NULL || vnpp == NULL) return;
1456   sap = bsp->annot;
1457   prevsap = (Pointer PNTR) &(bsp->annot);
1458   while (sap != NULL) {
1459     nextsap = sap->next;
1460     if (sap->type == 3) {
1461       sgp = (SeqGraphPtr) sap->data;
1462       prevsgp = (Pointer PNTR) &(sap->data);
1463       while (sgp != NULL) {
1464         nextsgp = sgp->next;
1465         *(prevsgp) = sgp->next;
1466         sgp->next = NULL;
1467         ValNodeAddPointer (vnpp, index, (Pointer) sgp);
1468         sgp = nextsgp;
1469       }
1470     }
1471     if (sap->data == NULL) {
1472       *(prevsap) = sap->next;
1473       sap->next = NULL;
1474       SeqAnnotFree (sap);
1475     } else {
1476       prevsap = (Pointer PNTR) &(sap->next);
1477     }
1478     sap = nextsap;
1479   }
1480 }
1481 
1482 static SeqAnnotPtr NewSeqAnnotType3 (CharPtr name, SeqGraphPtr sgp)
1483 
1484 {
1485   SeqAnnotPtr  sap = NULL;
1486 
1487   if (sgp == NULL) return NULL;
1488   sap = SeqAnnotNew ();
1489   if (sap == NULL) return NULL;
1490 
1491   if (! StringHasNoText (name)) {
1492     SeqDescrAddPointer (&(sap->desc), Annot_descr_name, StringSave (name));
1493   }
1494   sap->type = 3;
1495   sap->data = (Pointer) sgp;
1496 
1497   return sap;
1498 }
1499 
1500 static void OffsetAndLinkSeqGraph (BioseqPtr bsp, SeqGraphPtr sgp, Int2 index)
1501 
1502 {
1503   DeltaSeqPtr  dsp;
1504   SeqGraphPtr  lastsgp;
1505   Int4         len;
1506   SeqLitPtr    litp;
1507   SeqAnnotPtr  sap;
1508   SeqIntPtr    sintp;
1509   SeqLocPtr    slp;
1510 
1511   if (bsp == NULL || sgp == NULL || index < 1) return;
1512   len = 0;
1513   if (bsp->repr == Seq_repr_delta && bsp->seq_ext_type == 4) {
1514     for (dsp = (DeltaSeqPtr) (bsp->seq_ext);
1515          dsp != NULL && index > 1; dsp = dsp->next, index--) {
1516       if (dsp->choice == 1) {
1517         len += SeqLocLen ((SeqLocPtr) dsp->data.ptrvalue);
1518       } else if (dsp->choice == 2) {
1519         litp = (SeqLitPtr) dsp->data.ptrvalue;
1520         if (litp != NULL) {
1521           len += litp->length;
1522         }
1523       }
1524     }
1525   }
1526   slp = sgp->loc;
1527   if (slp != NULL && slp->choice == SEQLOC_INT) {
1528     sintp = (SeqIntPtr) slp->data.ptrvalue;
1529     if (sintp != NULL) {
1530       sintp->from += len;
1531       sintp->to += len;
1532       sintp->id = SeqIdFree (sintp->id);
1533       sintp->id = SeqIdDup (bsp->id);
1534     }
1535   }
1536   for (sap = bsp->annot; sap != NULL; sap = sap->next) {
1537     if (sap->type == 3) {
1538       for (lastsgp = sap->data; lastsgp->next != NULL; lastsgp = lastsgp->next) {
1539         continue;
1540       }
1541       lastsgp->next = sgp;
1542       break;
1543     }
1544   }
1545   if (sap == NULL) {
1546     if (bsp->annot != NULL) {
1547       for (sap = bsp->annot; sap->next != NULL; sap = sap->next) {
1548         continue;
1549       }
1550       sap->next = NewSeqAnnotType3 ("Graphs", sgp);
1551     } else {
1552       bsp->annot = NewSeqAnnotType3 ("Graphs", sgp);
1553     }
1554   }
1555 }
1556 
1557 static CharPtr phrapBoilerPlate = "Sequence Quality Assessment:~ \
1558 This entry has been annotated with sequence quality~ \
1559 estimates computed by the Phrap assembly program.~ \
1560 All manually edited bases have been reduced to quality zero.~ \
1561 Quality levels above 40 are expected to have less than ~ \
1562 1 error in 10,000 bp.~ \
1563 Base-by-base quality values are not generally visible from the~ \
1564 GenBank flat file format but are available as part~ \
1565 of this entry's ASN.1 file.~----------------------~";
1566 
1567 static void ProcessFa2htgs (Fa2htgsFormPtr ffp, SeqSubmitPtr ssp)
1568 
1569 {
1570   SeqEntryPtr  sep, oldsep, the_entry, nextsep;
1571   NCBISubPtr nsp;
1572   Int2 htgs_phase = -1;
1573   Uint1 tech;
1574   CharPtr seqname = NULL, accession = NULL, orgname = NULL;
1575   CharPtr clone = NULL, strain = NULL, cultivar = NULL, chromosome = NULL;
1576   CharPtr remark = NULL, title = NULL, seqbuf = NULL;
1577   Int4 length = 0, cumlength = 0, gaplen;
1578   BioseqPtr bsp;
1579   BioseqSetPtr bssp;
1580   SeqLitPtr slp;
1581   ValNodePtr vnp, PNTR prevpnt, next, extra_accs;
1582   Boolean lastwasraw, draft, fulltop, activefin, usedelta = FALSE;
1583   Char str [64];
1584   long int val;
1585   Int2 index = 0;
1586   ValNodePtr rescuedsgps = NULL;
1587   ValNodePtr seqlitlist = NULL;
1588   IntFuzzPtr ifp;
1589   ObjectIdPtr    oip;
1590   UserFieldPtr   ufp;
1591   UserObjectPtr  uop;
1592   DatePtr dp;
1593 
1594   if (ffp == NULL || ssp == NULL) return;
1595 
1596   htgs_phase = GetValue (ffp->htgsphase) - 1;
1597   orgname = SaveStringFromText (ffp->orgname);
1598   seqname = SaveStringFromText (ffp->seqname);
1599   if (GetStatus (ffp->update)) {
1600     accession = SaveStringFromText (ffp->accession);
1601   }
1602   clone = SaveStringFromText (ffp->clone);
1603   strain = SaveStringFromText (ffp->strain);
1604   cultivar = SaveStringFromText (ffp->cultivar);
1605   chromosome = SaveStringFromText (ffp->chromosome);
1606   remark = SaveStringFromText (ffp->remark);
1607   title = SaveStringFromText (ffp->title);
1608   extra_accs = DialogToPointer (ffp->secondaries);
1609   draft = GetStatus (ffp->draft);
1610   fulltop = GetStatus (ffp->fulltop);
1611   activefin = GetStatus (ffp->activefin);
1612 
1613   length = 0;
1614 /* may need to really calculate length */
1615   GetTitle (ffp->knownlength, str, sizeof (str));
1616   if (! StringHasNoText (str)) {
1617     if (sscanf (str, "%ld", &val) == 1 && val > 0) {
1618       length = (Int4) val;
1619     }
1620   }
1621 
1622   gaplen = 0;
1623 /* now usually filling in with gaps of 100 bases */
1624   GetTitle (ffp->gaplength, str, sizeof (str));
1625   if (! StringHasNoText (str)) {
1626     if (sscanf (str, "%ld", &val) == 1 && val > 0) {
1627       gaplen = (Int4) val;
1628     }
1629   }
1630 
1631 /* modified from fa2htgs */
1632    oldsep = (SeqEntryPtr)(ssp->data);  /* clear out template */
1633    ssp->data = NULL;
1634    MemFree(ssp->sub->tool);
1635    sprintf (str, "Sequin %s", SEQUIN_APPLICATION);
1636    ssp->sub->tool = StringSave (str);
1637    nsp = MemNew(sizeof(NCBISub));
1638    nsp->ssp = ssp;
1639    nsp->submittor_key = StringSave (genomeCenter);
1640    /*
1641    MemFree(ssp->sub->cit->descr);
1642    ssp->sub->cit->descr = remark;
1643    */
1644 
1645    cumlength = 0;
1646    index = 0;
1647 
1648    sep = ffp->seplist;
1649    if (sep != NULL && sep->next != NULL) {
1650      usedelta = TRUE;
1651    }
1652 
1653    if (ffp->buildContig) {
1654      ssp->data = (Pointer) ffp->seplist;
1655      the_entry = ffp->seplist;
1656      sep = the_entry;
1657 
1658      oip = ObjectIdNew ();
1659      oip->str = StringSave ("info");
1660      uop = UserObjectNew ();
1661      uop->type = oip;
1662      uop->_class = StringSave ("Genomes");
1663 
1664      oip = ObjectIdNew ();
1665      oip->id = 0;
1666      ufp = UserFieldNew ();
1667      ufp->choice = 2;
1668      ufp->data.intvalue = 0;
1669      ufp->label = oip;
1670 
1671      uop->data = ufp;
1672 
1673      if (IS_Bioseq (sep)) {
1674        bsp = (BioseqPtr) sep->data.ptrvalue;
1675        vnp = SeqDescrNew (NULL);
1676        vnp->choice = Seq_descr_user;
1677        vnp->data.ptrvalue = (Pointer) uop;
1678        vnp->next = bsp->descr;
1679        bsp->descr = vnp;
1680        cumlength = bsp->length;
1681      }
1682 
1683    }
1684    else if (htgs_phase < 3 || usedelta)
1685    {
1686       the_entry = AddDeltaSeqOnlyToSubmission (
1687                         nsp,
1688                         seqname,
1689                         NULL,
1690                         accession,
1691                         0,
1692                         MOLECULE_CLASS_DNA,
1693                         MOLECULE_TYPE_GENOMIC,
1694                         length,
1695                         TOPOLOGY_LINEAR,
1696                         STRANDEDNESS_DOUBLE);
1697 
1698       sep = ffp->seplist;
1699       lastwasraw = FALSE;
1700       while (sep != NULL)
1701       {
1702          nextsep = sep->next;
1703          sep->next = NULL;
1704          bsp = (BioseqPtr)(sep->data.ptrvalue);
1705          if (bsp->repr == Seq_repr_raw)
1706          {
1707             if (lastwasraw) {
1708                slp = AddFakeGapToDeltaSeq(nsp, the_entry, gaplen);
1709                ValNodeAddPointer (&seqlitlist, 0, (Pointer) slp);
1710                index++;
1711                cumlength += gaplen;
1712             }
1713             BioseqRawConvert(bsp, Seq_code_iupacna);
1714             seqbuf = BSMerge((ByteStorePtr)(bsp->seq_data), NULL);
1715             slp = AddLiteralToDeltaSeq(nsp, the_entry,
1716                bsp->length);
1717             AddBasesToLiteral(nsp, slp, seqbuf);
1718             MemFree(seqbuf);
1719             lastwasraw = TRUE;
1720             index++;
1721          }
1722          else
1723          {
1724             if (bsp->length < 0)
1725                bsp->length = 0;  /* -1 may be set */
1726             AddGapToDeltaSeq(nsp, the_entry,
1727                bsp->length);
1728             lastwasraw = FALSE;
1729             index++;
1730          }
1731          cumlength += bsp->length;
1732          RescueSeqGraphs (bsp, index, &rescuedsgps);
1733          SeqEntryFree(sep);
1734          sep = nextsep;
1735       }
1736    }
1737    else
1738    {
1739     the_entry = AddSeqOnlyToSubmission (
1740                         nsp,
1741                         seqname,
1742                         NULL,
1743                         accession,
1744                         0,
1745                         MOLECULE_CLASS_DNA,
1746                         MOLECULE_TYPE_GENOMIC,
1747                         length,
1748                         TOPOLOGY_LINEAR,
1749                         STRANDEDNESS_DOUBLE);
1750 
1751       sep = ffp->seplist;
1752       nextsep = sep->next;
1753       sep->next = NULL;
1754       bsp = (BioseqPtr)(sep->data.ptrvalue);
1755       if (bsp->repr == Seq_repr_raw)
1756       {
1757          BioseqRawConvert(bsp, Seq_code_iupacna);
1758          seqbuf = BSMerge((ByteStorePtr)(bsp->seq_data), NULL);
1759          AddBasesToBioseq(nsp, the_entry, seqbuf);
1760          MemFree(seqbuf);
1761          index++;
1762       }
1763       cumlength += bsp->length;
1764       RescueSeqGraphs (bsp, index, &rescuedsgps);
1765       SeqEntryFree(sep);
1766       if (nextsep != NULL) {
1767         ErrPostEx (SEV_ERROR ,0, 0, "Only the first contig was used for HTGS 3");
1768       }
1769       if (length > 0 && length != cumlength) {
1770         ErrPostEx (SEV_ERROR ,0, 0, "Length is exactly %ld, not %ld",
1771                    (long) cumlength, (long) length);
1772         length = cumlength;
1773       }
1774    }
1775 
1776     /* get data from template: pub, organism, and comment */
1777    if (IS_Bioseq(oldsep))
1778    {
1779       bsp = (BioseqPtr)(oldsep->data.ptrvalue);
1780       prevpnt = &(bsp->descr);
1781    }
1782    else
1783    {
1784       bssp = (BioseqSetPtr)(oldsep->data.ptrvalue);
1785       prevpnt = &(bssp->descr);
1786    }
1787 
1788    bsp = (BioseqPtr)(the_entry->data.ptrvalue);
1789    if (bsp != NULL) {
1790      bsp->length = MAX (cumlength, length);
1791    }
1792 
1793    for (vnp = *prevpnt; vnp != NULL; vnp = next)
1794    {
1795       next = vnp->next;
1796       if (vnp->choice == Seq_descr_pub)
1797       {
1798          *prevpnt = next;
1799          vnp->next = NULL;
1800          ValNodeLink(&(bsp->descr), vnp);
1801       }
1802       else
1803          prevpnt = &(vnp->next);
1804    }
1805    if (remark != NULL) {
1806      vnp = SeqDescrNew (NULL);
1807      if (vnp != NULL) {
1808        vnp->choice = Seq_descr_comment;
1809        vnp->data.ptrvalue = remark;
1810        ValNodeLink(&(bsp->descr), vnp);
1811      }
1812    }
1813 
1814    SeqEntryFree(oldsep);
1815 
1816    AddOrganismToEntryNew(nsp, the_entry, orgname, NULL, NULL, NULL,
1817                          NULL, NULL, NULL, NULL);
1818 
1819    AddGenomeToEntry(nsp, the_entry, 1);
1820    if (clone != NULL)
1821       AddSubSourceToEntry(nsp, the_entry, 3, clone);
1822    if (chromosome != NULL)
1823        AddSubSourceToEntry(nsp, the_entry, 1, chromosome);
1824    if (strain != NULL)
1825       AddOrgModToEntry(nsp, the_entry, 2, strain);
1826    if (cultivar != NULL)
1827       AddOrgModToEntry(nsp, the_entry, ORGMOD_cultivar, cultivar);
1828    if (title != NULL)
1829       AddTitleToEntry(nsp, the_entry, title);
1830    if (ffp->readPhrap) {
1831       AddCommentToEntry(nsp, the_entry, phrapBoilerPlate);
1832    }
1833 
1834    if (extra_accs != NULL) {
1835       SqnAddExtraAc2Entry(the_entry, extra_accs);
1836    }
1837 
1838    if (draft) {
1839       SqnAddDraft2Entry(the_entry, "HTGS_DRAFT");
1840    }
1841    if (fulltop) {
1842       SqnAddDraft2Entry(the_entry, "HTGS_FULLTOP");
1843    }
1844    if (activefin) {
1845       SqnAddDraft2Entry(the_entry, "HTGS_ACTIVEFIN");
1846    }
1847 
1848    AddBiomolToEntry(nsp, the_entry, 1);
1849    if (ffp->buildContig) {
1850    } else {
1851      switch (htgs_phase) {
1852        case 0 :
1853          tech = MI_TECH_htgs_0;
1854          break;
1855        case 1 :
1856          tech = MI_TECH_htgs_1;
1857          break;
1858        case 2 :
1859          tech = MI_TECH_htgs_2;
1860          break;
1861        case 3 :
1862          tech = MI_TECH_htgs_3;
1863          break;
1864        default :
1865          tech = MI_TECH_htgs_3;
1866          break;
1867      }
1868      AddTechToEntry(nsp, the_entry, tech);
1869    }
1870    vnp = NewDescrOnSeqEntry (the_entry, Seq_descr_create_date);
1871    if (vnp != NULL) {
1872      dp = DateCurr ();
1873      vnp->data.ptrvalue = (Pointer) dp;
1874    }
1875 
1876    if (bsp != NULL) {
1877      for (vnp = rescuedsgps; vnp != NULL; vnp = vnp->next) {
1878        OffsetAndLinkSeqGraph (bsp, (SeqGraphPtr) vnp->data.ptrvalue, (Int2) vnp->choice);
1879        vnp->data.ptrvalue = NULL;
1880      }
1881    }
1882    rescuedsgps = ValNodeFreeData (rescuedsgps);
1883 
1884    for (vnp = seqlitlist; vnp != NULL; vnp = vnp->next) {
1885      slp = (SeqLitPtr) vnp->data.ptrvalue;
1886      if (slp != NULL) {
1887        ifp = IntFuzzNew();
1888        ifp->choice = 4;    /* lim - unk*/
1889        slp->fuzz = ifp;
1890      }
1891    }
1892    seqlitlist = ValNodeFree (seqlitlist);
1893 
1894    MemFree (nsp);
1895 
1896 }
1897 
1898 static Pointer Fa2htgsToSeqSubmitPtr (ForM f)
1899 
1900 {
1901   Fa2htgsFormPtr  ffp;
1902   SeqSubmitPtr    ssp;
1903 
1904   ffp = (Fa2htgsFormPtr) GetObjectExtra (f);
1905   if (ffp == NULL) return NULL;
1906   ProcessFa2htgs (ffp, ffp->ssp);
1907   ssp = ffp->ssp;
1908   ffp->ssp = NULL;
1909   ffp->sep = NULL;
1910   ffp->seplist = NULL;
1911   return (Pointer) ssp;
1912 }
1913 
1914 static void Fa2htgsFormMessage (ForM f, Int2 mssg)
1915 
1916 {
1917   Fa2htgsFormPtr  ffp;
1918 
1919   ffp = (Fa2htgsFormPtr) GetObjectExtra (f);
1920   if (ffp) {
1921     switch (mssg) {
1922       case VIB_MSG_CUT :
1923         StdCutTextProc (NULL);
1924         break;
1925       case VIB_MSG_COPY :
1926         StdCopyTextProc (NULL);
1927         break;
1928       case VIB_MSG_PASTE :
1929         StdPasteTextProc (NULL);
1930         break;
1931       case VIB_MSG_DELETE :
1932         StdDeleteTextProc (NULL);
1933         break;
1934       default :
1935         if (ffp->appmessage != NULL) {
1936           ffp->appmessage (f, mssg);
1937         }
1938         break;
1939     }
1940   }
1941 }
1942 
1943 #ifndef WIN_MAC
1944 static void CreateFa2htgsFormMenus (WindoW w)
1945 
1946 {
1947   BaseFormPtr  bfp;
1948   MenU         m;
1949 
1950   bfp = (BaseFormPtr) GetObjectExtra (w);
1951   if (bfp != NULL) {
1952     m = PulldownMenu (w, "File");
1953     AddAboutAndHelpMenuItems (m);
1954     FormCommandItem (m, "Quit", bfp, VIB_MSG_QUIT);
1955     m = PulldownMenu (w, "Edit");
1956     FormCommandItem (m, CUT_MENU_ITEM, bfp, VIB_MSG_CUT);
1957     FormCommandItem (m, COPY_MENU_ITEM, bfp, VIB_MSG_COPY);
1958     FormCommandItem (m, PASTE_MENU_ITEM, bfp, VIB_MSG_PASTE);
1959     FormCommandItem (m, CLEAR_MENU_ITEM, bfp, VIB_MSG_DELETE);
1960   }
1961 }
1962 #endif
1963 
1964 static void FillInFa2htgsFields (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
1965 
1966 {
1967   BioseqPtr       bsp;
1968   BioseqSetPtr    bssp;
1969   Fa2htgsFormPtr  ffp;
1970   ValNodePtr      sdp = NULL;
1971 
1972   if (sep == NULL || sep->data.ptrvalue == NULL) return;
1973   ffp = (Fa2htgsFormPtr) mydata;
1974   if (ffp == NULL) return;
1975   if (IS_Bioseq (sep)) {
1976     bsp = (BioseqPtr) sep->data.ptrvalue;
1977     sdp = bsp->descr;
1978   } else if (IS_Bioseq_set (sep)) {
1979     bssp = (BioseqSetPtr) sep->data.ptrvalue;
1980     sdp = bssp->descr;
1981   } else return;
1982   while (sdp != NULL) {
1983     if (sdp->choice == Seq_descr_comment) {
1984       SetTitle (ffp->remark, (CharPtr) sdp->data.ptrvalue);
1985     }
1986     sdp = sdp->next;
1987   }
1988 }
1989 
1990 static void ReadTemplate (ButtoN b)
1991 
1992 {
1993   AsnIoPtr        aip;
1994   Fa2htgsFormPtr  ffp;
1995   Char            path [PATH_MAX];
1996   SeqEntryPtr     sep;
1997   SeqSubmitPtr    ssp;
1998   Char            str [128];
1999 
2000   ffp = (Fa2htgsFormPtr) GetObjectExtra (b);
2001   if (ffp == NULL) return;
2002   if (GetInputFileName (path, sizeof (path), "", "TEXT")) {
2003     ffp->ssp = SeqSubmitFree (ffp->ssp);
2004     aip = AsnIoOpen (path, "r");
2005     if (aip != NULL) {
2006       ffp->ssp = SeqSubmitAsnRead (aip, NULL);
2007     }
2008     AsnIoClose (aip);
2009   }
2010   if (ffp->ssp != NULL) {
2011     SafeShow (ffp->fastablock);
2012     SafeDisable (b);
2013     ssp = ffp->ssp;
2014     if (ssp->datatype == 1) {
2015       sep = (SeqEntryPtr) ssp->data;
2016       if (sep != NULL) {
2017         SeqEntryToGeneticCode (sep, NULL, str, sizeof (str));
2018         SetTitle (ffp->orgname, str);
2019         SeqEntryExplore (sep, (Pointer) ffp, FillInFa2htgsFields);
2020       }
2021     }
2022   }
2023 }
2024 
2025 static Boolean Fa2htgsFormOkay (Fa2htgsFormPtr ffp)
2026 
2027 {
2028   if (ffp == NULL) return FALSE;
2029   if (ffp->ssp == NULL) return FALSE;
2030   if (ffp->seplist == NULL) return FALSE;
2031   if (GetValue (ffp->htgsphase) == 0 && (! ffp->buildContig)) return FALSE;
2032   if (TextHasNoText (ffp->orgname)) return FALSE;
2033   if (TextHasNoText (ffp->seqname)) return FALSE;
2034   return TRUE;
2035 }
2036 
2037 static void ReadFastaHtgsFile (ButtoN b)
2038 
2039 {
2040   Fa2htgsFormPtr  ffp;
2041   FILE            *fp;
2042   SeqEntryPtr     head;
2043   Char            path [PATH_MAX];
2044   SeqEntryPtr     sep;
2045   CharPtr         ttl;
2046 
2047   ffp = (Fa2htgsFormPtr) GetObjectExtra (b);
2048   if (ffp == NULL) return;
2049   if (! GetInputFileName (path, sizeof (path), "", "TEXT")) return;
2050   if (! StringHasNoText (path)) {
2051     fp = FileOpen (path, "r");
2052     if (fp != NULL) {
2053       head = NULL;
2054       sep = FastaToSeqEntry (fp, TRUE);
2055       while (sep != NULL) {
2056         ValNodeLink (&head, sep);
2057         sep = FastaToSeqEntry (fp, TRUE);
2058       }
2059       if (head != NULL) {
2060         ttl = SeqEntryGetTitle (head);
2061         SetTitle (ffp->title, ttl);
2062       }
2063       ffp->seplist = head;
2064     }
2065     FileClose (fp);
2066     if (ffp->seplist != NULL) {
2067       SafeShow (ffp->controlblock);
2068       SafeDisable (b);
2069       if (TextHasNoText (ffp->orgname)) {
2070         Select (ffp->orgname);
2071       } else {
2072         Select (ffp->seqname);
2073       }
2074       if (Fa2htgsFormOkay (ffp)) {
2075         SafeEnable (ffp->okBtn);
2076       } else {
2077         SafeDisable (ffp->okBtn);
2078       }
2079     }
2080   }
2081 }
2082 
2083 static EnumFieldAssocPtr MakePhrapAlists (SeqEntryPtr head)
2084 
2085 {
2086   EnumFieldAssocPtr  alist = NULL;
2087   BioseqPtr          bsp;
2088   Int2               count;
2089   Int2               j;
2090   SeqEntryPtr        sep;
2091   SeqIdPtr           sip;
2092   Char               str [128];
2093 
2094   if (head == NULL) return NULL;
2095   count = ValNodeLen (head);
2096   alist = MemNew (sizeof (EnumFieldAssoc) * (size_t) (count + 4));
2097   if (alist == NULL) return NULL;
2098 
2099   j = 0;
2100   alist [j].name = StringSave ("                              ");
2101   alist [j].value = (UIEnum) 0;
2102   for (j = 1, sep = head; j <= count && sep != NULL; j++, sep = sep->next) {
2103     if (sep != NULL && sep->choice == 1 && sep->data.ptrvalue != NULL) {
2104       bsp = (BioseqPtr) sep->data.ptrvalue;
2105       sip = SeqIdFindWorst (bsp->id);
2106       SeqIdWrite (sip, str, PRINTID_REPORT, sizeof (str));
2107       str [30] = '\0';
2108       alist [j].name = StringSave (str);
2109       alist [j].value = (UIEnum) j;
2110     }
2111   }
2112   j = count + 1;
2113   alist [j].name = NULL;
2114   alist [j].value = (UIEnum) 0;
2115 
2116 
2117   return alist;
2118 }
2119 
2120 static void ReadAPhrapFile (ButtoN b)
2121 
2122 {
2123   PopuP           control;
2124   Int2            count;
2125   Fa2htgsFormPtr  ffp;
2126   FILE            *fp;
2127   SeqEntryPtr     head;
2128   Int2            i;
2129   Char            path [PATH_MAX];
2130   RecT            r;
2131   TagListPtr      tlp;
2132 
2133   ffp = (Fa2htgsFormPtr) GetObjectExtra (b);
2134   if (ffp == NULL) return;
2135   if (! GetInputFileName (path, sizeof (path), "", "TEXT")) return;
2136   if (! StringHasNoText (path)) {
2137     WatchCursor ();
2138     fp = FileOpen (path, "r");
2139     if (fp != NULL) {
2140       head = ReadPhrapFile (fp);
2141       ffp->seplist = head;
2142     }
2143     FileClose (fp);
2144     tlp = (TagListPtr) GetObjectExtra (ffp->contigorder);
2145     if (tlp != NULL) {
2146       ffp->alists [0] = MakePhrapAlists (ffp->seplist);
2147       tlp->alists = ffp->alists;
2148       for (i = 0; i < tlp->rows; i++) {
2149         control = (PopuP) tlp->control [i * MAX_TAGLIST_COLS + 0];
2150         if (control != NULL) {
2151           GetPosition (control, &r);
2152           Reset (control);
2153           InitEnumPopup (control, ffp->alists [0], NULL);
2154           SetEnumPopup (control, ffp->alists [0], 0);
2155           SetPosition (control, &r);
2156         }
2157       }
2158       count = ValNodeLen (ffp->seplist);
2159       for (i = 0; i < count; i++) {
2160         ValNodeCopyStr (&(tlp->vnp), 0, "0");
2161       }
2162       tlp->max = MAX ((Int2) 0, (Int2) (count - tlp->rows));
2163       CorrectBarMax (tlp->bar, tlp->max);
2164       CorrectBarPage (tlp->bar, tlp->rows - 1, tlp->rows - 1);
2165     }
2166     SafeShow (ffp->orderblock);
2167     SafeDisable (b);
2168     ArrowCursor ();
2169   }
2170 }
2171 
2172 static void PhrapOrderChosen (ButtoN b)
2173 
2174 {
2175   SeqEntryPtr     PNTR collision;
2176   Int2            count;
2177   Fa2htgsFormPtr  ffp;
2178   Int2            i;
2179   Int2            j;
2180   SeqEntryPtr     lastsep;
2181   SeqEntryPtr     nextsep;
2182   Boolean         okay;
2183   SeqEntryPtr     PNTR order;
2184   SeqEntryPtr     sep;
2185   CharPtr         str;
2186   TagListPtr      tlp;
2187   int             val;
2188   ValNodePtr      vnp;
2189   /*
2190   Char            contigs [256];
2191   Char            tmp [256];
2192   BioseqPtr       bsp;
2193   SeqIdPtr        sip;
2194   Boolean         notfirst;
2195   */
2196 
2197   ffp = (Fa2htgsFormPtr) GetObjectExtra (b);
2198   if (ffp == NULL) return;
2199   tlp = (TagListPtr) GetObjectExtra (ffp->contigorder);
2200   if (tlp == NULL) return;
2201   count = ValNodeLen (tlp->vnp);
2202   order = MemNew (sizeof (SeqEntryPtr) * (count + 1));
2203   if (order == NULL) return;
2204   collision = MemNew (sizeof (SeqEntryPtr) * (count + 1));
2205   if (collision == NULL) return;
2206 
2207   okay = TRUE;
2208   for (i = 0, vnp = tlp->vnp; i < count && vnp != NULL; i++, vnp = vnp->next) {
2209     str = ExtractTagListColumn ((CharPtr) vnp->data.ptrvalue, 0);
2210     if (str != NULL && sscanf (str, "%d", &val) == 1 && val > 0) {
2211       val--;
2212       for (j = 0, sep = ffp->seplist; j < (Int2) val && sep != NULL; j++, sep = sep->next) continue;
2213       if (sep != NULL) {
2214         if (collision [j] != NULL) {
2215           okay = FALSE;
2216         }
2217         collision [j] = sep;
2218         order [i] = sep;
2219       }
2220     }
2221     MemFree (str);
2222   }
2223   if (! okay) {
2224     Message (MSG_ERROR, "You must not select a contig more than once");
2225     MemFree (order);
2226     MemFree (collision);
2227     return;
2228   }
2229 
2230   okay = FALSE;
2231   for (i = 0; i < count; i++) {
2232     if (order [i] != NULL) {
2233       okay = TRUE;
2234     }
2235   }
2236   /* if no contigs selected, use all in order */
2237   if (! okay) {
2238     for (j = 0, sep = ffp->seplist; j < count && sep != NULL; j++, sep = sep->next) {
2239       order [j] = sep;
2240     }
2241     okay = TRUE;
2242   }
2243   /*
2244   if (! okay) {
2245     Message (MSG_ERROR, "You must select at least one contig");
2246     MemFree (order);
2247     MemFree (collision);
2248     return;
2249   }
2250   */
2251 
2252   /* use spreadsheet to reorder ffp->seplist, delete unwanted items */
2253 
2254   /*
2255   contigs [0] = '\0';
2256   notfirst = FALSE;
2257   for (i = 0; i < count; i++) {
2258     if (order [i] != NULL) {
2259       sep = order [i];
2260       bsp = (BioseqPtr) sep->data.ptrvalue;
2261       sip = SeqIdFindWorst (bsp->id);
2262       SeqIdWrite (sip, tmp, PRINTID_REPORT, sizeof (tmp));
2263       if (notfirst) {
2264         StringCat (contigs, " ");
2265       }
2266       StringCat (contigs, tmp);
2267       notfirst = TRUE;
2268     }
2269   }
2270   ffp->seplist = SetPhrapContigOrder (ffp->seplist, contigs);
2271   */
2272 
2273   for (i = 0; i < count; i++) {
2274     if (order [i] != NULL) {
2275       sep = ffp->seplist;
2276       lastsep = NULL;
2277       while (sep != NULL && sep != order [i]) {
2278         lastsep = sep;
2279         sep = sep->next;
2280       }
2281       if (sep != NULL) {
2282         if (lastsep != NULL) {
2283           lastsep->next = sep->next;
2284           sep->next = NULL;
2285         } else {
2286           ffp->seplist = sep->next;
2287           sep->next = NULL;
2288         }
2289       }
2290     }
2291   }
2292   sep = ffp->seplist;
2293   while (sep != NULL) {
2294     nextsep = sep->next;
2295     sep->next = NULL;
2296     SeqEntryFree (sep);
2297     sep = nextsep;
2298   }
2299   ffp->seplist = NULL;
2300 
2301   for (i = 0; i < count; i++) {
2302     if (order [i] != NULL) {
2303       ValNodeLink (&(ffp->seplist), order [i]);
2304     }
2305   }
2306 
2307   MemFree (order);
2308   MemFree (collision);
2309   SafeDisable (b);
2310   SafeHide (ffp->orderblock);
2311   SafeShow (ffp->controlblock);
2312   if (TextHasNoText (ffp->orgname)) {
2313     Select (ffp->orgname);
2314   } else {
2315     Select (ffp->seqname);
2316   }
2317   if (Fa2htgsFormOkay (ffp)) {
2318     SafeEnable (ffp->okBtn);
2319   } else {
2320     SafeDisable (ffp->okBtn);
2321   }
2322 }
2323 
2324 static void ReadContigFile (ButtoN b)
2325 
2326 {
2327   BioseqPtr       bsp;
2328   Fa2htgsFormPtr  ffp;
2329   FILE            *fp;
2330   Boolean         onMaster;
2331   Char            path [PATH_MAX];
2332   SeqEntryPtr     sep = NULL;
2333 
2334   ffp = (Fa2htgsFormPtr) GetObjectExtra (b);
2335   if (ffp == NULL) return;
2336   if (! GetInputFileName (path, sizeof (path), "", "TEXT")) return;
2337   if (! StringHasNoText (path)) {
2338     WatchCursor ();
2339     fp = FileOpen (path, "r");
2340     if (fp != NULL) {
2341       onMaster = (Boolean) (GetValue (ffp->contigtype) == 2);
2342       sep = ReadContigList (fp, onMaster);
2343       if (sep != NULL && sep->choice == 1) {
2344         ffp->seplist = sep;
2345         bsp = (BioseqPtr) sep->data.ptrvalue;
2346         SeqMgrSeqEntry (SM_BIOSEQ, (Pointer) bsp, sep);
2347       }
2348     }
2349     FileClose (fp);
2350     ArrowCursor ();
2351     if (ffp->seplist != NULL) {
2352       SafeShow (ffp->controlblock);
2353       SafeDisable (b);
2354       SafeDisable (ffp->contigtype);
2355       if (TextHasNoText (ffp->orgname)) {
2356         Select (ffp->orgname);
2357       } else {
2358         Select (ffp->seqname);
2359       }
2360       if (Fa2htgsFormOkay (ffp)) {
2361         SafeEnable (ffp->okBtn);
2362       } else {
2363         SafeDisable (ffp->okBtn);
2364       }
2365     }
2366   }
2367 }
2368 
2369 static void AcceptFa2htgs (ButtoN b)
2370 
2371 {
2372   Fa2htgsFormPtr  ffp;
2373 
2374   ffp = (Fa2htgsFormPtr) GetObjectExtra (b);
2375   if (ffp == NULL) return;
2376   Hide (ffp->form);
2377   Update ();
2378   if (ffp->finish != NULL) {
2379     ffp->finish (b);
2380   }
2381   SeqSubmitFree (ffp->ssp);
2382   SeqEntryFree (ffp->sep);
2383   Remove (ffp->form);
2384 }
2385 
2386 static void CancelFa2htgs (ButtoN b)
2387 
2388 {
2389   Fa2htgsFormPtr  ffp;
2390 
2391   ffp = (Fa2htgsFormPtr) GetObjectExtra (b);
2392   if (ffp == NULL) return;
2393   Hide (ffp->form);
2394   Update ();
2395   if (ffp->cancel != NULL) {
2396     ffp->cancel (b);
2397   }
2398   SeqSubmitFree (ffp->ssp);
2399   SeqEntryFree (ffp->sep);
2400   Remove (ffp->form);
2401 }
2402 
2403 static void SetFa2htgsAcceptBtn (Handle control)
2404 
2405 {
2406   Fa2htgsFormPtr  ffp;
2407 
2408   ffp = (Fa2htgsFormPtr) GetObjectExtra (control);
2409   if (ffp == NULL) return;
2410   if (Fa2htgsFormOkay (ffp)) {
2411     SafeEnable (ffp->okBtn);
2412   } else {
2413     SafeDisable (ffp->okBtn);
2414   }
2415 }
2416 
2417 static void SetFa2htgsUpdate (ButtoN b)
2418 
2419 {
2420   Fa2htgsFormPtr  ffp;
2421 
2422   ffp = (Fa2htgsFormPtr) GetObjectExtra (b);
2423   if (ffp == NULL) return;
2424   if (GetStatus (b)) {
2425     SafeEnable (ffp->accession);
2426   } else {
2427     SafeDisable (ffp->accession);
2428   }
2429   SetFa2htgsAcceptBtn ((Handle) b);
2430 }
2431 
2432 static void CleanupGenomeCenterForm (GraphiC g, VoidPtr data)
2433 
2434 {
2435   Fa2htgsFormPtr  ffp;
2436   SeqEntryPtr     next;
2437   SeqEntryPtr     sep;
2438 
2439   ffp = (Fa2htgsFormPtr) data;
2440   if (ffp != NULL) {
2441     sep = ffp->seplist;
2442     while (sep != NULL) {
2443       next = sep->next;
2444       sep->next = NULL;
2445       SeqEntryFree (sep);
2446       sep = next;
2447     }
2448     if (ffp->alists [0] != NULL) {
2449       FreeEnumFieldAlist (ffp->alists [0]);
2450     }
2451   }
2452   StdCleanupFormProc (g, data);
2453 }
2454 
2455 static CharPtr secaccstrings [] = {"Secondary", "Accessions", NULL};
2456 
2457 static Uint2 contigorder_types [] = {
2458   TAGLIST_POPUP
2459 };
2460 
2461 static ENUM_ALIST(contigdefault_alist)
2462   {"                              ", 0},
2463 END_ENUM_ALIST
2464 
2465 static EnumFieldAssocPtr contigdefault_alists [] = {
2466   contigdefault_alist
2467 };
2468 
2469 extern DialoG CreateTagListDialogEx (GrouP h, Uint2 rows, Uint2 cols,
2470                                      Int2 spacing, Uint2Ptr types,
2471                                      Uint2Ptr textWidths, EnumFieldAssocPtr PNTR alists,
2472                                      Boolean useBar, Boolean noExtend,
2473                                      ToDialogFunc tofunc, FromDialogFunc fromfunc);
2474 
2475 extern ForM CreateGenomeCenterForm (Int2 left, Int2 top, CharPtr title,
2476                                     BtnActnProc finish,
2477                                     BtnActnProc cancel,
2478                                     Boolean readPhrap,
2479                                     Boolean buildContig,
2480                                     WndActnProc activateForm)
2481 
2482 {
2483   ButtoN             b;
2484   GrouP              c;
2485   Fa2htgsFormPtr     ffp;
2486   GrouP              g;
2487   GrouP              h;
2488   PrompT             ppt;
2489   GrouP              q;
2490   GrouP              sa;
2491   StdEditorProcsPtr  sepp;
2492   WindoW             w;
2493   Int2               wid;
2494   GrouP              x;
2495   GrouP              y;
2496 
2497   ffp = (Fa2htgsFormPtr) MemNew (sizeof (Fa2htgsForm));
2498   if (ffp == NULL) return NULL;
2499   ffp->finish = finish;
2500   ffp->cancel = cancel;
2501   ffp->readPhrap = readPhrap;
2502   ffp->buildContig = buildContig;
2503 
2504   w = FixedWindow (left, top, -10, -10, title, NULL);
2505   if (w == NULL) return NULL;
2506   SetObjectExtra (w, ffp, CleanupGenomeCenterForm);
2507 
2508   ffp->form = (ForM) w;
2509   ffp->toform = NULL;
2510   ffp->fromform = Fa2htgsToSeqSubmitPtr;
2511   ffp->formmessage = Fa2htgsFormMessage;
2512 
2513   ffp->ssp = NULL;
2514   ffp->sep = NULL;
2515   ffp->seplist = NULL;
2516   ffp->alists [0] = NULL;
2517 
2518 #ifndef WIN_MAC
2519   CreateFa2htgsFormMenus (w);
2520 #endif
2521 
2522   sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
2523   if (sepp != NULL) {
2524     ffp->appmessage = sepp->handleMessages;
2525   }
2526 
2527   SetGroupSpacing (w, 10, 10);
2528 
2529   h = HiddenGroup (w, -1, 0, NULL);
2530   SetGroupSpacing (h, 10, 10);
2531 
2532   ffp->templateblock = HiddenGroup (h, -1, 0, NULL);
2533   b = PushButton (ffp->templateblock, "Read Seq-submit Template", ReadTemplate);
2534   SetObjectExtra (b, ffp, NULL);
2535 
2536   ffp->fastablock = HiddenGroup (h, -1, 0, NULL);
2537   if (readPhrap) {
2538     b = PushButton (ffp->fastablock, "Read PHRAP File", ReadAPhrapFile);
2539   } else if (buildContig) {
2540     SetGroupSpacing (ffp->fastablock, 10, 10);
2541     y = HiddenGroup (ffp->fastablock, 1, 0, NULL);
2542     StaticPrompt (y, "Coordinates are on", 0, stdLineHeight, programFont, 'c');
2543     ffp->contigtype = HiddenGroup (y, 3, 0, NULL);
2544     RadioButton (ffp->contigtype, "Individual Accessions");
2545     RadioButton (ffp->contigtype, "Master Sequence");
2546     SetValue (ffp->contigtype, 1);
2547     b = PushButton (ffp->fastablock, "Read CONTIG Instructions", ReadContigFile);
2548     AlignObjects (ALIGN_CENTER, (HANDLE) y, (HANDLE) b, NULL);
2549   } else {
2550     b = PushButton (ffp->fastablock, "Read FASTA File", ReadFastaHtgsFile);
2551   }
2552   SetObjectExtra (b, ffp, NULL);
2553   Hide (ffp->fastablock);
2554 
2555   x = HiddenGroup (h, 0, 0, NULL);
2556 
2557   ffp->orderblock = HiddenGroup (x, -1, 0, NULL);
2558   SetGroupSpacing (ffp->orderblock, 5, 5);
2559   ppt = StaticPrompt (ffp->orderblock, "Enter contigs in desired order", 0, 0, programFont, 'c');
2560   ffp->contigorder = CreateTagListDialogEx (ffp->orderblock, 8, 1, 2,
2561                                             contigorder_types, NULL,
2562                                             contigdefault_alists,
2563                                             TRUE, TRUE, NULL, NULL);
2564   b = PushButton (ffp->orderblock, "Proceed", PhrapOrderChosen);
2565   SetObjectExtra (b, ffp, NULL);
2566   AlignObjects (ALIGN_CENTER, (HANDLE) ppt, (HANDLE) ffp->contigorder,
2567                 (HANDLE) b, NULL);
2568   Hide (ffp->orderblock);
2569 
2570   ffp->controlblock = HiddenGroup (x, -1, 0, NULL);
2571   g = HiddenGroup (ffp->controlblock, 2, 0, NULL);
2572 
2573   ffp->htgsphase = NULL;
2574   if (! buildContig) {
2575     StaticPrompt (g, "Phase", 0, stdLineHeight, programFont, 'l');
2576     ffp->htgsphase = HiddenGroup (g, 4, 0, (GrpActnProc) SetFa2htgsAcceptBtn);
2577     SetObjectExtra (ffp->htgsphase, ffp, NULL);
2578     RadioButton (ffp->htgsphase, "HTGS-0");
2579     RadioButton (ffp->htgsphase, "HTGS-1");
2580     RadioButton (ffp->htgsphase, "HTGS-2");
2581     RadioButton (ffp->htgsphase, "HTGS-3");
2582     StaticPrompt (g, "HTGS_", 0, stdLineHeight, programFont, 'l');
2583     q = HiddenGroup (g, 3, 0, NULL);
2584     ffp->draft = CheckBox (q, "Draft", NULL);
2585     ffp->fulltop = CheckBox (q, "Fulltop", NULL);
2586     ffp->activefin = CheckBox (q, "Activefin", NULL);
2587   }
2588 
2589   StaticPrompt (g, "Organism", 0, dialogTextHeight, programFont, 'l');
2590   ffp->orgname = DialogText (g, "", 10, (TxtActnProc) SetFa2htgsAcceptBtn);
2591   SetObjectExtra (ffp->orgname, ffp, NULL);
2592 
2593   StaticPrompt (g, "Sequence name", 0, dialogTextHeight, programFont, 'l');
2594   ffp->seqname = DialogText (g, "", 10, (TxtActnProc) SetFa2htgsAcceptBtn);
2595   SetObjectExtra (ffp->seqname, ffp, NULL);
2596 
2597   StaticPrompt (g, "Length", 0, dialogTextHeight, programFont, 'l');
2598   ffp->knownlength = DialogText (g, "", 10, NULL);
2599   SetObjectExtra (ffp->knownlength, ffp, NULL);
2600 
2601   StaticPrompt (g, "Gap Length", 0, dialogTextHeight, programFont, 'l');
2602   ffp->gaplength = DialogText (g, "100", 10, NULL);
2603   SetObjectExtra (ffp->gaplength, ffp, NULL);
2604 
2605   ffp->update = CheckBox (g, "Update", SetFa2htgsUpdate);
2606   SetObjectExtra (ffp->update, ffp, NULL);
2607   ffp->accession = DialogText (g, "", 10, (TxtActnProc) SetFa2htgsAcceptBtn);
2608   SetObjectExtra (ffp->accession, ffp, NULL);
2609   Disable (ffp->accession);
2610 
2611   StaticPrompt (g, "Chromosome", 0, dialogTextHeight, programFont, 'l');
2612   ffp->chromosome = DialogText (g, "", 10, (TxtActnProc) SetFa2htgsAcceptBtn);
2613   SetObjectExtra (ffp->chromosome, ffp, NULL);
2614 
2615   StaticPrompt (g, "Clone", 0, dialogTextHeight, programFont, 'l');
2616   ffp->clone = DialogText (g, "", 10, (TxtActnProc) SetFa2htgsAcceptBtn);
2617   SetObjectExtra (ffp->clone, ffp, NULL);
2618 
2619   StaticPrompt (g, "Strain", 0, dialogTextHeight, programFont, 'l');
2620   ffp->strain = DialogText (g, "", 10, (TxtActnProc) SetFa2htgsAcceptBtn);
2621   SetObjectExtra (ffp->strain, ffp, NULL);
2622 
2623   StaticPrompt (g, "Cultivar", 0, dialogTextHeight, programFont, 'l');
2624   ffp->cultivar = DialogText (g, "", 10, (TxtActnProc) SetFa2htgsAcceptBtn);
2625   SetObjectExtra (ffp->cultivar, ffp, NULL);
2626 
2627   wid = MaxStringWidths (secaccstrings) + 2;
2628   sa = MultiLinePrompt (g, "Secondary Accessions", wid, programFont);
2629   ffp->secondaries = CreateVisibleStringDialog (g, 3, -1, 15);
2630   AlignObjects (ALIGN_MIDDLE, (HANDLE) sa, (HANDLE) ffp->secondaries, NULL);
2631 
2632   q = HiddenGroup (ffp->controlblock, 1, 0, NULL);
2633 
2634   StaticPrompt (q, "Title", 0, 0, programFont, 'c');
2635   ffp->title = ScrollText (q, 20, 4, programFont, TRUE, (TxtActnProc) SetFa2htgsAcceptBtn);
2636   SetObjectExtra (ffp->title, ffp, NULL);
2637 
2638   StaticPrompt (q, "Remark", 0, 0, programFont, 'c');
2639   ffp->remark = ScrollText (q, 20, 4, programFont, TRUE, (TxtActnProc) SetFa2htgsAcceptBtn);
2640   SetObjectExtra (ffp->remark, ffp, NULL);
2641 
2642   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) q, NULL);
2643   Hide (ffp->controlblock);
2644 
2645   c = HiddenGroup (h, 2, 0, NULL);
2646   ffp->okBtn = DefaultButton (c, "Accept", AcceptFa2htgs);
2647   SetObjectExtra (ffp->okBtn, ffp, NULL);
2648   Disable (ffp->okBtn);
2649   b = PushButton (c, "Cancel", CancelFa2htgs);
2650   SetObjectExtra (b, ffp, NULL);
2651 
2652   AlignObjects (ALIGN_CENTER, (HANDLE) ffp->templateblock, (HANDLE) ffp->fastablock,
2653                 (HANDLE) ffp->orderblock, (HANDLE) ffp->controlblock, (HANDLE) c, NULL);
2654 
2655   RealizeWindow (w);
2656 
2657   if (activateForm != NULL) {
2658     SetActivate (w, activateForm);
2659   }
2660 
2661   Show (w);
2662   Select (w);
2663   Select (ffp->orgname);
2664 
2665   return (ForM) w;
2666 }
2667 
2668 typedef struct convcdsdata {
2669   FEATURE_FORM_BLOCK
2670 
2671   SeqEntryPtr    sep;
2672   TexT           geneName;
2673   TexT           protName;
2674   TexT           featcomment;
2675   ButtoN         retain;
2676   Uint2          subtype;
2677   Int2           errcount;
2678   Char           findThis [128];
2679   SeqLocPtr      slp;
2680   SeqEntryPtr    nsep;
2681   ObjMgrPtr      omp;
2682   ObjMgrTypePtr  omtp;
2683 } ConvCdsData, PNTR ConvCdsPtr;
2684 
2685 static Boolean CollectCDSAncestorGatherFunc (GatherContextPtr gcp)
2686 
2687 {
2688   BioseqPtr      bsp;
2689   ConvCdsPtr     ccp;
2690   Boolean        noLeft;
2691   Boolean        noRight;
2692   ObjMgrTypePtr  omtp;
2693   SeqEntryPtr    sep;
2694   SeqFeatPtr     sfp;
2695   SeqLocPtr      slp;
2696   Uint2          subtype;
2697 
2698   if (gcp == NULL) return TRUE;
2699 
2700   ccp = (ConvCdsPtr) gcp->userdata;
2701   if (ccp == NULL ) return TRUE;
2702 
2703   if (gcp->thistype != OBJ_SEQFEAT) return TRUE;
2704   omtp = ccp->omtp;
2705   if (omtp == NULL || omtp->subtypefunc == NULL) return TRUE;
2706 
2707   sfp = (SeqFeatPtr) gcp->thisitem;
2708   subtype = (*(omtp->subtypefunc)) ((Pointer) sfp);
2709   if (subtype != ccp->subtype) return TRUE;
2710 
2711   bsp = GetBioseqGivenSeqLoc (sfp->location, gcp->entityID);
2712   if (bsp == NULL) return TRUE;
2713   if (ISA_aa (bsp->mol)) return TRUE;
2714   if (bsp->repr != Seq_repr_seg) {
2715     sep = ccp->nsep;
2716     if (sep == NULL || sep->choice != 1) return TRUE;
2717     bsp = (BioseqPtr) sep->data.ptrvalue;
2718     if (bsp == NULL) return TRUE;
2719   }
2720   CheckSeqLocForPartial (sfp->location, &noLeft, &noRight);
2721   slp = SeqLocMerge (bsp, sfp->location, ccp->slp, FALSE, TRUE, FALSE);
2722   if (slp == NULL) return TRUE;
2723   SetSeqLocPartial (slp, noLeft, noRight);
2724 
2725   ccp->slp = SeqLocFree (ccp->slp);
2726   ccp->slp = slp;
2727 
2728   return TRUE;
2729 }
2730 
2731 static void FinishConvertingToCDS (SeqEntryPtr sep, Uint2 entityID, ConvCdsPtr ccp)
2732 
2733 {
2734   ByteStorePtr  bs;
2735   BioseqPtr     bsp;
2736   Char          ch;
2737   CdRegionPtr   crp;
2738   ValNodePtr    descr;
2739   Uint1         frame;
2740   Int2          genCode;
2741   Int2          i;
2742   Int4          len;
2743   Int4          lens [4];
2744   Int4          max;
2745   Boolean       noLeft;
2746   Boolean       noRight;
2747   MolInfoPtr    mip;
2748   SeqEntryPtr   nsep;
2749   SeqEntryPtr   old;
2750   CharPtr       prot;
2751   ProtRefPtr    prp;
2752   SeqEntryPtr   psep;
2753   CharPtr       ptr;
2754   SeqFeatPtr    sfp;
2755   Char          str [128];
2756   ValNodePtr    vnp;
2757 
2758   if (sep == NULL || ccp == NULL) return;
2759   genCode = SeqEntryToGeneticCode (sep, NULL, NULL, 0);
2760   crp = CreateNewCdRgn (1, FALSE, genCode);
2761   if (crp == NULL) return;
2762   sfp = CreateNewFeature (ccp->nsep, NULL, SEQFEAT_CDREGION, NULL);
2763   if (sfp == NULL) {
2764     CdRegionFree (crp);
2765     return;
2766   }
2767   sfp->data.value.ptrvalue = (Pointer) crp;
2768   sfp->location = SeqLocFree (sfp->location);
2769   sfp->location = AsnIoMemCopy ((Pointer) ccp->slp,
2770                                 (AsnReadFunc) SeqLocAsnRead,
2771                                 (AsnWriteFunc) SeqLocAsnWrite);
2772   CheckSeqLocForPartial (sfp->location, &noLeft, &noRight);
2773   sfp->partial = (sfp->partial || noLeft || noRight);
2774   if (! TextHasNoText (ccp->featcomment)) {
2775     sfp->comment = SaveStringFromTextAndStripNewlines (ccp->featcomment);
2776   }
2777   max = 0;
2778   frame = 0;
2779   for (i = 1; i <= 3; i++) {
2780     crp->frame = (Uint1) i;
2781     bs = ProteinFromCdRegionEx (sfp, FALSE, FALSE);
2782     len = BSLen (bs);
2783     BSFree (bs);
2784     lens [i] = len;
2785     if (len > max) {
2786       max = len;
2787       frame = (Uint1) i;
2788     }
2789   }
2790   for (i = 1; i <= 3; i++) {
2791     if (lens [i] == max && i != frame) {
2792       (ccp->errcount)++;
2793     }
2794   }
2795   crp->frame = frame;
2796   bs = ProteinFromCdRegionEx (sfp, TRUE, FALSE);
2797   if (bs == NULL) return;
2798   prot = BSMerge (bs, NULL);
2799   bs = BSFree (bs);
2800   if (prot == NULL) return;
2801   ptr = prot;
2802   ch = *ptr;
2803   while (ch != '\0') {
2804     *ptr = TO_UPPER (ch);
2805     ptr++;
2806     ch = *ptr;
2807   }
2808   i = (Int2) StringLen (prot);
2809   if (i > 0 && prot [i - 1] == '*') {
2810     prot [i - 1] = '\0';
2811   }
2812   bs = BSNew (1000);
2813   if (bs != NULL) {
2814     ptr = prot;
2815     /*
2816     if (prot [0] == '-') {
2817       ptr++;
2818     }
2819     */
2820     BSWrite (bs, (VoidPtr) ptr, (Int4) StringLen (ptr));
2821   }
2822   MemFree (prot);
2823   if (bs == NULL) return;
2824   bsp = BioseqNew ();
2825   if (bsp == NULL) return;
2826   bsp->repr = Seq_repr_raw;
2827   bsp->mol = Seq_mol_aa;
2828   bsp->seq_data_type = Seq_code_ncbieaa;
2829   bsp->seq_data = (SeqDataPtr) bs;
2830   bsp->length = BSLen (bs);
2831   bs = NULL;
2832   old = SeqEntrySetScope (sep);
2833   bsp->id = MakeNewProteinSeqId (sfp->location, NULL);
2834   SeqMgrAddToBioseqIndex (bsp);
2835   SeqEntrySetScope (old);
2836   psep = SeqEntryNew ();
2837   if (psep != NULL) {
2838     psep->choice = 1;
2839     psep->data.ptrvalue = (Pointer) bsp;
2840     SeqMgrSeqEntry (SM_BIOSEQ, (Pointer) bsp, psep);
2841     mip = MolInfoNew ();
2842     if (mip != NULL) {
2843       mip->biomol = 8;
2844       mip->tech = 8;
2845       if (noLeft && noRight) {
2846         mip->completeness = 5;
2847       } else if (noLeft) {
2848         mip->completeness = 3;
2849       } else if (noRight) {
2850         mip->completeness = 4;
2851       }
2852       vnp = CreateNewDescriptor (psep, Seq_descr_molinfo);
2853       if (vnp != NULL) {
2854         vnp->data.ptrvalue = (Pointer) mip;
2855       }
2856     }
2857     descr = ExtractBioSourceAndPubs (sep);
2858     /*
2859     AddSeqEntryToSeqEntry (sep, psep, FALSE);
2860     */
2861     AddSeqEntryToSeqEntry (sep, psep, TRUE);
2862     nsep = FindNucSeqEntry (sep);
2863     ReplaceBioSourceAndPubs (sep, descr);
2864     SetSeqFeatProduct (sfp, bsp);
2865     GetTitle (ccp->protName, str, sizeof (str));
2866     if (! StringHasNoText (str)) {
2867       prp = CreateNewProtRef (str, NULL, NULL, NULL);
2868       if (prp != NULL) {
2869         sfp = CreateNewFeature (psep, NULL, SEQFEAT_PROT, NULL);
2870         if (sfp != NULL) {
2871           sfp->data.value.ptrvalue = (Pointer) prp;
2872           SetSeqLocPartial (sfp->location, noLeft, noRight);
2873           sfp->partial = (sfp->partial || noLeft || noRight);
2874         }
2875       }
2876     }
2877   }
2878 }
2879 
2880 static void RemoveCDSAncestorCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
2881 
2882 {
2883   BioseqPtr      bsp;
2884   BioseqSetPtr   bssp;
2885   ConvCdsPtr     ccp;
2886   SeqAnnotPtr    nextsap;
2887   SeqFeatPtr     nextsfp;
2888   ObjMgrTypePtr  omtp;
2889   Pointer PNTR   prevsap;
2890   Pointer PNTR   prevsfp;
2891   SeqAnnotPtr    sap;
2892   SeqFeatPtr     sfp;
2893   Uint2          subtype;
2894 
2895   if (sep == NULL || sep->data.ptrvalue == NULL) return;
2896   ccp = (ConvCdsPtr) mydata;
2897   if (ccp == NULL) return;
2898   omtp = ccp->omtp;
2899   if (omtp == NULL || omtp->subtypefunc == NULL) return;
2900   if (IS_Bioseq (sep)) {
2901     bsp = (BioseqPtr) sep->data.ptrvalue;
2902     sap = bsp->annot;
2903     prevsap = (Pointer PNTR) &(bsp->annot);
2904   } else if (IS_Bioseq_set (sep)) {
2905     bssp = (BioseqSetPtr) sep->data.ptrvalue;
2906     sap = bssp->annot;
2907     prevsap = (Pointer PNTR) &(bssp->annot);
2908   } else return;
2909   while (sap != NULL) {
2910     nextsap = sap->next;
2911     if (sap->type == 1) {
2912       sfp = (SeqFeatPtr) sap->data;
2913       prevsfp = (Pointer PNTR) &(sap->data);
2914       while (sfp != NULL) {
2915         nextsfp = sfp->next;
2916         subtype = (*(omtp->subtypefunc)) ((Pointer) sfp);
2917         if (subtype == ccp->subtype) {
2918           *(prevsfp) = sfp->next;
2919           sfp->next = NULL;
2920           SeqFeatFree (sfp);
2921         } else {
2922           prevsfp = (Pointer PNTR) &(sfp->next);
2923         }
2924         sfp = nextsfp;
2925       }
2926     }
2927     if (sap->data == NULL) {
2928       *(prevsap) = sap->next;
2929       sap->next = NULL;
2930       SeqAnnotFree (sap);
2931     } else {
2932       prevsap = (Pointer PNTR) &(sap->next);
2933     }
2934     sap = nextsap;
2935   }
2936 }
2937 
2938 static void ConvertToCDSCallback (SeqEntryPtr sep, Uint2 entityID, ConvCdsPtr ccp)
2939 
2940 {
2941   BioseqPtr     bsp;
2942   BioseqSetPtr  bssp;
2943   GeneRefPtr    grp;
2944   GatherScope   gs;
2945   SeqLocPtr     gslp;
2946   Boolean       hasNulls;
2947   Boolean       noLeft;
2948   Boolean       noRight;
2949   SeqEntryPtr   nsep;
2950   SeqFeatPtr    sfp;
2951   SeqIdPtr      sip;
2952   SeqLocPtr     slp;
2953   Char          str [128];
2954 
2955   if (sep == NULL || ccp == NULL) return;
2956   if (IS_Bioseq_set (sep)) {
2957     bssp = (BioseqSetPtr) sep->data.ptrvalue;
2958     if (bssp != NULL && (bssp->_class == 7 ||
2959                          (IsPopPhyEtcSet (bssp->_class)))) {
2960       for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
2961         ConvertToCDSCallback (sep, entityID, ccp);
2962       }
2963       return;
2964     }
2965   }
2966   ccp->nsep = FindNucSeqEntry (sep);
2967   if (ccp->nsep == NULL) return;
2968   MemSet ((Pointer) (&gs), 0, sizeof (GatherScope));
2969   gs.seglevels = 1;
2970   gs.get_feats_location = FALSE;
2971   MemSet ((Pointer) (gs.ignore), (int)(TRUE), (size_t) (OBJ_MAX * sizeof(Boolean)));
2972   gs.ignore[OBJ_BIOSEQ] = FALSE;
2973   gs.ignore[OBJ_BIOSEQ_SEG] = FALSE;
2974   gs.ignore[OBJ_SEQFEAT] = FALSE;
2975   gs.ignore[OBJ_SEQANNOT] = FALSE;
2976   gs.scope = sep;
2977   ccp->slp = NULL;
2978   GatherEntity (entityID, (Pointer) ccp, CollectCDSAncestorGatherFunc, &gs);
2979   if (ccp->slp != NULL) {
2980     CheckSeqLocForPartial (ccp->slp, &noLeft, &noRight);
2981     sip = SeqLocId (ccp->slp);
2982     if (sip != NULL) {
2983       bsp = BioseqFind (sip);
2984       if (bsp != NULL && ISA_na (bsp->mol)) {
2985         slp = SegLocToParts (bsp, ccp->slp);
2986         if (slp != NULL) {
2987           ccp->slp = SeqLocFree (ccp->slp);
2988           ccp->slp = slp;
2989           FreeAllFuzz (ccp->slp);
2990           SetSeqLocPartial (ccp->slp, noLeft, noRight);
2991         }
2992       }
2993     }
2994     FinishConvertingToCDS (sep, entityID, ccp);
2995     nsep = FindNucSeqEntry (sep);
2996     GetTitle (ccp->geneName, str, sizeof (str));
2997     if (! StringHasNoText (str)) {
2998       grp = CreateNewGeneRef (str, NULL, NULL, FALSE);
2999       if (grp != NULL) {
3000         if (ExtendGene (grp, nsep, ccp->slp)) {
3001           grp = GeneRefFree (grp);
3002         } else {
3003           sfp = CreateNewFeature (nsep, NULL, SEQFEAT_GENE, NULL);
3004           if (sfp != NULL) {
3005             sfp->data.value.ptrvalue = (Pointer) grp;
3006             sfp->location = SeqLocFree (sfp->location);
3007             sfp->location = AsnIoMemCopy ((Pointer) ccp->slp,
3008                                           (AsnReadFunc) SeqLocAsnRead,
3009                                           (AsnWriteFunc) SeqLocAsnWrite);
3010             sip = SeqLocId (sfp->location);
3011             if (sip != NULL) {
3012               bsp = BioseqFind (sip);
3013               if (bsp != NULL) {
3014                 gslp = SeqLocMerge (bsp, sfp->location, NULL, TRUE, FALSE, FALSE);
3015                 if (gslp != NULL) {
3016                   sfp->location = SeqLocFree (sfp->location);
3017                   sfp->location = gslp;
3018                   if (bsp->repr == Seq_repr_seg) {
3019                     gslp = SegLocToPartsEx (bsp, sfp->location, TRUE);
3020                     sfp->location = SeqLocFree (sfp->location);
3021                     sfp->location = gslp;
3022                     hasNulls = LocationHasNullsBetween (sfp->location);
3023                     sfp->partial = (sfp->partial || hasNulls);
3024                   }
3025                   FreeAllFuzz (gslp);
3026                   SetSeqLocPartial (sfp->location, noLeft, noRight);
3027                   sfp->partial = (sfp->partial || noLeft || noRight);
3028                 }
3029               }
3030             }
3031           }
3032         }
3033       }
3034     }
3035   }
3036   ccp->slp = SeqLocFree (ccp->slp);
3037 }
3038 
3039 static void DoConvertToCDS (ButtoN b)
3040 
3041 {
3042   ConvCdsPtr  ccp;
3043   CharPtr     plural;
3044   Char        str [128];
3045 
3046   ccp = GetObjectExtra (b);
3047   if (ccp == NULL) {
3048     Remove (ParentWindow (b));
3049     return;
3050   }
3051   GetTitle (ccp->protName, str, sizeof (str));
3052   if (StringHasNoText (str)) {
3053     Message (MSG_OK, "Protein name is required");
3054     return;
3055   }
3056   Hide (ccp->form);
3057   WatchCursor ();
3058 
3059   ccp->omp = ObjMgrGet ();
3060   if (ccp->omp != NULL) {
3061     ccp->omtp = ObjMgrTypeFind (ccp->omp, OBJ_SEQFEAT, NULL, NULL);
3062     if (ccp->omtp != NULL && ccp->omtp->subtypefunc != NULL) {
3063       ConvertToCDSCallback (ccp->sep, ccp->input_entityID, ccp);
3064       if (! GetStatus (ccp->retain)) {
3065         SeqEntryExplore (ccp->sep, (Pointer) ccp, RemoveCDSAncestorCallback);
3066       }
3067     }
3068   }
3069 
3070   ArrowCursor ();
3071   Update ();
3072 
3073   if (ccp->errcount > 0) {
3074     if (ccp->errcount > 1) {
3075       plural = "records";
3076     } else {
3077       plural = "record";
3078     }
3079     Message (MSG_ERROR, "Possible ambiguous frames detected in %d %s",
3080              (int) ccp->errcount, plural);
3081   }
3082 
3083   ObjMgrSetDirtyFlag (ccp->input_entityID, TRUE);
3084   ObjMgrSendMsg (OM_MSG_UPDATE, ccp->input_entityID, 0, 0);
3085   Remove (ccp->form);
3086   Update ();
3087 }
3088 
3089 extern void PrepareToConvertToCDS (SeqEntryPtr sep, Uint2 entityID,
3090                                    Uint2 subtype, CharPtr findthis)
3091 
3092 {
3093   ButtoN             b;
3094   GrouP              c;
3095   ConvCdsPtr         ccp;
3096   GrouP              g;
3097   GrouP              h;
3098   StdEditorProcsPtr  sepp;
3099   WindoW             w;
3100 
3101   if (sep == NULL || entityID == 0 || subtype == 0) return;
3102 
3103   ccp = (ConvCdsPtr) MemNew (sizeof (ConvCdsData));
3104   if (ccp == NULL) return;
3105   w = FixedWindow (-50, -33, -10, -10, "Convert to CDS", StdCloseWindowProc);
3106   SetObjectExtra (w, ccp, StdCleanupFormProc);
3107   ccp->form = (ForM) w;
3108   ccp->formmessage = DefaultMessageProc;
3109 
3110   sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
3111   if (sepp != NULL) {
3112     SetActivate (w, sepp->activateForm);
3113     ccp->appmessage = sepp->handleMessages;
3114   }
3115 
3116   ccp->input_entityID = entityID;
3117 
3118   h = HiddenGroup (w, -1, 0, NULL);
3119   SetGroupSpacing (h, 10, 10);
3120 
3121   ccp->sep = sep;
3122   ccp->subtype = subtype;
3123   StringNCpy_0 (ccp->findThis, findthis, sizeof (ccp->findThis));
3124   ccp->errcount = 0;
3125 
3126   g = HiddenGroup (h, 2, 0, NULL);
3127   StaticPrompt (g, "Gene Symbol", 0, dialogTextHeight, programFont, 'l');
3128   ccp->geneName = DialogText (g, "", 20, NULL);
3129   StaticPrompt (g, "Protein Name", 0, dialogTextHeight, programFont, 'l');
3130   ccp->protName = DialogText (g, "", 20, NULL);
3131   StaticPrompt (g, "Comment", 0, 4 * Nlm_stdLineHeight, programFont, 'l');
3132   ccp->featcomment = ScrollText (g, 20, 4, programFont, TRUE, NULL);
3133 
3134   ccp->retain = CheckBox (h, "Retain original features", NULL);
3135 
3136   c = HiddenGroup (h, 4, 0, NULL);
3137   b = DefaultButton (c, "Accept", DoConvertToCDS);
3138   SetObjectExtra (b, ccp, NULL);
3139   PushButton (c, "Cancel", StdCancelButtonProc);
3140 
3141   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, (HANDLE) ccp->retain, NULL);
3142   RealizeWindow (w);
3143   Show (w);
3144   Select (ccp->geneName);
3145   Update ();
3146 }
3147 
3148 typedef struct alignform {
3149   FORM_MESSAGE_BLOCK
3150   DoC            doc;
3151 } AlignForm, PNTR AlignFormPtr;
3152 
3153 static ParData bioseqParFmt = {FALSE, FALSE, FALSE, FALSE, FALSE, 0, 0};
3154 static ColData bioseqColFmt [] = {
3155   {0, 5, 0, 0, NULL, 'l', TRUE, FALSE, FALSE, FALSE, TRUE}
3156 };
3157 
3158 static ParData annotParFmt = {FALSE, FALSE, FALSE, FALSE, FALSE, 0, 0};
3159 static ColData annotColFmt [] = {
3160   {0, 10, 0, 0, NULL, 'l', FALSE, FALSE, FALSE, FALSE, TRUE}
3161 };
3162 
3163 static ParData alignParFmt = {FALSE, FALSE, FALSE, FALSE, FALSE, 0, 0};
3164 static ColData alignColFmt [] = {
3165   {0, 15, 0, 0, NULL, 'l', FALSE, FALSE, FALSE, FALSE, FALSE},
3166   {0, 5, 0, 0, NULL, 'l', FALSE, FALSE, FALSE, FALSE, FALSE},
3167   {0, 0, 0, 0, NULL, 'l', FALSE, FALSE, FALSE, FALSE, TRUE}
3168 };
3169 
3170 static Boolean AlignFormPopulateProc (GatherContextPtr gcp)
3171 
3172 {
3173   AlignFormPtr      afp;
3174   SeqAlignPtr       align;
3175   Char              annotDB [32];
3176   Uint1             annot_type;
3177   BioseqContextPtr  bcp;
3178   BioseqPtr         bsp;
3179   DenseDiagPtr      ddp;
3180   DenseSegPtr       dsp;
3181   ProtRefPtr        prp;
3182   CharPtr           ptr;
3183   SeqAnnotPtr       sap;
3184   SeqEntryPtr       sep;
3185   SeqFeatPtr        sfp;
3186   SeqIdPtr          sip;
3187   StdSegPtr         ssp;
3188   Char              str [256];
3189   Char              tmp [128];
3190 
3191   if (gcp == NULL) return TRUE;
3192 
3193   afp = (AlignFormPtr) gcp->userdata;
3194   if (afp == NULL ) return TRUE;
3195 
3196   switch (gcp->thistype) {
3197     case OBJ_BIOSEQ :
3198       bsp = (BioseqPtr) gcp->thisitem;
3199       if (bsp != NULL) {
3200         SeqIdWrite (bsp->id, str, PRINTID_REPORT, sizeof (str));
3201         bcp = BioseqContextNew (bsp);
3202         sfp = BioseqContextGetSeqFeat (bcp, SEQFEAT_PROT, NULL, NULL, 0);
3203         BioseqContextFree (bcp);
3204         if (sfp != NULL) {
3205           prp = (ProtRefPtr) sfp->data.value.ptrvalue;
3206           if (prp != NULL) {
3207             if (prp->name != NULL && (! StringHasNoText (prp->name->data.ptrvalue))) {
3208               StringCat (str, " (");
3209               StringCat (str, (CharPtr) prp->name->data.ptrvalue);
3210               StringCat (str, ")");
3211             } else if (! StringHasNoText (prp->desc)) {
3212               StringCat (str, " (");
3213               StringCat (str, (CharPtr) prp->desc);
3214               StringCat (str, ")");
3215             }
3216           }
3217         }
3218         StringCat (str, ":\n");
3219         AppendText (afp->doc, str, &bioseqParFmt, bioseqColFmt, programFont);
3220       }
3221       break;
3222     case OBJ_SEQANNOT :
3223       sap = (SeqAnnotPtr) gcp->thisitem;
3224       if (sap != NULL && sap->type == 2) {
3225         get_align_annot_qual (sap, annotDB, sizeof (annotDB), &annot_type);
3226         if (annot_type == ANNOT_BLAST) {
3227           StringCpy (str, annotDB);
3228           StringCat (str, ":\n");
3229           AppendText (afp->doc, str, &annotParFmt, annotColFmt, programFont);
3230         }
3231       }
3232       break;
3233     case OBJ_SEQALIGN :
3234     case OBJ_SEQHIST_ALIGN :
3235       align = (SeqAlignPtr) gcp->thisitem;
3236       sip = NULL;
3237       if (align->segtype == 1) {
3238         ddp = (DenseDiagPtr) align->segs;
3239         if (ddp != NULL) {
3240           for (sip = ddp->id; sip != NULL && sip->next != NULL; sip = sip->next) {
3241           }
3242         }
3243       } else if (align->segtype == 2) {
3244         dsp = (DenseSegPtr) align->segs;
3245         if (dsp != NULL) {
3246           for (sip = dsp->ids; sip != NULL && sip->next != NULL; sip = sip->next) {
3247           }
3248         }
3249       } else if (align->segtype == 3) {
3250         ssp = (StdSegPtr) align->segs;
3251         if (ssp != NULL) {
3252           for (sip = ssp->ids; sip != NULL && sip->next != NULL; sip = sip->next) {
3253           }
3254         }
3255       }
3256       if (sip != NULL) {
3257         bsp = BioseqLockById (sip);
3258         if (bsp != NULL) {
3259           /* SeqIdWrite (bsp->id, str, PRINTID_FASTA_LONG, sizeof (str)); */
3260           SeqIdWrite (bsp->id, str, PRINTID_REPORT, sizeof (str));
3261           StringNCpy_0 (tmp, BioseqGetTitle (bsp), sizeof (tmp));
3262           StringCat (str, "\t");
3263           if (! StringHasNoText (tmp)) {
3264             StringCat (str, tmp);
3265           }
3266           tmp [0] = '\0';
3267           sep = SeqMgrGetSeqEntryForData (bsp);
3268           if (sep != NULL) {
3269             SeqEntryToBioSource (sep, NULL, tmp, sizeof (tmp), NULL);
3270             if (! StringHasNoText (tmp)) {
3271               ptr = StringStr (tmp, "(");
3272               if (ptr != NULL) {
3273                 *ptr = '\0';
3274               }
3275               StringCat (str, " [");
3276               StringCat (str, tmp);
3277               StringCat (str, "]");
3278             }
3279           }
3280           StringCat (str, "\t");
3281           sprintf (tmp, "%d %d %d", (int) gcp->entityID,
3282                    (int) gcp->itemID, (int) gcp->thistype);
3283           StringCat (str, tmp);
3284           StringCat (str, "\n");
3285           AppendText (afp->doc, str, &alignParFmt, alignColFmt, programFont);
3286         }
3287         BioseqUnlock (bsp);
3288       }
3289       return TRUE;
3290     default :
3291       break;
3292   }
3293   return TRUE;
3294 }
3295 
3296 static void PopulateAlignForm (ForM f, SeqEntryPtr sep)
3297 
3298 {
3299   AlignFormPtr  afp;
3300   GatherScope   gs;
3301   RecT          r;
3302   Int2          width;
3303 
3304   if (f == NULL || sep == NULL) return;
3305   afp = (AlignFormPtr) GetObjectExtra (f);
3306   if (afp == NULL) return;
3307   Reset (afp->doc);
3308   SetDocAutoAdjust (afp->doc, FALSE);
3309   ObjectRect (afp->doc, &r);
3310   InsetRect (&r, 4, 4);
3311   width = r.right - r.left;
3312   alignColFmt [0].pixWidth = width / 5;
3313   alignColFmt [1].pixWidth = width - alignColFmt [0].pixWidth;
3314   bioseqColFmt [0].pixWidth = width;
3315   annotColFmt [0].pixWidth = width;
3316   MemSet ((Pointer) (&gs), 0, sizeof (GatherScope));
3317   gs.seglevels = 1;
3318   MemSet((Pointer) (gs.ignore), (int) (TRUE), (size_t) (OBJ_MAX * sizeof (Boolean)));
3319   gs.ignore[OBJ_BIOSEQ] = FALSE;
3320   gs.ignore[OBJ_BIOSEQ_SEG] = FALSE;
3321   gs.ignore[OBJ_SEQALIGN] = FALSE;
3322   gs.ignore[OBJ_SEQANNOT] = FALSE;
3323   gs.ignore[OBJ_SEQHIST] = FALSE;
3324   gs.ignore[OBJ_SEQHIST_ALIGN] = FALSE;
3325   gs.scope = sep;
3326   GatherEntity (afp->input_entityID, (Pointer) afp, AlignFormPopulateProc, &gs);
3327   AdjustDocScroll (afp->doc);
3328 }
3329 
3330 static void AlignMessageProc (ForM f, Int2 mssg)
3331 
3332 {
3333   FILE          *fp;
3334   AlignFormPtr  afp;
3335   Char          path [PATH_MAX];
3336 
3337   afp = (AlignFormPtr) GetObjectExtra (f);
3338   if (afp != NULL) {
3339     switch (mssg) {
3340       case VIB_MSG_CLOSE :
3341         Remove (f);
3342         break;
3343       case VIB_MSG_PRINT :
3344         PrintDocument (afp->doc);
3345         break;
3346       case VIB_MSG_EXPORT :
3347         if (GetOutputFileName (path, sizeof (path), "align.txt")) {
3348           WatchCursor ();
3349 #ifdef WIN_MAC
3350           fp = FileOpen (path, "r");
3351           if (fp != NULL) {
3352             FileClose (fp);
3353           } else {
3354             FileCreate (path, "TEXT", "ttxt");
3355           }
3356 #endif
3357           fp = FileOpen (path, "w");
3358           if (fp != NULL) {
3359             SaveDocument (afp->doc, fp);
3360             FileClose (fp);
3361           }
3362           ArrowCursor ();
3363         }
3364         break;
3365       default :
3366         if (afp->appmessage != NULL) {
3367           afp->appmessage (f, mssg);
3368         }
3369         break;
3370     }
3371   }
3372 }
3373 
3374 static void AlignFormActivate (WindoW w)
3375 
3376 {
3377   AlignFormPtr  afp;
3378   IteM          exportItm;
3379   IteM          printItm;
3380 
3381   afp = (AlignFormPtr) GetObjectExtra (w);
3382 #ifdef WIN_MAC
3383   currentFormDataPtr = (VoidPtr) afp;
3384 #endif
3385   if (afp != NULL) {
3386     if (afp->activate != NULL) {
3387       afp->activate (w);
3388     }
3389     exportItm = FindFormMenuItem ((BaseFormPtr) afp, VIB_MSG_EXPORT);
3390     SafeSetTitle (exportItm, "Export Align Summary...");
3391     SafeEnable (exportItm);
3392     printItm = FindFormMenuItem ((BaseFormPtr) afp, VIB_MSG_PRINT);
3393     SafeEnable (printItm);
3394   }
3395 }
3396 
3397 static void AlignNotifyProc (DoC d, Int2 item, Int2 row, Int2 col, Boolean dblClick)
3398 
3399 {
3400   unsigned int  entityID;
3401   unsigned int  itemID;
3402   unsigned int  itemtype;
3403   CharPtr       txt;
3404 
3405   if (d == NULL || item < 1 || row < 1 || col < 1) return;
3406   txt = GetDocText (d, item, row, 3);
3407   if (! StringHasNoText (txt)) {
3408     if (sscanf (txt, "%u %u %u", &entityID, &itemID, &itemtype) == 3) {
3409       if (shftKey) {
3410         ObjMgrAlsoSelect (entityID, itemID, itemtype, 0, NULL);
3411       } else {
3412         ObjMgrSelect (entityID, itemID, itemtype, 0, NULL);
3413       }
3414     }
3415   }
3416   MemFree (txt);
3417 }
3418 
3419 static ForM CreateAlignForm (Uint2 entityID)
3420 
3421 {
3422   AlignFormPtr       afp;
3423   GrouP              c;
3424   GrouP              h;
3425   StdEditorProcsPtr  sepp;
3426   WindoW             w;
3427 #ifndef WIN_MAC
3428   MenU               m;
3429 #endif
3430 
3431   w = NULL;
3432   afp = MemNew (sizeof (AlignForm));
3433   if (afp != NULL) {
3434     w = FixedWindow (-50, -33, -10, -10, "Alignment Summary", StdCloseWindowProc);
3435     SetObjectExtra (w, afp, StdCleanupFormProc);
3436     afp->form = (ForM) w;
3437     afp->formmessage = AlignMessageProc;
3438     afp->input_entityID = entityID;
3439 
3440     sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
3441     if (sepp != NULL) {
3442       afp->appmessage = sepp->handleMessages;
3443     }
3444 
3445 #ifndef WIN_MAC
3446     m = PulldownMenu (w, "File");
3447     FormCommandItem (m, "Close", (BaseFormPtr) afp, VIB_MSG_CLOSE);
3448     SeparatorItem (m);
3449     FormCommandItem (m, "Export...", (BaseFormPtr) afp, VIB_MSG_EXPORT);
3450     SeparatorItem (m);
3451     FormCommandItem (m, "Print...", (BaseFormPtr) afp, VIB_MSG_PRINT);
3452 #endif
3453 
3454     h = HiddenGroup (w, -1, 0, NULL);
3455     SetGroupSpacing (h, 10, 10);
3456 
3457     afp->doc = DocumentPanel (h, 35 * stdCharWidth, 20 * stdLineHeight);
3458     SetObjectExtra (afp->doc, afp, NULL);
3459     SetDocNotify (afp->doc, AlignNotifyProc);
3460 
3461     c = HiddenGroup (w, 4, 0, NULL);
3462     PushButton (c, "Cancel", StdCancelButtonProc);
3463 
3464     AlignObjects (ALIGN_CENTER, (HANDLE) afp->doc, (HANDLE) c, NULL);
3465 
3466     RealizeWindow (w);
3467     SetActivate (w, AlignFormActivate);
3468   }
3469   return (ForM) w;
3470 }
3471 
3472 extern void ViewAlignmentSummary (IteM i)
3473 
3474 {
3475   BaseFormPtr  bfp;
3476   ForM         f;
3477   SeqEntryPtr  sep;
3478 
3479 #ifdef WIN_MAC
3480   bfp = currentFormDataPtr;
3481 #else
3482   bfp = GetObjectExtra (i);
3483 #endif
3484   if (bfp == NULL || bfp->input_entityID == 0) return;
3485   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3486   if (sep == NULL) return;
3487 
3488   WatchCursor ();
3489   Update ();
3490   f = CreateAlignForm (bfp->input_entityID);
3491   PopulateAlignForm (f, sep);
3492   ArrowCursor ();
3493   Update ();
3494   Show (f);
3495   Select (f);
3496 }
3497 
3498 typedef struct geneprotfind {
3499   SeqFeatPtr     cds;
3500   SeqFeatPtr     gene;
3501   SeqFeatPtr     prot;
3502   SeqLocPtr      location;
3503   SeqLocPtr      product;
3504   Int4           mingene;
3505   Int4           minprot;
3506 } GeneProtFind, PNTR GeneProtPtr;
3507 
3508 static Boolean GeneProtFindFunc (GatherContextPtr gcp)
3509 
3510 {
3511   Int4         diff;
3512   GeneProtPtr  gpp;
3513   SeqFeatPtr   sfp;
3514 
3515   if (gcp == NULL) return TRUE;
3516   gpp = (GeneProtPtr) gcp->userdata;
3517   if (gpp == NULL) return TRUE;
3518   if (gcp->thistype != OBJ_SEQFEAT) return TRUE;
3519   sfp = (SeqFeatPtr) gcp->thisitem;
3520   if (sfp == NULL || sfp->data.value.ptrvalue == NULL) return TRUE;
3521   if (sfp->data.choice == SEQFEAT_GENE && gpp->location != NULL) {
3522     diff = SeqLocAinB (gpp->location, sfp->location);
3523     if (diff >= 0) {
3524       if (diff < gpp->mingene) {
3525         gpp->gene = sfp;
3526         gpp->mingene = diff;
3527       }
3528     }
3529   } else if (sfp->data.choice == SEQFEAT_PROT && gpp->product != NULL) {
3530     diff = SeqLocAinB (gpp->product, sfp->location);
3531     if (diff >= 0) {
3532       if (diff < gpp->minprot) {
3533         gpp->prot = sfp;
3534         gpp->minprot = diff;
3535       }
3536     }
3537   }
3538   return TRUE;
3539 }
3540 
3541 void FindGeneAndProtForCDS (Uint2 entityID, SeqFeatPtr cds,
3542                             SeqFeatPtr PNTR gene, SeqFeatPtr PNTR prot)
3543 
3544 {
3545   GeneProtFind  gpf;
3546   GatherScope   gs;
3547 
3548   if (gene != NULL) {
3549     *gene = NULL;
3550   }
3551   if (prot != NULL) {
3552     *prot = NULL;
3553   }
3554   if (entityID == 0 || cds == NULL) return;
3555   MemSet ((Pointer) (&gpf), 0, sizeof (GeneProtFind));
3556   gpf.cds = cds;
3557   gpf.gene = NULL;
3558   gpf.prot = NULL;
3559   gpf.location = cds->location;
3560   gpf.product = cds->product;
3561   gpf.mingene = INT4_MAX;
3562   gpf.minprot = INT4_MAX;
3563   MemSet ((Pointer) (&gs), 0, sizeof (GatherScope));
3564   gs.seglevels = 1;
3565   gs.get_feats_location = FALSE;
3566   MemSet((Pointer)(gs.ignore), (int)(TRUE), (size_t)(OBJ_MAX * sizeof(Boolean)));
3567   gs.ignore[OBJ_BIOSEQ] = FALSE;
3568   gs.ignore[OBJ_BIOSEQ_SEG] = FALSE;
3569   gs.ignore[OBJ_SEQFEAT] = FALSE;
3570   gs.ignore[OBJ_SEQANNOT] = FALSE;
3571   GatherEntity (entityID, (Pointer) &gpf, GeneProtFindFunc, &gs);
3572   if (gene != NULL) {
3573     *gene = gpf.gene;
3574   }
3575   if (prot != NULL) {
3576     *prot = gpf.prot;
3577   }
3578 }
3579 
3580 
3581 #define FIND_ASN   1
3582 #define FIND_FLAT  2
3583 #define FIND_GENE  3
3584 #define FIND_PROT  4
3585 #define FIND_POS   5
3586 
3587 typedef struct findform {
3588   FORM_MESSAGE_BLOCK
3589   TexT            findTxt;
3590   TexT            replaceTxt;
3591   ButtoN          caseCounts;
3592   ButtoN          wholeWord;
3593   ButtoN          doSeqIdLocal;
3594   ButtoN          findAllBtn;
3595   ButtoN          replaceAllBtn;
3596   Int2            type;
3597   ButtoN          findFirstBtn;
3598   ButtoN          findNextBtn;
3599   Int4            last_paragraph_found;
3600 } FindForm, PNTR FindFormPtr;
3601 
3602 extern CharPtr CompressSpaces (CharPtr str)
3603 
3604 {
3605   Char     ch;
3606   CharPtr  dst;
3607   Char     last;
3608   CharPtr  ptr;
3609 
3610   if (str != NULL && str [0] != '\0') {
3611     dst = str;
3612     ptr = str;
3613     ch = *ptr;
3614     while (ch != '\0' && ch <= ' ') {
3615       ptr++;
3616       ch = *ptr;
3617     }
3618     while (ch != '\0') {
3619       *dst = ch;
3620       dst++;
3621       ptr++;
3622       last = ch;
3623       ch = *ptr;
3624       if (ch != '\0' && ch < ' ') {
3625         *ptr = ' ';
3626         ch = *ptr;
3627       }
3628       while (ch != '\0' && last <= ' ' && ch <= ' ') {
3629         ptr++;
3630         ch = *ptr;
3631       }
3632     }
3633     *dst = '\0';
3634     dst = NULL;
3635     ptr = str;
3636     ch = *ptr;
3637     while (ch != '\0') {
3638       if (ch != ' ') {
3639         dst = NULL;
3640       } else if (dst == NULL) {
3641         dst = ptr;
3642       }
3643       ptr++;
3644       ch = *ptr;
3645     }
3646     if (dst != NULL) {
3647       *dst = '\0';
3648     }
3649   }
3650   return str;
3651 }
3652 
3653 extern CharPtr SearchForString (CharPtr str, CharPtr sub, Boolean case_counts, Boolean whole_word)
3654 
3655 {
3656   CharPtr  ptr = NULL;
3657   CharPtr  tmp;
3658 
3659   if (case_counts) {
3660     ptr = StringSearch (str, sub);
3661   } else {
3662     ptr = StringISearch (str, sub);
3663   }
3664   if (ptr == NULL) return NULL;
3665   if (whole_word) {
3666     if (ptr > str) {
3667       tmp = ptr - 1;
3668       if (! IS_WHITESP (*tmp)) return NULL;
3669     }
3670     tmp = ptr + StringLen (sub);
3671     if (*tmp != '\0' && (! IS_WHITESP (*tmp))) return NULL;
3672   }
3673   return ptr;
3674 }
3675 
3676 
3677 static Int4
3678 FindInFlatFileNext 
3679 (Asn2gbJobPtr ajp,
3680  CharPtr sub,
3681  Boolean case_counts,
3682  Boolean whole_word,
3683  Boolean stop_after_one_found,
3684  Int4    start_index)
3685 {
3686   Int4             index;
3687   CharPtr          string;
3688   BaseBlockPtr     bbp;
3689   SelStructPtr     sel;
3690   unsigned int     entID;
3691   unsigned int     itmID;
3692   unsigned int     itmtype;
3693   Boolean          already = FALSE;
3694 
3695   if (ajp == NULL) return -1;
3696       
3697   for (index = start_index + 1; index < ajp->numParagraphs; index++) {
3698     string = asn2gnbk_format (ajp, (Int4) index);
3699     if (string != NULL && *string != '\0') {
3700       CompressSpaces (string);
3701       if (SearchForString (string, sub, case_counts, whole_word) != NULL) {
3702         bbp = ajp->paragraphArray [index];
3703         if (bbp != NULL) {
3704           entID = bbp->entityID;
3705           itmID = bbp->itemID;
3706           itmtype = bbp->itemtype;
3707           already = FALSE;
3708           for (sel = ObjMgrGetSelected (); sel != NULL; sel = sel->next) {
3709             if (sel->entityID == entID && sel->itemID == itmID && sel->itemtype == itmtype) {
3710               already = TRUE;
3711             }
3712           }
3713           if (! already) {
3714             ObjMgrAlsoSelect (entID, itmID, itmtype, 0, NULL);
3715             if (stop_after_one_found) return index;
3716           }
3717         }
3718       }
3719     }
3720   }
3721   return -1;
3722 }
3723 
3724 
3725 static Int4 
3726 FindInFlatFile 
3727 (Uint2 entityID,
3728  Uint4 itemID,
3729  Uint2 itemtype,                           
3730  Uint1 format,
3731  Uint1 mode,                           
3732  CharPtr sub,
3733  Boolean case_counts,
3734  Boolean whole_word,                           
3735  Boolean stop_after_one,
3736  Int4 start_index)
3737 
3738 {
3739   Asn2gbJobPtr     ajp = NULL;
3740   BioseqPtr        bsp = NULL;
3741   BioseqSetPtr     bssp;
3742   ErrSev           level;
3743   SeqEntryPtr      oldsep;
3744   SeqEntryPtr      sep = NULL;
3745   SeqEntryPtr      topsep;
3746   SeqEntryPtr      usethetop = NULL;
3747   Int4             retval = -1;
3748   FlgType          flags = SHOW_CONTIG_FEATURES | SHOW_CONTIG_SOURCES | SHOW_FAR_TRANSLATION;
3749 
3750   if (itemID == 0) {
3751     sep = GetTopSeqEntryForEntityID (entityID);
3752     usethetop = sep;
3753   } else {
3754     bsp = GetBioseqGivenIDs (entityID, itemID, itemtype);
3755     if (bsp == NULL)
3756       return retval;
3757     sep = SeqMgrGetSeqEntryForData (bsp);
3758     if (bsp->repr == Seq_repr_seg) {
3759       sep = GetBestTopParentForData (entityID, bsp);
3760     }
3761   }
3762 
3763   if (sep == NULL)
3764     return retval;
3765 
3766   level = ErrSetMessageLevel (SEV_MAX);
3767   WatchCursor ();
3768   Update ();
3769 
3770   topsep = GetTopSeqEntryForEntityID (entityID);
3771   oldsep = SeqEntrySetScope (topsep);
3772 
3773   if (usethetop != NULL && IS_Bioseq_set (usethetop)) {
3774     bssp = (BioseqSetPtr) usethetop->data.ptrvalue;
3775     ajp = asn2gnbk_setup (NULL, bssp, NULL, (FmtType) format, (ModType) mode, NORMAL_STYLE, flags, (LckType) 0, (CstType) 0, NULL);
3776   } else if (bsp != NULL) {
3777     ajp = asn2gnbk_setup (bsp, NULL, NULL, (FmtType) format, (ModType) mode, NORMAL_STYLE, flags, (LckType) 0, (CstType) 0, NULL);
3778   }
3779   if (ajp != NULL) {
3780     retval = FindInFlatFileNext (ajp, sub, case_counts, whole_word, stop_after_one, start_index);
3781     asn2gnbk_cleanup (ajp);
3782   }
3783 
3784   SeqEntrySetScope (oldsep);
3785 
3786   ErrSetMessageLevel (level);
3787   ArrowCursor ();
3788   Update ();
3789   return retval;
3790 }
3791 
3792 static void FindFlatProc (ButtoN b)
3793 
3794 {
3795   Boolean      caseCounts;
3796   FindFormPtr  ffp;
3797   CharPtr      findme;
3798   Boolean      wholeWord;
3799 
3800   ffp = (FindFormPtr) GetObjectExtra (b);
3801   if (ffp == NULL) return;
3802   findme = SaveStringFromText (ffp->findTxt);
3803   ObjMgrDeSelect (0, 0, 0, 0, NULL);
3804   caseCounts = GetStatus (ffp->caseCounts);
3805   wholeWord = GetStatus (ffp->wholeWord);
3806   CompressSpaces (findme);
3807   ffp->last_paragraph_found = FindInFlatFile (ffp->input_entityID, ffp->input_itemID,
3808                   ffp->input_itemtype, GENBANK_FMT, SEQUIN_MODE,
3809                   findme, caseCounts, wholeWord, FALSE, -1);
3810   MemFree (findme);
3811 }
3812 
3813 static void FindFlatProcFirst (ButtoN b)
3814 
3815 {
3816   Boolean      caseCounts;
3817   FindFormPtr  ffp;
3818   CharPtr      findme;
3819   Boolean      wholeWord;
3820 
3821   ffp = (FindFormPtr) GetObjectExtra (b);
3822   if (ffp == NULL) return;
3823   findme = SaveStringFromText (ffp->findTxt);
3824   ObjMgrDeSelect (0, 0, 0, 0, NULL);
3825   caseCounts = GetStatus (ffp->caseCounts);
3826   wholeWord = GetStatus (ffp->wholeWord);
3827   CompressSpaces (findme);
3828   ffp->last_paragraph_found = FindInFlatFile (ffp->input_entityID, ffp->input_itemID,
3829                   ffp->input_itemtype, GENBANK_FMT, SEQUIN_MODE,
3830                   findme, caseCounts, wholeWord, TRUE, -1);
3831   MemFree (findme);
3832 }
3833 
3834 static void FindFlatProcNext (ButtoN b)
3835 
3836 {
3837   Boolean      caseCounts;
3838   FindFormPtr  ffp;
3839   CharPtr      findme;
3840   Boolean      wholeWord;
3841 
3842   ffp = (FindFormPtr) GetObjectExtra (b);
3843   if (ffp == NULL) return;
3844   findme = SaveStringFromText (ffp->findTxt);
3845   ObjMgrDeSelect (0, 0, 0, 0, NULL);
3846   caseCounts = GetStatus (ffp->caseCounts);
3847   wholeWord = GetStatus (ffp->wholeWord);
3848   CompressSpaces (findme);
3849   ffp->last_paragraph_found = FindInFlatFile (ffp->input_entityID, ffp->input_itemID,
3850                   ffp->input_itemtype, GENBANK_FMT, SEQUIN_MODE,
3851                   findme, caseCounts, wholeWord, TRUE, ffp->last_paragraph_found);
3852   MemFree (findme);
3853 }
3854 
3855 static void FindTextProc (TexT t)
3856 
3857 {
3858   FindFormPtr  ffp;
3859 
3860   ffp = (FindFormPtr) GetObjectExtra (t);
3861   if (ffp != NULL) {
3862     if (TextLength (t) > 0) {
3863       SafeEnable (ffp->findAllBtn);
3864       SafeEnable (ffp->replaceAllBtn);
3865       if (ffp->type == FIND_FLAT) {
3866         SafeEnable (ffp->findFirstBtn);
3867         SafeEnable (ffp->findNextBtn);
3868       }
3869       if (ffp->type == FIND_GENE || ffp->type == FIND_PROT) {
3870         SafeEnable (ffp->findFirstBtn);
3871       }
3872     } else {
3873       SafeDisable (ffp->findAllBtn);
3874       SafeDisable (ffp->replaceAllBtn);
3875       if (ffp->type == FIND_FLAT) {
3876         SafeDisable (ffp->findFirstBtn);
3877         SafeDisable (ffp->findNextBtn);
3878       }
3879       if (ffp->type == FIND_GENE || ffp->type == FIND_PROT) {
3880         SafeDisable (ffp->findFirstBtn);
3881       }
3882     }
3883   }
3884 }
3885 
3886 static void CommonFindReplaceProc (ButtoN b, Boolean replace, Boolean replaceAll)
3887 
3888 {
3889   Boolean      caseCounts;
3890   CharPtr      changeme;
3891   Boolean      doSeqIdLocal;
3892   FindFormPtr  ffp;
3893   CharPtr      findme;
3894   Boolean      wholeWord;
3895 
3896   ffp = (FindFormPtr) GetObjectExtra (b);
3897   if (ffp != NULL) {
3898     findme = JustSaveStringFromText (ffp->findTxt);
3899     ObjMgrDeSelect (0, 0, 0, 0, NULL);
3900     caseCounts = GetStatus (ffp->caseCounts);
3901     wholeWord = GetStatus (ffp->wholeWord);
3902     doSeqIdLocal = GetStatus (ffp->doSeqIdLocal);
3903     if (replace) {
3904       changeme = JustSaveStringFromText (ffp->replaceTxt);
3905       FindReplaceInEntity (ffp->input_entityID, findme, changeme, caseCounts, wholeWord, replaceAll,
3906                            FALSE, UPDATE_ONCE, NULL, NULL, NULL, doSeqIdLocal, NULL, NULL);
3907       GetRidOfEmptyFeatsDescStrings (ffp->input_entityID, NULL);
3908       ObjMgrSetDirtyFlag (ffp->input_entityID, TRUE);
3909       ObjMgrSendMsg (OM_MSG_UPDATE, ffp->input_entityID, 0, 0);
3910       MemFree (changeme);
3911     } else {
3912       FindReplaceInEntity (ffp->input_entityID, findme, NULL, caseCounts, wholeWord, FALSE,
3913                            TRUE, UPDATE_ONCE, NULL, NULL, NULL, doSeqIdLocal, NULL, NULL);
3914     }
3915     MemFree (findme);
3916     Update ();
3917   }
3918 }
3919 
3920 static void FindAllProc (ButtoN b)
3921 
3922 {
3923   CommonFindReplaceProc (b, FALSE, FALSE);
3924 }
3925 
3926 static void ReplaceAllProc (ButtoN b)
3927 
3928 {
3929   CommonFindReplaceProc (b, TRUE, TRUE);
3930 }
3931 
3932 static SeqFeatPtr 
3933 FindNthFeatureOnBspByLabel 
3934 (BioseqPtr              bsp,
3935  CharPtr                label,
3936  Uint1                  seqFeatChoice,
3937  Uint1                  featDefChoice,
3938  Int4                   n,
3939  Int4 PNTR              last_found,
3940  SeqMgrFeatContext PNTR context)
3941 {
3942   SMFeatItemPtr PNTR  array;
3943   BioseqExtraPtr      bspextra;
3944   Uint2               entityID;
3945   SMFeatItemPtr       feat;
3946   Int4                L;
3947   Int4                mid;
3948   Int4                num;
3949   ObjMgrDataPtr       omdp;
3950   Int4                R;
3951   SeqFeatPtr          sfp;
3952   Uint1               seqfeattype;
3953   Int4                index = 0;
3954 
3955   if (context != NULL) {
3956     MemSet ((Pointer) context, 0, sizeof (SeqMgrFeatContext));
3957   }
3958   if (last_found != NULL) {
3959     *last_found = -1;
3960   }
3961 
3962   if (bsp == NULL || StringHasNoText (label)) return NULL;
3963 
3964   omdp = SeqMgrGetOmdpForBioseq (bsp);
3965   if (omdp == NULL || omdp->datatype != OBJ_BIOSEQ) return NULL;
3966 
3967   bspextra = (BioseqExtraPtr) omdp->extradata;
3968   if (bspextra == NULL) return NULL;
3969   array = bspextra->featsByLabel;
3970   num = bspextra->numfeats;
3971 
3972   if (array == NULL || num < 1) return NULL;
3973 
3974   if (n < 0 || n > bspextra->numfeats) return NULL;
3975 
3976   entityID = ObjMgrGetEntityIDForPointer (omdp->dataptr);
3977 
3978   /* binary search to leftmost candidate within the featsByLabel array */
3979 
3980   L = 0;
3981   R = num - 1;
3982   while (L < R) {
3983     mid = (L + R) / 2;
3984     feat = array [mid];
3985     if (feat != NULL && StringICmp (feat->label, label) < 0) {
3986       L = mid + 1;
3987     } else {
3988       R = mid;
3989     }
3990   }
3991 
3992   feat = array [R];
3993 
3994   /* linear scan to find desired label on desired feature type */
3995 
3996   while (R < num && feat != NULL && StringICmp (feat->label, label) == 0) {
3997     sfp = feat->sfp;
3998     if (sfp != NULL) {
3999       seqfeattype = sfp->data.choice;
4000       if ((seqFeatChoice == 0 || seqfeattype == seqFeatChoice) &&
4001           (featDefChoice == 0 || feat->subtype == featDefChoice) &&
4002           (! feat->ignore)) {
4003         if (context != NULL) {
4004           context->entityID = entityID;
4005           context->itemID = feat->itemID;
4006           context->sfp = sfp;
4007           context->sap = feat->sap;
4008           context->bsp = feat->bsp;
4009           context->label = feat->label;
4010           context->left = feat->left;
4011           context->right = feat->right;
4012           context->dnaStop = feat->dnaStop;
4013           context->partialL = feat->partialL;
4014           context->partialR = feat->partialR;
4015           context->farloc = feat->farloc;
4016           context->strand = feat->strand;
4017           context->seqfeattype = seqfeattype;
4018           context->featdeftype = feat->subtype;
4019           context->numivals = feat->numivals;
4020           context->ivals = feat->ivals;
4021           context->userdata = NULL;
4022           context->omdp = (Pointer) omdp;
4023           context->index = R + 1;
4024         }
4025         if (index == n) {
4026           if (last_found != NULL) {
4027             *last_found = index;
4028           }
4029           return sfp;
4030         } else {
4031           if (last_found != NULL) {
4032             *last_found = index;
4033           }
4034           index++;
4035         }
4036       }
4037     }
4038 
4039     R++;
4040     feat = array [R];
4041   }
4042 
4043   return NULL;
4044 }
4045 
4046 typedef struct findnthfeatdata {
4047   CharPtr                findme;
4048   Uint1                  seqFeatChoice;
4049   Uint1                  featDefChoice;
4050   Int4                   n;
4051   Int4                   passed_so_far;
4052   SeqMgrFeatContext PNTR context;
4053   SeqFeatPtr             sfp;
4054 } FindNthFeatData, PNTR FindNthFeatPtr;
4055 
4056 static void FindNthFeatureByLabelInSeqEntryBspProc (BioseqPtr bsp, Pointer userdata)
4057 {
4058   FindNthFeatPtr fnfp;
4059   Int4           this_search_index;
4060   Int4           passed_this_bsp = 0;
4061 
4062   if (bsp == NULL || (fnfp = (FindNthFeatPtr)userdata) == NULL
4063       || fnfp->sfp != NULL) {
4064     return;
4065   }
4066 
4067   this_search_index = fnfp->n - fnfp->passed_so_far;
4068 
4069   if (fnfp->seqFeatChoice == SEQFEAT_GENE || fnfp->featDefChoice == FEATDEF_GENE) {  
4070     fnfp->sfp = FindNthGeneOnBspByLabelOrLocusTag (bsp,
4071                                                    fnfp->findme,
4072                                                    this_search_index,
4073                                                    &passed_this_bsp,
4074                                                    fnfp->context);
4075   } else {
4076     fnfp->sfp = FindNthFeatureOnBspByLabel (bsp,
4077                                             fnfp->findme,
4078                                             fnfp->seqFeatChoice,
4079                                             fnfp->featDefChoice,
4080                                             this_search_index,
4081                                             &passed_this_bsp,
4082                                             fnfp->context);
4083   }
4084   if (fnfp->sfp == NULL) {
4085     fnfp->passed_so_far += passed_this_bsp;
4086   }
4087 }
4088 
4089 static SeqFeatPtr FindNthFeatureByLabelInSeqEntry
4090 (SeqEntryPtr            sep,
4091  CharPtr                findme,
4092  Uint1                  seqFeatChoice,
4093  Uint1                  featDefChoice,
4094  Int4                   n,
4095  SeqMgrFeatContext PNTR context)
4096 {
4097   FindNthFeatData fnf;
4098   
4099   fnf.findme = findme;
4100   fnf.seqFeatChoice = seqFeatChoice;
4101   fnf.featDefChoice = featDefChoice;
4102   fnf.n = n;
4103   fnf.context = context;
4104   fnf.passed_so_far = 0;
4105   fnf.sfp = NULL;
4106 
4107   VisitBioseqsInSep (sep, &fnf, FindNthFeatureByLabelInSeqEntryBspProc);
4108 
4109   return fnf.sfp;
4110 }
4111 
4112 static void FindByLabelOrPosProc (ButtoN b)
4113 
4114 {
4115   Boolean            already;
4116   BioseqPtr          bsp = NULL;
4117   SeqMgrFeatContext  context;
4118   FindFormPtr        ffp;
4119   CharPtr            findme;
4120   SelStructPtr       sel;
4121   SeqEntryPtr        sep = NULL;
4122   SeqFeatPtr         sfp = NULL;
4123   Int4               val;
4124 
4125   ffp = (FindFormPtr) GetObjectExtra (b);
4126   if (ffp == NULL) return;
4127 
4128   if (ffp->input_itemID == 0) {
4129     sep = GetTopSeqEntryForEntityID (ffp->input_entityID);
4130   } else {
4131     bsp = GetBioseqGivenIDs (ffp->input_entityID, ffp->input_itemID, ffp->input_itemtype);
4132     if (bsp == NULL) return;
4133     sep = SeqMgrGetSeqEntryForData (bsp);
4134     if (bsp->repr == Seq_repr_seg) {
4135       sep = GetBestTopParentForData (ffp->input_entityID, bsp);
4136     }
4137   }
4138   if (sep == NULL) return;
4139 
4140   findme = SaveStringFromText (ffp->findTxt);
4141   ObjMgrDeSelect (0, 0, 0, 0, NULL);
4142   CompressSpaces (findme);
4143 
4144   switch (ffp->type) {
4145     case FIND_GENE :
4146       sfp = FindNthFeatureByLabelInSeqEntry (sep, findme, SEQFEAT_GENE, 0,
4147                                              ffp->last_paragraph_found + 1,
4148                                              &context);
4149       if (sfp == NULL) {
4150         if (ffp->last_paragraph_found > -1) {
4151           Message (MSG_OK, "No more found");
4152         } else {
4153           Message (MSG_OK, "No matches found");
4154         }
4155         ffp->last_paragraph_found = -1;
4156       } else {
4157         ffp->last_paragraph_found ++;
4158       }
4159       break;
4160     case FIND_PROT :
4161       sfp = FindNthFeatureByLabelInSeqEntry (sep, findme, SEQFEAT_CDREGION, 0,
4162                                              ffp->last_paragraph_found + 1,
4163                                              &context);
4164       if (sfp == NULL) {
4165         ffp->last_paragraph_found = -1;
4166       } else {
4167         ffp->last_paragraph_found ++;
4168       }
4169       break;
4170     case FIND_POS :
4171       if (StrToLong (findme, &val)) {
4172         if (val > 0 && val <= bsp->length) {
4173           val--;
4174           sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &context);
4175           while (sfp != NULL) {
4176             if (context.left >= val) break;
4177             sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &context);
4178           }
4179         }
4180       }
4181       break;
4182     default :
4183       break;
4184   }
4185 
4186   MemFree (findme);
4187 
4188   if (sfp == NULL) return;
4189 
4190   already = FALSE;
4191   for (sel = ObjMgrGetSelected (); sel != NULL; sel = sel->next) {
4192     if (sel->entityID == context.entityID &&
4193         sel->itemID == context.itemID &&
4194         sel->itemtype == OBJ_SEQFEAT) {
4195       already = TRUE;
4196     }
4197   }
4198   if (! already) {
4199     ObjMgrAlsoSelect (context.entityID, context.itemID, OBJ_SEQFEAT, 0, NULL);
4200   }
4201 
4202 }
4203 
4204 static void FindByLabelOrPosProcFindFirst (ButtoN b)
4205 {
4206   FindFormPtr ffp;
4207 
4208   ffp = (FindFormPtr) GetObjectExtra (b);
4209   if (ffp == NULL) return;
4210   ffp->last_paragraph_found = -1;
4211   FindByLabelOrPosProc (b);
4212 }
4213 
4214 static void ClearFindTextProc (ButtoN b)
4215 
4216 {
4217   FindFormPtr  ffp;
4218 
4219   ffp = (FindFormPtr) GetObjectExtra (b);
4220   if (ffp == NULL) return;
4221   SafeSetTitle (ffp->findTxt, "");
4222   SafeSetTitle (ffp->replaceTxt, "");
4223   if (ffp->type == FIND_FLAT) {
4224     ObjMgrDeSelect (0, 0, 0, 0, NULL);
4225     ffp->last_paragraph_found = -1;
4226   }
4227   FindTextProc (ffp->findTxt);
4228   Select (ffp->findTxt);
4229 }
4230 
4231 static void FindFormMessage (ForM f, Int2 mssg)
4232 
4233 {
4234   FindFormPtr  ffp;
4235 
4236   ffp = (FindFormPtr) GetObjectExtra (f);
4237   if (ffp != NULL) {
4238     switch (mssg) {
4239       case VIB_MSG_CLOSE :
4240         Remove (f);
4241         break;
4242       case VIB_MSG_CUT :
4243         StdCutTextProc (NULL);
4244         break;
4245       case VIB_MSG_COPY :
4246         StdCopyTextProc (NULL);
4247         break;
4248       case VIB_MSG_PASTE :
4249         StdPasteTextProc (NULL);
4250         break;
4251       case VIB_MSG_DELETE :
4252         StdDeleteTextProc (NULL);
4253         break;
4254       default :
4255         if (ffp->appmessage != NULL) {
4256           ffp->appmessage (f, mssg);
4257         }
4258         break;
4259     }
4260   }
4261 }
4262 
4263 static void CopyFindReplBtn (ButtoN b)
4264 {
4265   FindFormPtr ffp;
4266   CharPtr     str;
4267   
4268   ffp = (FindFormPtr) GetObjectExtra (b); 
4269   if (ffp == NULL)
4270   {
4271     return;
4272   }
4273   str = JustSaveStringFromText (ffp->findTxt);
4274   SetTitle (ffp->replaceTxt, str);
4275   str = MemFree (str);
4276 }
4277 
4278 static ForM CreateFindForm (Int2 left, Int2 top, CharPtr title,
4279                             Uint2 entityID, Uint4 itemID, Uint2 itemtype,
4280                             Int2 type)
4281 
4282 {
4283   ButtoN             b;
4284   GrouP              c;
4285   GrouP              g;
4286   FindFormPtr        ffp;
4287   GrouP              j;
4288   GrouP              q = NULL;
4289   StdEditorProcsPtr  sepp;
4290   WindoW             w;
4291 
4292   w = NULL;
4293   ffp = MemNew (sizeof (FindForm));
4294   if (ffp != NULL) {
4295     w = FixedWindow (left, top, -10, -10, title, StdCloseWindowProc);
4296     SetObjectExtra (w, ffp, StdCleanupFormProc);
4297     ffp->form = (ForM) w;
4298     ffp->formmessage = FindFormMessage;
4299     ffp->input_entityID = entityID;
4300     ffp->input_itemID = itemID;
4301     ffp->input_itemtype = itemtype;
4302     ffp->type = type;
4303     ffp->last_paragraph_found = -1;
4304 
4305 #ifndef WIN_MAC
4306     CreateStdEditorFormMenus (w);
4307 #endif
4308 
4309     sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
4310     if (sepp != NULL) {
4311       SetActivate (w, sepp->activateForm);
4312       ffp->appmessage = sepp->handleMessages;
4313     }
4314 
4315     j = HiddenGroup (w, -1, 0, NULL);
4316     SetGroupSpacing (j, 10, 10);
4317 
4318     g = HiddenGroup (j, 3, 0, NULL);
4319     StaticPrompt (g, "Find", 0, dialogTextHeight, programFont, 'l');
4320     ffp->findTxt = DialogText (g, "", 25, FindTextProc);
4321     SetObjectExtra (ffp->findTxt, ffp, NULL);
4322     StaticPrompt (g, "", 0, 0, programFont, 'l');
4323     if (type == FIND_ASN) {
4324       StaticPrompt (g, "Replace", 0, dialogTextHeight, programFont, 'l');
4325       ffp->replaceTxt = DialogText (g, "", 25, NULL);
4326       SetObjectExtra (ffp->replaceTxt, ffp, NULL);
4327       b = PushButton (g, "Copy", CopyFindReplBtn);
4328       SetObjectExtra (b, ffp, NULL);
4329     }
4330 
4331     if (type == FIND_ASN || type == FIND_FLAT) {
4332       q = HiddenGroup (w, 3, 0, NULL);
4333       ffp->caseCounts = CheckBox (q, "Case Sensitive", NULL);
4334       ffp->wholeWord = CheckBox (q, "Entire Word", NULL);
4335       if (indexerVersion && type == FIND_ASN) {
4336         ffp->doSeqIdLocal = CheckBox (q, "SeqID LOCAL", NULL);
4337       }
4338     }
4339 
4340     c = HiddenGroup (w, 5, 0, NULL);
4341     SetGroupSpacing (c, 10, 2);
4342     if (type == FIND_ASN) {
4343       ffp->findAllBtn = DefaultButton (c, "Find All", FindAllProc);
4344       SetObjectExtra (ffp->findAllBtn, ffp, NULL);
4345       Disable (ffp->findAllBtn);
4346       ffp->replaceAllBtn = PushButton (c, "Replace All", ReplaceAllProc);
4347       SetObjectExtra (ffp->replaceAllBtn, ffp, NULL);
4348       Disable (ffp->replaceAllBtn);
4349     } else if (type == FIND_FLAT) {
4350       ffp->findFirstBtn = PushButton (c, "Find First", FindFlatProcFirst);
4351       SetObjectExtra (ffp->findFirstBtn, ffp, NULL);
4352       Disable (ffp->findFirstBtn);
4353       ffp->findNextBtn = PushButton (c, "Find Next", FindFlatProcNext);
4354       SetObjectExtra (ffp->findNextBtn, ffp, NULL);
4355       Disable (ffp->findNextBtn);
4356       ffp->findAllBtn = DefaultButton (c, "Find All", FindFlatProc);
4357       SetObjectExtra (ffp->findAllBtn, ffp, NULL);
4358       Disable (ffp->findAllBtn);
4359     } else if (type == FIND_GENE) {
4360       ffp->findFirstBtn = DefaultButton (c, "Find First Gene", FindByLabelOrPosProcFindFirst);
4361       SetObjectExtra (ffp->findFirstBtn, ffp, NULL);
4362       Disable (ffp->findFirstBtn);
4363       ffp->findAllBtn = PushButton (c, "Find Next Gene", FindByLabelOrPosProc);
4364       SetObjectExtra (ffp->findAllBtn, ffp, NULL);
4365       Disable (ffp->findAllBtn);
4366     } else if (type == FIND_PROT) {
4367      ffp->findFirstBtn = DefaultButton (c, "Find First Protein", FindByLabelOrPosProcFindFirst);
4368       SetObjectExtra (ffp->findFirstBtn, ffp, NULL);
4369       Disable (ffp->findFirstBtn);
4370       ffp->findAllBtn = PushButton (c, "Find Next Protein", FindByLabelOrPosProc);
4371       SetObjectExtra (ffp->findAllBtn, ffp, NULL);
4372       Disable (ffp->findAllBtn);
4373     } else if (type == FIND_POS) {
4374       ffp->findAllBtn = DefaultButton (c, "Find by Position", FindByLabelOrPosProc);
4375       SetObjectExtra (ffp->findAllBtn, ffp, NULL);
4376       Disable (ffp->findAllBtn);
4377     }
4378     b = PushButton (c, "Clear", ClearFindTextProc);
4379     SetObjectExtra (b, ffp, NULL);
4380     PushButton (c, "Cancel", StdCancelButtonProc);
4381 
4382     AlignObjects (ALIGN_CENTER, (HANDLE) j, (HANDLE) c, (HANDLE) q, NULL);
4383 
4384     RealizeWindow (w);
4385     Select (ffp->findTxt);
4386   }
4387   return (ForM) w;
4388 }
4389 
4390 extern void FindStringProc (IteM i)
4391 
4392 {
4393   BaseFormPtr  bfp;
4394   ForM         w;
4395 
4396 #ifdef WIN_MAC
4397   bfp = currentFormDataPtr;
4398 #else
4399   bfp = GetObjectExtra (i);
4400 #endif
4401   if (bfp != NULL) {
4402     w = CreateFindForm (-90, -66, "Find", bfp->input_entityID,
4403                         bfp->input_itemID, bfp->input_itemtype, FIND_ASN);
4404     Show (w);
4405     Select (w);
4406   }
4407 }
4408 
4409 extern void FindStringProcToolBtn (ButtoN b)
4410 
4411 {
4412   BaseFormPtr  bfp;
4413   ForM         w;
4414 
4415   bfp = (BaseFormPtr) GetObjectExtra (b);
4416   if (bfp == NULL) return;
4417 
4418   w = CreateFindForm (-90, -66, "Find", bfp->input_entityID,
4419                       bfp->input_itemID, bfp->input_itemtype, FIND_ASN);
4420   Show (w);
4421   Select (w);
4422 
4423 }
4424 
4425 
4426 extern void FindFlatfileProcToolBtn (ButtoN b)
4427 
4428 {
4429   BaseFormPtr  bfp;
4430   ForM         w;
4431 
4432   bfp = (BaseFormPtr) GetObjectExtra (b);
4433   if (bfp == NULL) return;
4434 
4435   w = CreateFindForm (-90, -66, "Flat File Find", bfp->input_entityID,
4436                       bfp->input_itemID, bfp->input_itemtype, FIND_FLAT);
4437   Show (w);
4438   Select (w);
4439 
4440 }
4441 
4442 
4443 extern void FindFlatfileProc (IteM i)
4444 
4445 {
4446   BaseFormPtr  bfp;
4447   ForM         w;
4448 
4449 #ifdef WIN_MAC
4450   bfp = currentFormDataPtr;
4451 #else
4452   bfp = GetObjectExtra (i);
4453 #endif
4454   if (bfp != NULL) {
4455     w = CreateFindForm (-90, -66, "Flat File Find", bfp->input_entityID,
4456                         bfp->input_itemID, bfp->input_itemtype, FIND_FLAT);
4457     Show (w);
4458     Select (w);
4459   }
4460 }
4461 
4462 extern void FindGeneProc (IteM i)
4463 
4464 {
4465   BaseFormPtr  bfp;
4466   ForM         w;
4467 
4468 #ifdef WIN_MAC
4469   bfp = currentFormDataPtr;
4470 #else
4471   bfp = GetObjectExtra (i);
4472 #endif
4473   if (bfp != NULL) {
4474     w = CreateFindForm (-90, -66, "Find", bfp->input_entityID,
4475                         bfp->input_itemID, bfp->input_itemtype, FIND_GENE);
4476     Show (w);
4477     Select (w);
4478   }
4479 }
4480 
4481 extern void FindProtProc (IteM i)
4482 
4483 {
4484   BaseFormPtr  bfp;
4485   ForM         w;
4486 
4487 #ifdef WIN_MAC
4488   bfp = currentFormDataPtr;
4489 #else
4490   bfp = GetObjectExtra (i);
4491 #endif
4492   if (bfp != NULL) {
4493     w = CreateFindForm (-90, -66, "Find", bfp->input_entityID,
4494                         bfp->input_itemID, bfp->input_itemtype, FIND_PROT);
4495     Show (w);
4496     Select (w);
4497   }
4498 }
4499 
4500 extern void FindPosProc (IteM i)
4501 
4502 {
4503   BaseFormPtr  bfp;
4504   ForM         w;
4505 
4506 #ifdef WIN_MAC
4507   bfp = currentFormDataPtr;
4508 #else
4509   bfp = GetObjectExtra (i);
4510 #endif
4511   if (bfp != NULL) {
4512     w = CreateFindForm (-90, -66, "Find", bfp->input_entityID,
4513                         bfp->input_itemID, bfp->input_itemtype, FIND_POS);
4514     Show (w);
4515     Select (w);
4516   }
4517 }
4518 
4519 static void RemoveRedundantSourceNote (CharPtr str, CharPtr keyword, CharPtr name)
4520 
4521 {
4522   Char     ch;
4523   Boolean  extract;
4524   CharPtr  tmp1, tmp2;
4525 
4526   if (str == NULL || keyword == NULL || name == NULL) return;
4527   while (str != NULL && *str != '\0') {
4528     extract = TRUE;
4529     tmp1 = str;
4530     ch = *tmp1;
4531     while (ch == ' ' || ch == ';') {
4532       tmp1++;
4533       ch = *tmp1;
4534     }
4535     tmp2 = keyword;
4536     ch = TO_UPPER (*tmp1);
4537     while (ch != '\0' && ch == TO_UPPER (*tmp2)) {
4538       tmp1++;
4539       tmp2++;
4540       ch = TO_UPPER (*tmp1);
4541     }
4542     if (*tmp2 == '\0' && ch == ' ') {
4543       while (ch != '\0' && ch == ' ') {
4544         tmp1++;
4545         ch = *tmp1;
4546       }
4547       tmp2 = name;
4548       while (ch != '\0' && ch == *tmp2) {
4549         tmp1++;
4550         tmp2++;
4551         ch = *tmp1;
4552       }
4553       if (*tmp2 == '\0' && (ch == '\0' || ch == ' ' || ch == ';')) {
4554         while (ch != '\0' && ch == ' ') {
4555           tmp1++;
4556           ch = *tmp1;
4557         }
4558         /* now ready to extract */
4559       } else {
4560         extract = FALSE;
4561       }
4562     } else {
4563       extract = FALSE;
4564     }
4565     if (extract) {
4566       while (ch == ' ' || ch == ';') {
4567         tmp1++;
4568         ch = *tmp1;
4569       }
4570       tmp2 = str;
4571       while (ch != '\0') {
4572         *tmp2 = ch;
4573         tmp1++;
4574         tmp2++;
4575         ch = *tmp1;
4576       }
4577       *tmp2 = '\0';
4578     } else {
4579       ch = *tmp1;
4580       while (ch != '\0' && ch != ';') {
4581         tmp1++;
4582         ch = *tmp1;
4583       }
4584       if (ch == ';') {
4585         tmp1++;
4586         ch = *tmp1;
4587       }
4588       while (ch != '\0' && (ch == ' ' || ch == ';')) {
4589         tmp1++;
4590         ch = *tmp1;
4591       }
4592       str = tmp1;
4593     }
4594   }
4595 }
4596 
4597 static CharPtr TrimSpacesAndSemicolonsAroundString (CharPtr str)
4598 
4599 {
4600   Uchar    ch;  /* to use 8bit characters in multibyte languages */
4601   CharPtr  dst;
4602   CharPtr  ptr;
4603 
4604   if (str != NULL && str [0] != '\0') {
4605     dst = str;
4606     ptr = str;
4607     ch = *ptr;
4608     while (ch != '\0' && (ch <= ' ' || ch == ';')) {
4609       ptr++;
4610       ch = *ptr;
4611     }
4612     while (ch != '\0') {
4613       *dst = ch;
4614       dst++;
4615       ptr++;
4616       ch = *ptr;
4617     }
4618     *dst = '\0';
4619     dst = NULL;
4620     ptr = str;
4621     ch = *ptr;
4622     while (ch != '\0') {
4623       if (ch != ' ' && ch != ';') {
4624         dst = NULL;
4625       } else if (dst == NULL) {
4626         dst = ptr;
4627       }
4628       ptr++;
4629       ch = *ptr;
4630     }
4631     if (dst != NULL) {
4632       *dst = '\0';
4633     }
4634   }
4635   return str;
4636 }
4637 
4638 extern void GetRidOfRedundantSourceNotes (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent);
4639 extern void GetRidOfRedundantSourceNotes (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
4640 
4641 {
4642   BioSourcePtr       biop;
4643   BioseqPtr          bsp;
4644   BioseqSetPtr       bssp;
4645   OrgModPtr          mod;
4646   OrgNamePtr         onp;
4647   OrgRefPtr          orp;
4648   ValNodePtr         sdp;
4649   SubSourcePtr       ssp;
4650   CharPtr            str1, str2;
4651 
4652   if (sep == NULL || sep->data.ptrvalue == NULL) return;
4653   if (IS_Bioseq (sep)) {
4654     bsp = (BioseqPtr) sep->data.ptrvalue;
4655     sdp = bsp->descr;
4656   } else if (IS_Bioseq_set (sep)) {
4657     bssp = (BioseqSetPtr) sep->data.ptrvalue;
4658     sdp = bssp->descr;
4659   } else return;
4660   while (sdp != NULL) {
4661     if (sdp->choice == Seq_descr_source) {
4662       str1 = NULL;
4663       str2 = NULL;
4664       onp = NULL;
4665       biop = (BioSourcePtr) sdp->data.ptrvalue;
4666       if (biop != NULL) {
4667         orp = biop->org;
4668         if (orp != NULL) {
4669           onp = orp->orgname;
4670           if (onp != NULL) {
4671             mod = onp->mod;
4672             while (mod != NULL) {
4673               if (mod->subtype == 255) {
4674                 str1 = mod->subname;
4675               }
4676               mod = mod->next;
4677             }
4678           }
4679         }
4680         ssp = biop->subtype;
4681         while (ssp != NULL) {
4682           if (ssp->subtype == 255) {
4683             str2 = ssp->name;
4684           }
4685           ssp = ssp->next;
4686         }
4687         if (str1 != NULL || str2 != NULL) {
4688           if (onp != NULL) {
4689             mod = onp->mod;
4690             while (mod != NULL) {
4691               if (mod->subtype != 255) {
4692                 RemoveRedundantSourceNote (str1, GetOrgModQualName (mod->subtype), mod->subname);
4693                 RemoveRedundantSourceNote (str2, GetOrgModQualName (mod->subtype), mod->subname);
4694               }
4695               mod = mod->next;
4696             }
4697           }
4698           ssp = biop->subtype;
4699           while (ssp != NULL) {
4700             if (ssp->subtype != 255) {
4701               RemoveRedundantSourceNote (str1, GetSubsourceQualName (ssp->subtype), ssp->name);
4702               RemoveRedundantSourceNote (str2, GetSubsourceQualName (ssp->subtype), ssp->name);
4703             }
4704             ssp = ssp->next;
4705           }
4706         }
4707       }
4708       TrimSpacesAndSemicolonsAroundString (str1);
4709       TrimSpacesAndSemicolonsAroundString (str2);
4710     }
4711     sdp = sdp->next;
4712   }
4713 }
4714 
4715 typedef struct convaccdata {
4716   CharPtr        currID;
4717   CharPtr        newID;
4718 } ConvAccData, PNTR ConvAccPtr;
4719 
4720 static void ChangeSeqIdListToAccLocalID (SeqIdPtr sip, CharPtr currID, CharPtr newID)
4721 
4722 {
4723   ObjectIdPtr   oip;
4724 
4725   while (sip != NULL) {
4726     switch (sip->choice) {
4727       case SEQID_LOCAL :
4728         oip = (ObjectIdPtr) sip->data.ptrvalue;
4729         if (oip != NULL) {
4730           if (StringCmp (oip->str, currID) == 0) {
4731             MemFree (oip->str);
4732             oip->str = StringSave (newID);
4733           }
4734         }
4735         break;
4736       default :
4737         break;
4738     }
4739     sip = sip->next;
4740   }
4741 }
4742 
4743 static void ChangeSeqLocListToAccLocalID (SeqLocPtr slp, CharPtr currID, CharPtr newID)
4744 
4745 {
4746   SeqLocPtr      loc;
4747   PackSeqPntPtr  psp;
4748   SeqBondPtr     sbp;
4749   SeqIntPtr      sinp;
4750   SeqIdPtr       sip;
4751   SeqPntPtr      spp;
4752 
4753   while (slp != NULL) {
4754     switch (slp->choice) {
4755       case SEQLOC_NULL :
4756         break;
4757       case SEQLOC_EMPTY :
4758       case SEQLOC_WHOLE :
4759         sip = (SeqIdPtr) slp->data.ptrvalue;
4760         ChangeSeqIdListToAccLocalID (sip, currID, newID);
4761         break;
4762       case SEQLOC_INT :
4763         sinp = (SeqIntPtr) slp->data.ptrvalue;
4764         if (sinp != NULL) {
4765           sip = sinp->id;
4766           ChangeSeqIdListToAccLocalID (sip, currID, newID);
4767         }
4768         break;
4769       case SEQLOC_PNT :
4770         spp = (SeqPntPtr) slp->data.ptrvalue;
4771         if (spp != NULL) {
4772           sip = spp->id;
4773           ChangeSeqIdListToAccLocalID (sip, currID, newID);
4774         }
4775         break;
4776       case SEQLOC_PACKED_PNT :
4777         psp = (PackSeqPntPtr) slp->data.ptrvalue;
4778         if (psp != NULL) {
4779           sip = psp->id;
4780           ChangeSeqIdListToAccLocalID (sip, currID, newID);
4781         }
4782         break;
4783       case SEQLOC_PACKED_INT :
4784       case SEQLOC_MIX :
4785       case SEQLOC_EQUIV :
4786         loc = (SeqLocPtr) slp->data.ptrvalue;
4787         while (loc != NULL) {
4788           ChangeSeqIdListToAccLocalID (loc, currID, newID);
4789           loc = loc->next;
4790         }
4791         break;
4792       case SEQLOC_BOND :
4793         sbp = (SeqBondPtr) slp->data.ptrvalue;
4794         if (sbp != NULL) {
4795           spp = (SeqPntPtr) sbp->a;
4796           if (spp != NULL) {
4797             sip = spp->id;
4798             ChangeSeqIdListToAccLocalID (sip, currID, newID);
4799           }
4800           spp = (SeqPntPtr) sbp->b;
4801           if (spp != NULL) {
4802             sip = spp->id;
4803             ChangeSeqIdListToAccLocalID (sip, currID, newID);
4804           }
4805         }
4806         break;
4807       case SEQLOC_FEAT :
4808         break;
4809       default :
4810         break;
4811     }
4812     slp = slp->next;
4813   }
4814 }
4815 
4816 static void ChangeAlignListToAccLocalID (SeqAlignPtr align, CharPtr currID, CharPtr newID)
4817 
4818 {
4819   DenseDiagPtr  ddp;
4820   DenseSegPtr   dsp;
4821   StdSegPtr     ssp;
4822 
4823   if (align == NULL) return;
4824   if (align->segtype == 1) {
4825     ddp = (DenseDiagPtr) align->segs;
4826     if (ddp != NULL) {
4827       ChangeSeqIdListToAccLocalID (ddp->id, currID, newID);
4828     }
4829   } else if (align->segtype == 2) {
4830     dsp = (DenseSegPtr) align->segs;
4831     if (dsp != NULL) {
4832       ChangeSeqIdListToAccLocalID (dsp->ids, currID, newID);
4833     }
4834   } else if (align->segtype == 3) {
4835     ssp = (StdSegPtr) align->segs;
4836     if (ssp != NULL) {
4837        ChangeSeqLocListToAccLocalID (ssp->loc, currID, newID);
4838     }
4839   }
4840 }
4841 
4842 static void CopyAccToLocalCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
4843 
4844 {
4845   BioseqPtr     bsp;
4846   BioseqSetPtr  bssp;
4847   ConvAccPtr    cap;
4848   SeqAlignPtr   sal;
4849   SeqAnnotPtr   sap;
4850   SeqFeatPtr    sfp;
4851   SeqIdPtr      sip;
4852   SeqLocPtr     slp;
4853 
4854   if (sep == NULL || sep->data.ptrvalue == NULL) return;
4855   cap = (ConvAccPtr) mydata;
4856   if (cap == NULL) return;
4857   if (IS_Bioseq (sep)) {
4858     bsp = (BioseqPtr) sep->data.ptrvalue;
4859     sip = bsp->id;
4860     ChangeSeqIdListToAccLocalID (sip, cap->currID, cap->newID);
4861     SeqMgrReplaceInBioseqIndex (bsp);
4862     sap = bsp->annot;
4863   } else if (IS_Bioseq_set (sep)) {
4864     bssp = (BioseqSetPtr) sep->data.ptrvalue;
4865     sap = bssp->annot;
4866   } else return;
4867   while (sap != NULL) {
4868     if (sap->type == 1) {
4869       sfp = (SeqFeatPtr) sap->data;
4870       while (sfp != NULL) {
4871         slp = sfp->location;
4872         ChangeSeqLocListToAccLocalID (slp, cap->currID, cap->newID);
4873         slp = sfp->product;
4874         ChangeSeqLocListToAccLocalID (slp, cap->currID, cap->newID);
4875         sfp = sfp->next;
4876       }
4877     } else if (sap->type == 2) {
4878       sal = (SeqAlignPtr) sap->data;
4879       while (sal != NULL) {
4880         ChangeAlignListToAccLocalID (sal, cap->currID, cap->newID);
4881         sal = sal->next;
4882       }
4883     }
4884     sap = sap->next;
4885   }
4886 }
4887 
4888 static void RecordAccToConvert (ValNodePtr PNTR vnpp, BioseqPtr bsp, CharPtr newID)
4889 
4890 {
4891   ConvAccPtr   cap;
4892   ObjectIdPtr  oip;
4893   SeqIdPtr     sip;
4894 
4895   if (vnpp == NULL || bsp == NULL || StringHasNoText (newID)) return;
4896   for (sip = bsp->id; sip != NULL; sip = sip->next) {
4897     if (sip->choice == SEQID_LOCAL) {
4898       oip = (ObjectIdPtr) sip->data.ptrvalue;
4899       if (oip != NULL) {
4900         if (! StringHasNoText (oip->str)) {
4901           cap = (ConvAccPtr) MemNew (sizeof (ConvAccData));
4902           if (cap == NULL) return;
4903           cap->currID = StringSave (oip->str);
4904           cap->newID = StringSave (newID);
4905           ValNodeAddPointer (vnpp, 0, (Pointer) cap);
4906           return;
4907         }
4908       }
4909     }
4910   }
4911 }
4912 
4913 static Boolean IsLegalAccession (CharPtr acnum, Int2 i)
4914 
4915 {
4916   Int2  j;
4917 
4918   if (! isalpha ((Int4)(acnum [0]))) return FALSE;
4919   if (!(isdigit((Int4)(acnum[1])) && i == 6) && !(isalpha((Int4)(acnum[1])) && i == 8)) return FALSE;
4920   for (j = 2; j < i; j++) {
4921     if (!(isdigit((Int4)(acnum[j])))) return FALSE;
4922   }
4923   return TRUE;
4924 }
4925 
4926 static void FindAccInDefCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
4927 
4928 {
4929   Char         acnum [17];
4930   BioseqPtr    bsp;
4931   Int2         i;
4932   CharPtr      p;
4933   Char         str [128];
4934   ValNodePtr   ttl;
4935   ValNodePtr   PNTR vnpp;
4936 
4937   if (sep == NULL || sep->data.ptrvalue == NULL) return;
4938   if (! IS_Bioseq (sep)) return;
4939   vnpp = (ValNodePtr PNTR) mydata;
4940   if (vnpp == NULL) return;
4941   ttl = SeqEntryGetSeqDescr (sep, Seq_descr_title, NULL);
4942   while (ttl != NULL) {
4943     StringNCpy_0 (str, (CharPtr) ttl->data.ptrvalue, sizeof (str));
4944     TrimSpacesAroundString (str);
4945     if (! StringHasNoText (str)) {
4946       if (str [0] == 'a' && str [1] == 'c' && str [2] == 'c') {
4947         p = str + 3;
4948         for (i = 0; isalnum ((Int4)(*p)) && *p != '\0'; p++, i++) {
4949           acnum [i] = *p;
4950         }
4951         acnum [i] = '\0';
4952         if (i == 6 || i == 8) {
4953           if (IsLegalAccession (acnum, i)) {
4954             bsp = (BioseqPtr) sep->data.ptrvalue;
4955             RecordAccToConvert (vnpp, bsp, str);
4956           }
4957         }
4958       }
4959     }
4960     ttl = SeqEntryGetSeqDescr (sep, Seq_descr_title, ttl);
4961   }
4962 }
4963 
4964 static void ConvertAccInDefToLocalIdProc (SeqEntryPtr sep)
4965 
4966 {
4967   ConvAccPtr  cap;
4968   ValNodePtr  head;
4969   ValNodePtr  vnp;
4970 
4971   if (sep == NULL) return;
4972   head = NULL;
4973   SeqEntryExplore (sep, (Pointer) &head, FindAccInDefCallback);
4974   if (head == NULL) return;
4975   if (Message (MSG_YN, "Convert accLNNNNN or accLLNNNNNN in title to local ID?") == ANS_NO) return;
4976   for (vnp = head; vnp != NULL; vnp = vnp->next) {
4977     cap = (ConvAccPtr) vnp->data.ptrvalue;
4978     if (cap != NULL) {
4979       SeqEntryExplore (sep, (Pointer) cap, CopyAccToLocalCallback);
4980     }
4981   }
4982   for (vnp = head; vnp != NULL; vnp = vnp->next) {
4983     cap = (ConvAccPtr) vnp->data.ptrvalue;
4984     if (cap != NULL) {
4985       MemFree (cap->currID);
4986       MemFree (cap->newID);
4987       vnp->data.ptrvalue = MemFree (cap);
4988     }
4989   }
4990   ValNodeFree (head);
4991 }
4992 
4993 static Int2  taxonCount;
4994 
4995 static Int4 DoSeqEntryToAsn3 (SeqEntryPtr sep, Boolean strip, Boolean correct,
4996                               Boolean force, Boolean dotaxon, MonitorPtr mon)
4997 
4998 {
4999   BioseqSetPtr  bssp;
5000   SeqEntryPtr   oldscope;
5001   Int4          rsult;
5002   Char          str [32];
5003 
5004   rsult = 0;
5005   if (IS_Bioseq_set (sep)) {
5006     bssp = (BioseqSetPtr) sep->data.ptrvalue;
5007     if (bssp != NULL && (bssp->_class == 7 ||
5008                          (IsPopPhyEtcSet (bssp->_class)))) {
5009       for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
5010         rsult += DoSeqEntryToAsn3 (sep, strip, correct, force, dotaxon, mon);
5011       }
5012       return rsult;
5013     }
5014   }
5015 /*#ifdef USE_TAXON*/
5016   if (dotaxon && mon != NULL) {
5017     taxonCount++;
5018     sprintf (str, "Processing Component %d", (int) taxonCount);
5019     MonitorStrValue (mon, str);
5020   }
5021 /*#endif*/
5022 /*#ifdef INTERNAL_NCBI_SEQUIN*/
5023   if (indexerVersion) {
5024     if ((! force) && (! NoBiosourceOrTaxonId (sep))) return 0;
5025   } else {
5026 /*#else*/
5027     if ((! force) && SeqEntryGetSeqDescr (sep, Seq_descr_source, NULL) != NULL) return 0;
5028   }
5029 /*#endif*/
5030   oldscope = SeqEntrySetScope (sep);
5031   if (dotaxon) {
5032     rsult = SeqEntryToAsn3Ex (sep, strip, correct, TRUE, NULL, Tax3MergeSourceDescr, FALSE);
5033     DeleteMarkedObjects (0, OBJ_SEQENTRY, sep);
5034   } else {
5035     rsult = SeqEntryToAsn3Ex (sep, strip, correct, FALSE, NULL, NULL, FALSE);
5036   }
5037   SeqEntrySetScope (oldscope);
5038   return rsult;
5039 }
5040 
5041 /* CheckSeqAlignCallback copied from salsa.c */
5042 static void CheckSeqAlignCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
5043 {
5044   BioseqPtr          bsp;
5045   BioseqSetPtr       bssp;
5046   SeqAnnotPtr        sap,
5047                      pre;
5048 
5049   if (sep != NULL && sep->data.ptrvalue) {
5050      if (IS_Bioseq(sep)) {
5051         bsp = (BioseqPtr) sep->data.ptrvalue;
5052         if (bsp!=NULL) {
5053            pre=NULL;
5054            sap=bsp->annot;
5055            while (sap!= NULL)
5056            {
5057               if (sap->type == 2) {
5058                  if (is_dim1seqalign ((SeqAlignPtr) sap->data)) {
5059                     if (pre==NULL) {
5060                        bsp->annot=sap->next;
5061                        sap->next=NULL;
5062                        SeqAnnotFree (sap);
5063                        sap=bsp->annot; 
5064                     }
5065                     else {
5066                        pre->next=sap->next;
5067                        pre=sap->next;
5068                        sap->next=NULL; 
5069                        SeqAnnotFree (sap);
5070                        sap=pre;
5071                     }
5072                  }
5073                  else {
5074                     pre=sap;
5075                     sap=sap->next;
5076                  }
5077               }
5078               else {
5079                  pre=sap;
5080                  sap=sap->next;
5081               }
5082            }
5083         }
5084      }
5085      else if(IS_Bioseq_set(sep)) {
5086         bssp = (BioseqSetPtr)sep->data.ptrvalue;
5087         if (bssp!=NULL) {
5088            pre=NULL;
5089            sap=bssp->annot;
5090            while (sap!= NULL)
5091            {
5092               if (sap->type == 2) {
5093                  if (is_dim1seqalign ((SeqAlignPtr) sap->data)) {
5094                     if (pre==NULL) {
5095                        bssp->annot=sap->next;
5096                        sap->next=NULL;
5097                        SeqAnnotFree (sap);
5098                        sap=bssp->annot; 
5099                     }
5100                     else {
5101                        pre=sap->next;
5102                        sap->next=NULL; 
5103                        SeqAnnotFree (sap);
5104                        sap=sap->next;
5105                     }
5106                  }
5107                  else {
5108                     pre=sap;
5109                     sap=sap->next;
5110                  }
5111               }
5112               else {
5113                  pre=sap;
5114                  sap=sap->next;
5115               }
5116            }
5117         }
5118      }
5119   }
5120 }
5121 
5122 /* RemoveMultipleTitles currently removes FIRST title in chain */
5123 
5124 static void RemoveMultipleTitles (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
5125 
5126 {
5127   BioseqPtr      bsp;
5128   BioseqSetPtr   bssp;
5129   SeqDescrPtr    descr = NULL;
5130   SeqDescrPtr    lasttitle = NULL;
5131   ObjValNodePtr  ovp;
5132   SeqDescrPtr    sdp;
5133 
5134   if (IS_Bioseq (sep)) {
5135     bsp = (BioseqPtr) sep->data.ptrvalue;
5136     if (bsp == NULL) return;
5137     descr = bsp->descr;
5138   } else if (IS_Bioseq_set (sep)) {
5139     bssp = (BioseqSetPtr) sep->data.ptrvalue;
5140     if (bssp == NULL) return;
5141     descr = bssp->descr;
5142   } else return;
5143   for (sdp = descr; sdp != NULL; sdp = sdp->next) {
5144     if (sdp->choice != Seq_descr_title) continue;
5145     if (lasttitle != NULL) {
5146       if (lasttitle->extended != 0) {
5147         ovp = (ObjValNodePtr) lasttitle;
5148         ovp->idx.deleteme = TRUE;
5149       }
5150       lasttitle = sdp;
5151     } else {
5152       lasttitle = sdp;
5153     }
5154   }
5155 }
5156 
5157 static void MakeSequinCleanupObject (SeqEntryPtr sep)
5158 
5159 {
5160   DatePtr        dp;
5161   ValNodePtr     sdp;
5162   UserObjectPtr  uop;
5163 
5164   dp = DateCurr ();
5165   if (dp == NULL) return;
5166 
5167   uop = CreateNcbiCleanupUserObject ();
5168   if (uop == NULL) return;
5169 
5170   AddStringToNcbiCleanupUserObject (uop, "method", "SequinCleanup");
5171   AddIntegerToNcbiCleanupUserObject (uop, "version", NCBI_CLEANUP_VERSION);
5172 
5173   AddIntegerToNcbiCleanupUserObject (uop, "month", dp->data [2]);
5174   AddIntegerToNcbiCleanupUserObject (uop, "day", dp->data [3]);
5175   AddIntegerToNcbiCleanupUserObject (uop, "year", dp->data [1] + 1900);
5176 
5177   sdp = NewDescrOnSeqEntry (sep, Seq_descr_user);
5178   if (sdp == NULL) return;
5179   sdp->data.ptrvalue = uop;
5180 }
5181 
5182 extern Int4 MySeqEntryToAsn3Ex (SeqEntryPtr sep, Boolean strip, Boolean correct, Boolean force, Boolean dotaxon);
5183 extern Int4 MySeqEntryToAsn3Ex (SeqEntryPtr sep, Boolean strip, Boolean correct, Boolean force, Boolean dotaxon)
5184 
5185 {
5186   Uint2       entityID;
5187   MonitorPtr  mon;
5188   Boolean     needstaxfix;
5189   Int4        rsult;
5190   ErrSev      sev;
5191 
5192   rsult = 0;
5193   sev = ErrSetMessageLevel (SEV_FATAL);
5194 
5195   RemoveAllNcbiCleanupUserObjects (sep);
5196 
5197   BasicSeqEntryCleanup (sep);
5198   EntryChangeImpFeat(sep);     /* change any CDS ImpFeat to real CdRegion */
5199   /* NormalizePeriodsOnInitials (sep); */ /* put periods on author initials */
5200   /* MoveRnaGBQualProductToName (sep); */ /* move rna gbqual product to rna-ref.ext.name */
5201   /* MoveProtGBQualProductToName (sep); */ /* move prot gbqual product to prot-ref.name */
5202   /* MoveCdsGBQualProductToName (sep); */ /* move cds gbqual product to prot-ref.name */
5203   /* MoveFeatGBQualsToFields (sep); */ /* move feature partial, exception to fields */
5204   if (indexerVersion) {
5205     /*
5206     StripTitleFromProtsInNucProts (sep);
5207     */
5208     MoveFeatsFromPartsSet (sep);
5209     move_cds (sep); /* move CDS features to nuc-prot set */
5210   }
5211   /* ExtendGeneFeatIfOnMRNA (0, sep); */ /* gene on mRNA is full length */
5212   entityID = ObjMgrGetEntityIDForChoice (sep);
5213   SeqMgrIndexFeatures (entityID, NULL);
5214   VisitBioseqsInSep (sep, NULL, ExtendSingleGeneOnMRNA);
5215   RemoveBioSourceOnPopSet (sep, NULL);
5216   /* SeqEntryExplore (sep, NULL, CleanupEmptyFeatCallback); */
5217   SeqEntryExplore (sep, NULL, DeleteMultipleTitles); /* do it old way in Sequin */
5218   /*
5219   SeqEntryExplore (sep, NULL, RemoveMultipleTitles);
5220   DeleteMarkedObjects (0, OBJ_SEQENTRY, (Pointer) sep);
5221   */
5222   SeqEntryPack (sep);
5223   if (indexerVersion) {
5224     ConvertAccInDefToLocalIdProc (sep); /* if title is accXNNNNN, convert to seqID */
5225   }
5226   if (useEntrez) {
5227     ValidateSeqAlignandACCInSeqEntry (sep, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE); /* remove components with seqID accXNNNNN */
5228   }
5229   SeqEntryExplore (sep, NULL, CheckSeqAlignCallback); /* remove alignments with single dimension */
5230   needstaxfix = FALSE;
5231   if (! force) {
5232     needstaxfix = NoBiosourceOrTaxonId (sep);
5233   }
5234   if ((! force) && (! needstaxfix)) {
5235     ConvertFullLenSourceFeatToDesc (sep);
5236     ConvertFullLenPubFeatToDesc (sep);
5237     /* EntryStripSerialNumber(sep); */ /* strip citation serial numbers */
5238     EntryChangeGBSource (sep);   /* at least remove redundant information in GBBlocks */
5239     EntryCheckGBBlock (sep);
5240     /* SeqEntryMoveDbxrefs (sep); */ /* db_xref gbqual to sfp->dbxref */
5241     EntryMergeDupBioSources (sep);
5242     GetRidOfEmptyFeatsDescStrings (0, sep);
5243     GetRidOfLocusInSeqIds (0, sep);
5244     /* reindex, since CdEndCheck (from CdCheck) gets best overlapping gene */
5245     entityID = ObjMgrGetEntityIDForChoice (sep);
5246     SeqMgrIndexFeatures (entityID, NULL);
5247     MakeSequinCleanupObject (sep);
5248     NormalizeDescriptorOrder (sep);
5249     SeqMgrIndexFeatures (entityID, NULL);
5250     CdCheck (sep, NULL);
5251     BasicSeqEntryCleanup (sep);
5252     ErrSetMessageLevel (sev);
5253     return rsult;
5254   }
5255   if (force && useTaxon) {
5256     dotaxon = TRUE;
5257   }
5258   mon = NULL;
5259   taxonCount = 0;
5260 /*#ifdef USE_TAXON*/
5261   if (dotaxon) {
5262     WatchCursor ();
5263     mon = MonitorStrNewEx ("Taxonomy Lookup", 40, FALSE);
5264     MonitorStrValue (mon, "Processing Organism Info");
5265     Update ();
5266   }
5267 /*#endif*/
5268 
5269   /* set dirty flag if no lineage or division in any biosource */
5270   if (dotaxon && needstaxfix) {
5271     entityID = ObjMgrGetEntityIDForChoice (sep);
5272     ObjMgrSetDirtyFlag (entityID, TRUE);
5273   }
5274 
5275   EntryMergeDupBioSources (sep); /* do before and after SE2A3 */
5276   if (dotaxon) {
5277     Taxon3ReplaceOrgInSeqEntry (sep, FALSE);
5278   }
5279   rsult = DoSeqEntryToAsn3 (sep, strip, correct, force, FALSE, mon);
5280 /*#ifdef USE_TAXON*/
5281   if (dotaxon) {
5282     MonitorStrValue (mon, "Closing Taxon");
5283     Update ();
5284     MonitorFree (mon);
5285     ArrowCursor ();
5286     Update ();
5287   }
5288 /*#endif*/
5289   ConvertFullLenSourceFeatToDesc (sep);
5290   ConvertFullLenPubFeatToDesc (sep);
5291   /* EntryStripSerialNumber(sep); */ /* strip citation serial numbers */
5292   MovePopPhyMutPubs (sep);
5293   EntryChangeGBSource (sep);   /* remove redundant information in GBBlocks again */
5294   EntryCheckGBBlock (sep);
5295   /* SeqEntryMoveDbxrefs (sep); */ /* db_xref gbqual to sfp->dbxref */
5296   EntryMergeDupBioSources (sep);
5297   GetRidOfEmptyFeatsDescStrings (0, sep);
5298   GetRidOfLocusInSeqIds (0, sep);
5299   /* reindex, since CdEndCheck (from CdCheck) gets best overlapping gene */
5300   entityID = ObjMgrGetEntityIDForChoice (sep);
5301   SeqMgrClearFeatureIndexes (entityID, NULL);
5302   MakeSequinCleanupObject (sep);
5303   NormalizeDescriptorOrder (sep);
5304   SeqMgrIndexFeatures (entityID, NULL);
5305   CdCheck (sep, NULL);
5306   BasicSeqEntryCleanup (sep);
5307   ErrSetMessageLevel (sev);
5308   ErrClear ();
5309   ErrShow ();
5310   return rsult;
5311 }
5312 
5313 typedef struct partialformdata {
5314   FEATURE_FORM_BLOCK
5315 
5316   ValNodePtr         featlist;
5317   LisT               feature;
5318   PopuP              change5;
5319   PopuP              change3;
5320   PopuP              orderJoinState;
5321   GrouP              nucprotchoice;
5322   TexT               findThis;
5323   CharPtr            findThisStr;
5324   Int2               subtype;
5325   Int2               leftpolicy;
5326   Int2               rightpolicy;
5327   Int2               nucprotpolicy;
5328   Int2               orderjoinpolicy;
5329   ObjMgrPtr          omp;
5330   ObjMgrTypePtr      omtp;
5331   ButtoN             extend5_btn;
5332   ButtoN             extend3_btn;
5333   Boolean            extend5;
5334   Boolean            extend3;
5335   ButtoN             leaveDlgUp;
5336   Boolean            case_insensitive;
5337   ButtoN             case_insensitive_btn;
5338   Boolean            when_string_not_present;
5339   ButtoN             when_string_not_present_btn;
5340 } PartialFormData, PNTR PartialFormPtr;
5341 
5342 static Boolean CDSMeetsStringConstraint (SeqFeatPtr sfp,
5343                                       CharPtr     findThisStr,
5344                                       Boolean     case_insensitive)
5345 {
5346   BioseqPtr             protbsp;
5347   SeqFeatPtr            protsfp;
5348   SeqMgrFeatContext     context;
5349   ProtRefPtr            prp;
5350 
5351   if (sfp == NULL) return FALSE;
5352   protbsp = BioseqFindFromSeqLoc (sfp->product);
5353   if (protbsp == NULL) return FALSE;
5354   protsfp = SeqMgrGetBestProteinFeature (protbsp, &context);
5355   if ((case_insensitive && StringISearch (context.label, findThisStr) != NULL)
5356     || (!case_insensitive && StringSearch (context.label, findThisStr) != NULL))
5357   {
5358     return TRUE;
5359   }
5360   if (protsfp == NULL) return FALSE;
5361   prp = (ProtRefPtr) protsfp->data.value.ptrvalue;
5362   if (prp->name != NULL)
5363   {
5364     if ((case_insensitive && StringISearch (prp->name->data.ptrvalue, findThisStr) != NULL)
5365       || (!case_insensitive && StringSearch (prp->name->data.ptrvalue, findThisStr) != NULL))
5366     {
5367       return TRUE;
5368     }
5369   }
5370   if (prp->desc != NULL)
5371   {
5372         if ((case_insensitive && StringISearch (prp->desc, findThisStr) != NULL)
5373           || (!case_insensitive && StringSearch (prp->desc, findThisStr) != NULL))
5374         {
5375           return TRUE;
5376         }
5377   }
5378   return FALSE;
5379 }
5380 
5381 extern Boolean MeetsStringConstraint (SeqFeatPtr  sfp,
5382                                                       CharPtr     findThisStr,
5383                                                       Boolean     case_insensitive)
5384 {
5385   GBQualPtr         gbqp;
5386   GeneRefPtr        grp;
5387   RnaRefPtr         rrp;
5388   SeqMgrFeatContext context;
5389   Boolean           have_context = FALSE;
5390 
5391   /* If no string constraint, then everyone matches */
5392 
5393   if (NULL == findThisStr)
5394     return TRUE;
5395 
5396   /* Search for the string constraint */
5397   /* in the feature title field */
5398   if (StringISearch (sfp->title, findThisStr))
5399     return TRUE;
5400 
5401   /* Search for the string constraint */
5402   /* in the feature comment field.    */
5403 
5404   if (StringISearch (sfp->comment, findThisStr))
5405     return TRUE;
5406 
5407   /* Search for the string constraint */
5408   /* in GB qualifiers.                */
5409 
5410   gbqp = sfp->qual;
5411   while (NULL != gbqp)
5412     {
5413       if ((NULL != gbqp->val) && StringISearch (gbqp->val, findThisStr))
5414         return TRUE;
5415       gbqp = gbqp->next;
5416     }
5417 
5418   if (SeqMgrGetDesiredFeature (sfp->idx.entityID, NULL, 0, 0, sfp, &context) != NULL)
5419   {
5420     if (!case_insensitive && StringSearch (context.label, findThisStr) != NULL)
5421     {
5422         return TRUE;
5423     }
5424     else if (case_insensitive && StringISearch (context.label, findThisStr) != NULL)
5425         {
5426           return TRUE;
5427         }
5428         have_context = TRUE;
5429   }
5430 
5431   if (sfp->data.choice == SEQFEAT_GENE)
5432   {
5433     grp = sfp->data.value.ptrvalue;
5434     if (!case_insensitive && 
5435         (StringSearch (grp->locus, findThisStr) != NULL
5436         || StringSearch (grp->desc, findThisStr) != NULL
5437         || StringSearch (grp->desc, findThisStr) != NULL
5438         || StringSearch (grp->locus_tag, findThisStr) != NULL))
5439     {
5440       return TRUE;      
5441     }
5442     else if (case_insensitive &&
5443         (StringISearch (grp->locus, findThisStr) != NULL
5444         || StringISearch (grp->desc, findThisStr) != NULL
5445         || StringISearch (grp->desc, findThisStr) != NULL
5446         || StringISearch (grp->locus_tag, findThisStr) != NULL))
5447     {
5448       return TRUE;      
5449     }
5450   }
5451   else if (sfp->data.choice == SEQFEAT_CDREGION)
5452   {
5453     if (CDSMeetsStringConstraint (sfp, findThisStr, case_insensitive))
5454       return TRUE;
5455   }
5456   else if (sfp->data.choice == SEQFEAT_RNA)
5457   {
5458     rrp = sfp->data.value.ptrvalue;
5459 
5460     if (rrp->ext.choice == 1) {
5461       if ((!case_insensitive && StringSearch ((CharPtr) rrp->ext.value.ptrvalue, findThisStr) != NULL)
5462         || (case_insensitive && StringISearch ((CharPtr) rrp->ext.value.ptrvalue, findThisStr) != NULL))
5463       {
5464         return TRUE;
5465       }
5466     }
5467     else if (rrp->type == 3 && rrp->ext.choice == 2 && have_context) 
5468     {
5469       /* look for the label as it appears to the user */
5470       if ((!case_insensitive && StringNCmp(findThisStr, "tRNA-", 5) == 0
5471           && StringSearch (context.label, findThisStr + 5))
5472           || (case_insensitive && StringNICmp (findThisStr, "tRNA-", 5) == 0
5473           && StringISearch (context.label, findThisStr + 5)))
5474       {
5475         return TRUE;
5476       }
5477     }
5478   }
5479 
5480   /* If we got to here, then the string constraint was not found */
5481 
5482   return FALSE;
5483 }
5484 
5485 
5486 extern Boolean SetBestFrameByLocation (SeqFeatPtr sfp)
5487 {
5488   CdRegionPtr  crp;
5489   Uint1        new_frame = 0, i;
5490   ByteStorePtr bs;
5491   Int4         lens [3];
5492   Int4         max;
5493   Boolean      retval = TRUE;
5494 
5495   if (sfp == NULL || sfp->data.choice != SEQFEAT_CDREGION) return FALSE;
5496   
5497   crp = sfp->data.value.ptrvalue;
5498   if (crp == NULL) return FALSE;
5499 
5500   max = 0;
5501   for (i = 1; i <= 3; i++) {
5502     crp->frame = i;
5503     bs = ProteinFromCdRegionEx (sfp, FALSE, FALSE);
5504     lens[i - 1] = BSLen (bs);
5505     BSFree (bs);
5506     if (lens[i - 1] > max) {
5507       max = lens[i - 1];
5508       new_frame = i;
5509     }
5510   }
5511   for (i = 1; i <= 3; i++) {
5512     if (lens [i - 1] == max && i != new_frame) {
5513       retval = FALSE;
5514     }
5515   }
5516   crp->frame = new_frame;
5517   return retval;
5518 }
5519 
5520 
5521 extern void SetBestFrame (SeqFeatPtr sfp)
5522 {
5523   SeqAlignPtr  salp;
5524   CdRegionPtr  crp;
5525   BioseqPtr    old_prot, new_prot;
5526   ByteStorePtr bs = NULL;
5527   Int4         original_frame, test_frame;
5528   Boolean      revcomp;
5529   ErrSev       level;
5530   CharPtr      seq_str1, seq_str2;
5531   Int4         best_len = -1, new_aln_len;
5532   Int4         best_frame = -1;
5533   
5534   if (sfp == NULL || sfp->idx.subtype != FEATDEF_CDS) return;
5535   
5536   crp = sfp->data.value.ptrvalue;
5537   if (crp == NULL) return;
5538 
5539   old_prot = BioseqFindFromSeqLoc (sfp->product);
5540   if (old_prot == NULL) return;
5541   
5542   new_prot = BioseqNew ();
5543   new_prot->id = SeqIdParse ("lcl|CdRgnTransl");
5544   new_prot->repr = Seq_repr_raw;
5545   new_prot->mol = Seq_mol_aa;
5546   new_prot->seq_data_type = Seq_code_ncbieaa;
5547   bs = ProteinFromCdRegionEx (sfp, TRUE, FALSE);
5548   new_prot->seq_data = (SeqDataPtr) bs;
5549   new_prot->length = BSLen (bs);
5550   
5551   original_frame = crp->frame;
5552 
5553   /* suppress BLAST error messages when no similarity is found */
5554   level = ErrSetMessageLevel (SEV_MAX);
5555   seq_str1 = BSMerge((ByteStorePtr)(old_prot->seq_data), NULL);
5556   seq_str2 = BSMerge((ByteStorePtr)(new_prot->seq_data), NULL);
5557   
5558   for (test_frame = 1; test_frame <= 3; test_frame ++)
5559   {
5560     new_prot->seq_data = SeqDataFree (new_prot->seq_data, new_prot->seq_data_type);
5561     crp->frame = test_frame;
5562     new_prot->seq_data = (SeqDataPtr) ProteinFromCdRegionEx (sfp, TRUE, FALSE);
5563     salp = Sequin_GlobalAlign2Seq (old_prot, new_prot, &revcomp);
5564     if (salp != NULL)
5565     {
5566       new_aln_len = SeqAlignLength (salp);
5567       if (new_aln_len > best_len)
5568       {
5569         best_len = new_aln_len;
5570         best_frame = test_frame;
5571       }
5572       salp = SeqAlignFree (salp);
5573     }
5574   }     
5575   
5576   if (best_frame > -1)
5577   {
5578     crp->frame = best_frame;
5579   }
5580   else
5581   {
5582     crp->frame = original_frame;
5583   }
5584 
5585   ErrSetMessageLevel (level);
5586   BioseqFree (new_prot);
5587 }
5588 
5589 
5590 /*
5591 static Boolean AddOrgToDefGatherFunc (GatherContextPtr gcp)
5592 
5593 {
5594   CharPtr     def;
5595   CharPtr     ptr;
5596   ValNodePtr  sdp;
5597   CharPtr     str;
5598   CharPtr     text;
5599 
5600   if (gcp == NULL || gcp->thisitem == NULL) return TRUE;
5601   if (gcp->thistype != OBJ_SEQDESC) return TRUE;
5602   text = (CharPtr) gcp->userdata;
5603   if (text == NULL || StringHasNoText (text)) return TRUE;
5604   sdp = (ValNodePtr) gcp->thisitem;
5605   if (sdp->choice != Seq_descr_title) return TRUE;
5606   def = (CharPtr) sdp->data.ptrvalue;
5607   if (StringHasNoText (def)) return TRUE;
5608 
5609   ptr = StringISearch (def, text);
5610   if (ptr != NULL && ptr == def) return TRUE;
5611   str = MemNew ((StringLen (text) + StringLen (def) + 4) * sizeof (Char));
5612   if (str != NULL) {
5613     StringCpy (str, text);
5614     StringCat (str, " ");
5615     StringCat (str, def);
5616     sdp->data.ptrvalue = MemFree (sdp->data.ptrvalue);
5617     sdp->data.ptrvalue = str;
5618     ObjMgrSetDirtyFlag (gcp->entityID, TRUE);
5619   }
5620   return TRUE;
5621 }
5622 */
5623 
5624 static void AppendOrgToString (Uint2 entityID, SeqDescrPtr sdp, CharPtr text)
5625 
5626 {
5627   CharPtr     def;
5628   CharPtr     ptr;
5629   CharPtr     str;
5630 
5631   def = (CharPtr) sdp->data.ptrvalue;
5632   if (StringHasNoText (def)) return;
5633 
5634   ptr = StringISearch (def, text);
5635   if (ptr != NULL && ptr == def) return;
5636   str = MemNew ((StringLen (text) + StringLen (def) + 4) * sizeof (Char));
5637   if (str != NULL) {
5638     StringCpy (str, text);
5639     StringCat (str, " ");
5640     StringCat (str, def);
5641     sdp->data.ptrvalue = MemFree (sdp->data.ptrvalue);
5642     sdp->data.ptrvalue = str;
5643     ObjMgrSetDirtyFlag (entityID, TRUE);
5644   }
5645 }
5646 
5647 static void AddOrgToDefElement (Uint2 entityID, SeqEntryPtr sep, Int2 orgmod, Int2 subsource)
5648 
5649 {
5650   BioSourcePtr       biop;
5651   BioseqPtr          bsp;
5652   BioseqSetPtr       bssp;
5653   Char               ch;
5654   SeqMgrDescContext  dcontext;
5655   OrgModPtr          mod;
5656   OrgNamePtr         onp;
5657   OrgRefPtr          orp;
5658   CharPtr            ptr;
5659   SeqDescrPtr        sdp;
5660   SubSourcePtr       ssp;
5661   Char               str [96];
5662   Char               text [64];
5663   CharPtr            title;
5664 
5665   if (sep == NULL) return;
5666   if (IS_Bioseq_set (sep)) {
5667     bssp = (BioseqSetPtr) sep->data.ptrvalue;
5668     if (bssp != NULL && (bssp->_class == 1 || bssp->_class == 2 ||
5669                          bssp->_class == 4)) {
5670       for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
5671         AddOrgToDefElement (entityID, sep, orgmod, subsource);
5672       }
5673       return;
5674     }
5675   }
5676   if (! IS_Bioseq (sep)) return;
5677   bsp = (BioseqPtr) sep->data.ptrvalue;
5678   biop = NULL;
5679   text [0] = '\0';
5680   str [0] = '\0';
5681   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_source, &dcontext);
5682   if (sdp != NULL) {
5683     biop = (BioSourcePtr) sdp->data.ptrvalue;
5684   }
5685   if (biop == NULL) return;
5686   /* SeqEntryToBioSource (sep, NULL, str, sizeof (str) - 1, &biop); */
5687   if (orgmod == 0 && subsource == 0) {
5688     orp = biop->org;
5689     if (orp == NULL) return;
5690     StringNCpy_0 (str, orp->taxname, sizeof (str));
5691     /*
5692     ptr = StringSearch (str, "(");
5693     if (ptr != NULL) {
5694       *ptr = '\0';
5695     }
5696     */
5697     TrimSpacesAroundString (str);
5698     if ((StringICmp (str, "Human immunodeficiency virus type 1") == 0) ||
5699         (StringICmp (str, "Human immunodeficiency virus 1") == 0)) {
5700       StringCpy (str, "HIV-1");
5701     } else if ((StringICmp (str,"Human immunodeficiency virus type 2")==0) ||
5702                (StringICmp (str,"Human immunodeficiency virus 2") == 0)) {
5703       StringCpy (str, "HIV-2");
5704     }
5705     str [0] = TO_UPPER (str [0]);
5706   } else if (biop != NULL && biop->org != NULL) {
5707     text [0] = '\0';
5708     str [0] = '\0';
5709     orp = biop->org;
5710     if (orgmod > 0) {
5711       onp = orp->orgname;
5712       if (onp != NULL) {
5713         mod = onp->mod;
5714         while (mod != NULL) {
5715           if (mod->subtype == orgmod) {
5716             StringNCpy_0 (text, mod->subname, sizeof (text));
5717             StringNCpy_0 (str, GetOrgModQualName (mod->subtype), sizeof (str));
5718           }
5719           mod = mod->next;
5720         }
5721       }
5722     } else if (subsource > 0) {
5723       ssp = biop->subtype;
5724       while (ssp != NULL) {
5725         if (ssp->subtype == subsource) {
5726           StringNCpy_0 (text, ssp->name, sizeof (text));
5727           StringNCpy_0 (str, GetSubsourceQualName (ssp->subtype), sizeof (str));
5728         }
5729         ssp = ssp->next;
5730       }
5731     }
5732     if (StringHasNoText (text)) {
5733       str [0] = '\0';
5734       text [0] = '\0';
5735     } else {
5736       StringCat (str, " ");
5737       ptr = str;
5738       while (*ptr != '\0') {
5739         ch = *ptr;
5740         *ptr = TO_LOWER (ch);
5741         ptr++;
5742       }
5743       StringCat (str, text);
5744     }
5745   }
5746   /*
5747   MemSet ((Pointer) (&gs), 0, sizeof (GatherScope));
5748   gs.seglevels = 1;
5749   gs.get_feats_location = FALSE;
5750   MemSet ((Pointer) (gs.ignore), (int)(TRUE), (size_t) (OBJ_MAX * sizeof(Boolean)));
5751   gs.ignore[OBJ_BIOSEQ] = FALSE;
5752   gs.ignore[OBJ_BIOSEQ_SEG] = FALSE;
5753   gs.ignore[OBJ_SEQANNOT] = FALSE;
5754   gs.ignore[OBJ_SEQDESC] = FALSE;
5755   gs.scope = sep;
5756   GatherSeqEntry (sep, (Pointer) str, AddOrgToDefGatherFunc, &gs);
5757   */
5758   sdp = SeqEntryGetSeqDescr (sep, Seq_descr_title, NULL);
5759   if (sdp == NULL) {
5760     sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_title, &dcontext);
5761     if (sdp == NULL) return;
5762     title = (CharPtr) sdp->data.ptrvalue;
5763     if (title == NULL) return;
5764     sdp = SeqDescrAdd (&(bsp->descr));
5765     if (sdp == NULL) return;
5766     sdp->choice = Seq_descr_title;
5767     sdp->data.ptrvalue = StringSave (title);
5768   }
5769   if (sdp == NULL) return;
5770   AppendOrgToString (entityID, sdp, str);
5771 }
5772 
5773 static void AddOrgToDef (Uint2 entityID, SeqEntryPtr sep, Int2 orgmod, Int2 subsource)
5774 
5775 {
5776   BioseqSetPtr       bssp;
5777 
5778   if (sep == NULL) return;
5779   if (IS_Bioseq_set (sep)) {
5780     bssp = (BioseqSetPtr) sep->data.ptrvalue;
5781     if (bssp != NULL && (bssp->_class == 7 ||
5782                          (IsPopPhyEtcSet (bssp->_class)))) {
5783       for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
5784         AddOrgToDef (entityID, sep, orgmod, subsource);
5785       }
5786       return;
5787     }
5788   }
5789   AddOrgToDefElement (entityID, sep, orgmod, subsource);
5790 }
5791 
5792 extern void CommonAddOrgOrModsToDefLines (IteM i, Int2 orgmod, Int2 subsource, ButtoN b)
5793 
5794 {
5795   BaseFormPtr  bfp;
5796   SeqEntryPtr  sep;
5797 
5798   if (b != NULL) {
5799     bfp = GetObjectExtra (b);
5800   } else {
5801 #ifdef WIN_MAC
5802     bfp = currentFormDataPtr;
5803 #else
5804     bfp = GetObjectExtra (i);
5805 #endif
5806   }
5807   if (bfp == NULL) return;
5808   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
5809   if (sep == NULL) return;
5810   WatchCursor ();
5811   Update ();
5812   AddOrgToDef (bfp->input_entityID, sep, orgmod, subsource);
5813   ArrowCursor ();
5814   Update ();
5815   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
5816   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
5817 }
5818 
5819 static void RemoveAlignmentCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
5820 
5821 {
5822   BioseqPtr      bsp;
5823   BioseqSetPtr   bssp;
5824   SeqAlignPtr    nextsalp;
5825   SeqAnnotPtr    nextsap;
5826   Pointer PNTR   prevsalp;
5827   Pointer PNTR   prevsap;
5828   SeqAlignPtr    salp;
5829   SeqAnnotPtr    sap;
5830 
5831   if (sep == NULL || sep->data.ptrvalue == NULL) return;
5832   if (IS_Bioseq (sep)) {
5833     bsp = (BioseqPtr) sep->data.ptrvalue;
5834     sap = bsp->annot;
5835     prevsap = (Pointer PNTR) &(bsp->annot);
5836   } else if (IS_Bioseq_set (sep)) {
5837     bssp = (BioseqSetPtr) sep->data.ptrvalue;
5838     sap = bssp->annot;
5839     prevsap = (Pointer PNTR) &(bssp->annot);
5840   } else return;
5841   while (sap != NULL) {
5842     nextsap = sap->next;
5843     if (sap->type == 2) {
5844       salp = (SeqAlignPtr) sap->data;
5845       prevsalp = (Pointer PNTR) &(sap->data);
5846       while (salp != NULL) {
5847         nextsalp = salp->next;
5848         *(prevsalp) = salp->next;
5849         salp->next = NULL;
5850         SeqAlignFree (salp);
5851         salp = nextsalp;
5852       }
5853     }
5854     if (sap->data == NULL) {
5855       *(prevsap) = sap->next;
5856       sap->next = NULL;
5857       SeqAnnotFree (sap);
5858     } else {
5859       prevsap = (Pointer PNTR) &(sap->next);
5860     }
5861     sap = nextsap;
5862   }
5863 }
5864 
5865 extern void RemoveAlignment (IteM i)
5866 
5867 {
5868   BaseFormPtr bfp;
5869   SeqEntryPtr  sep;
5870 
5871 #ifdef WIN_MAC
5872   bfp = currentFormDataPtr;
5873 #else
5874   bfp = GetObjectExtra (i);
5875 #endif
5876   if (bfp == NULL) return;
5877   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
5878   if (sep == NULL) return;
5879   SeqEntryExplore (sep, NULL, RemoveAlignmentCallback);
5880   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
5881   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
5882   ObjMgrDeSelect (0, 0, 0, 0, NULL);
5883   Update ();
5884 }
5885 
5886 static void RemoveGraphCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
5887 
5888 {
5889   BioseqPtr      bsp;
5890   BioseqSetPtr   bssp;
5891   SeqAnnotPtr    nextsap;
5892   SeqGraphPtr    nextsgp;
5893   Pointer PNTR   prevsap;
5894   Pointer PNTR   prevsgp;
5895   SeqAnnotPtr    sap;
5896   SeqGraphPtr    sgp;
5897 
5898   if (sep == NULL || sep->data.ptrvalue == NULL) return;
5899   if (IS_Bioseq (sep)) {
5900     bsp = (BioseqPtr) sep->data.ptrvalue;
5901     sap = bsp->annot;
5902     prevsap = (Pointer PNTR) &(bsp->annot);
5903   } else if (IS_Bioseq_set (sep)) {
5904     bssp = (BioseqSetPtr) sep->data.ptrvalue;
5905     sap = bssp->annot;
5906     prevsap = (Pointer PNTR) &(bssp->annot);
5907   } else return;
5908   while (sap != NULL) {
5909     nextsap = sap->next;
5910     if (sap->type == 3) {
5911       sgp = (SeqGraphPtr) sap->data;
5912       prevsgp = (Pointer PNTR) &(sap->data);
5913       while (sgp != NULL) {
5914         nextsgp = sgp->next;
5915         if (sgp->flags [2] >= 1 && sgp->flags [2] <= 3) {
5916           *(prevsgp) = sgp->next;
5917           sgp->next = NULL;
5918           SeqGraphFree (sgp);
5919         } else {
5920           prevsgp = (Pointer PNTR) &(sgp->next);
5921         }
5922         sgp = nextsgp;
5923       }
5924     }
5925     if (sap->data == NULL) {
5926       *(prevsap) = sap->next;
5927       sap->next = NULL;
5928       SeqAnnotFree (sap);
5929     } else {
5930       prevsap = (Pointer PNTR) &(sap->next);
5931     }
5932     sap = nextsap;
5933   }
5934 }
5935 
5936 extern void RemoveGraph (IteM i)
5937 
5938 {
5939   BaseFormPtr bfp;
5940   SeqEntryPtr  sep;
5941 
5942 #ifdef WIN_MAC
5943   bfp = currentFormDataPtr;
5944 #else
5945   bfp = GetObjectExtra (i);
5946 #endif
5947   if (bfp == NULL) return;
5948   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
5949   if (sep == NULL) return;
5950   SeqEntryExplore (sep, NULL, RemoveGraphCallback);
5951   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
5952   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
5953   ObjMgrDeSelect (0, 0, 0, 0, NULL);
5954   Update ();
5955 }
5956 
5957 static void RemoveSeqAnnotIDsCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
5958 
5959 {
5960   BioseqPtr      bsp;
5961   BioseqSetPtr   bssp;
5962   SeqAnnotPtr    nextsap;
5963   Pointer PNTR   prevsap;
5964   SeqAnnotPtr    sap;
5965   SeqIdPtr       sip;
5966 
5967   if (sep == NULL || sep->data.ptrvalue == NULL) return;
5968   if (IS_Bioseq (sep)) {
5969     bsp = (BioseqPtr) sep->data.ptrvalue;
5970     sap = bsp->annot;
5971     prevsap = (Pointer PNTR) &(bsp->annot);
5972   } else if (IS_Bioseq_set (sep)) {
5973     bssp = (BioseqSetPtr) sep->data.ptrvalue;
5974     sap = bssp->annot;
5975     prevsap = (Pointer PNTR) &(bssp->annot);
5976   } else return;
5977   while (sap != NULL) {
5978     nextsap = sap->next;
5979     if (sap->type == 4) {
5980       sip = (SeqIdPtr) sap->data;
5981       SeqIdSetFree (sip);
5982       sap->data = NULL;
5983     }
5984     if (sap->data == NULL) {
5985       *(prevsap) = sap->next;
5986       sap->next = NULL;
5987       SeqAnnotFree (sap);
5988     } else {
5989       prevsap = (Pointer PNTR) &(sap->next);
5990     }
5991     sap = nextsap;
5992   }
5993 }
5994 
5995 extern void RemoveSeqAnnotIDs (IteM i)
5996 
5997 {
5998   BaseFormPtr bfp;
5999   SeqEntryPtr  sep;
6000 
6001 #ifdef WIN_MAC
6002   bfp = currentFormDataPtr;
6003 #else
6004   bfp = GetObjectExtra (i);
6005 #endif
6006   if (bfp == NULL) return;
6007   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
6008   if (sep == NULL) return;
6009   SeqEntryExplore (sep, NULL, RemoveSeqAnnotIDsCallback);
6010   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
6011   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
6012   ObjMgrDeSelect (0, 0, 0, 0, NULL);
6013   Update ();
6014 }
6015 
6016 static void RemoveSeqAnnotLOCsCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
6017 
6018 {
6019   BioseqPtr      bsp;
6020   BioseqSetPtr   bssp;
6021   SeqAnnotPtr    nextsap;
6022   Pointer PNTR   prevsap;
6023   SeqAnnotPtr    sap;
6024   SeqLocPtr      slp;
6025 
6026   if (sep == NULL || sep->data.ptrvalue == NULL) return;
6027   if (IS_Bioseq (sep)) {
6028     bsp = (BioseqPtr) sep->data.ptrvalue;
6029     sap = bsp->annot;
6030     prevsap = (Pointer PNTR) &(bsp->annot);
6031   } else if (IS_Bioseq_set (sep)) {
6032     bssp = (BioseqSetPtr) sep->data.ptrvalue;
6033     sap = bssp->annot;
6034     prevsap = (Pointer PNTR) &(bssp->annot);
6035   } else return;
6036   while (sap != NULL) {
6037     nextsap = sap->next;
6038     if (sap->type == 4) {
6039       slp = (SeqLocPtr) sap->data;
6040       SeqLocSetFree (slp);
6041       sap->data = NULL;
6042     }
6043     if (sap->data == NULL) {
6044       *(prevsap) = sap->next;
6045       sap->next = NULL;
6046       SeqAnnotFree (sap);
6047     } else {
6048       prevsap = (Pointer PNTR) &(sap->next);
6049     }
6050     sap = nextsap;
6051   }
6052 }
6053 
6054 extern void RemoveSeqAnnotLOCs (IteM i)
6055 
6056 {
6057   BaseFormPtr bfp;
6058   SeqEntryPtr  sep;
6059 
6060 #ifdef WIN_MAC
6061   bfp = currentFormDataPtr;
6062 #else
6063   bfp = GetObjectExtra (i);
6064 #endif
6065   if (bfp == NULL) return;
6066   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
6067   if (sep == NULL) return;
6068   SeqEntryExplore (sep, NULL, RemoveSeqAnnotLOCsCallback);
6069   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
6070   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
6071   ObjMgrDeSelect (0, 0, 0, 0, NULL);
6072   Update ();
6073 }
6074 
6075 static void MarkProteinCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
6076 
6077 {
6078   BioseqPtr        bsp;
6079   ValNodePtr PNTR  vnpp;
6080 
6081   if (mydata == NULL) return;
6082   if (sep == NULL || sep->data.ptrvalue == NULL) return;
6083   vnpp = (ValNodePtr PNTR) mydata;
6084   if (vnpp == NULL) return;
6085   if (IS_Bioseq (sep)) {
6086     bsp = (BioseqPtr) sep->data.ptrvalue;
6087     if (ISA_aa (bsp->mol)) {
6088       ValNodeAddPointer (vnpp, 0, (Pointer) bsp);
6089     }
6090   }
6091 }
6092 
6093 static void RemoveProteinsAndOptionallyRenormalize (IteM i, Boolean renormalize)
6094 
6095 {
6096   BaseFormPtr    bfp;
6097   BioseqPtr      bsp;
6098   Uint4          itemID;
6099   ObjMgrDataPtr  omdptop;
6100   ObjMgrData     omdata;
6101   OMProcControl  ompc;
6102   Uint2          parenttype;
6103   Pointer        parentptr;
6104   SeqEntryPtr    sep;
6105   ValNodePtr     tmp;
6106   ValNodePtr     vnp;
6107 
6108 #ifdef WIN_MAC
6109   bfp = currentFormDataPtr;
6110 #else
6111   bfp = GetObjectExtra (i);
6112 #endif
6113   if (bfp == NULL) return;
6114   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
6115   if (sep == NULL) return;
6116   SaveSeqEntryObjMgrData (sep, &omdptop, &omdata);
6117   GetSeqEntryParent (sep, &parentptr, &parenttype);
6118   vnp = NULL;
6119   SeqEntryExplore (sep, (Pointer) &vnp, MarkProteinCallback);
6120   for (tmp = vnp; tmp != NULL; tmp = tmp->next) {
6121     bsp = (BioseqPtr) tmp->data.ptrvalue;
6122     itemID = GetItemIDGivenPointer (bfp->input_entityID, OBJ_BIOSEQ, (Pointer) bsp);
6123     if (itemID > 0) {
6124       MemSet ((Pointer) (&ompc), 0, sizeof (OMProcControl));
6125       ompc.do_not_reload_from_cache = TRUE;
6126       ompc.input_entityID = bfp->input_entityID;
6127       ompc.input_itemID = itemID;
6128       ompc.input_itemtype = OBJ_BIOSEQ;
6129       if (! DetachDataForProc (&ompc, FALSE)) {
6130         Message (MSG_POSTERR, "DetachDataForProc failed");
6131       }
6132     }
6133   }
6134   ValNodeFree (vnp);
6135   SeqMgrLinkSeqEntry (sep, parenttype, parentptr);
6136   RestoreSeqEntryObjMgrData (sep, omdptop, &omdata);
6137   if (renormalize) 
6138   {
6139     RenormalizeNucProtSets (sep, TRUE);
6140   }
6141   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
6142   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
6143   ObjMgrDeSelect (0, 0, 0, 0, NULL);
6144   Update ();
6145 }
6146 
6147 extern void RemoveProteins (IteM i)
6148 {
6149   RemoveProteinsAndOptionallyRenormalize (i, FALSE);
6150 }
6151 
6152 extern void RemoveProteinsAndRenormalize (IteM i)
6153 {
6154   RemoveProteinsAndOptionallyRenormalize (i, TRUE);
6155 }
6156 
6157 #define EDIT_FIVE_PRIME  1
6158 #define EDIT_THREE_PRIME 2
6159 
6160 #define ADD_TO_END       1
6161 #define TRIM_FROM_END    2
6162 
6163 #define TRIM_BY_SEQUENCE 1
6164 #define TRIM_BY_COUNT    2
6165 
6166 typedef struct edseqendsdata {
6167   FEATURE_FORM_BLOCK
6168 
6169   TexT           seq;
6170   TexT           genename;
6171   GrouP          whichend;
6172   GrouP          addOrTrim;
6173   Int2           addOrTrimBool;
6174   GrouP          trimBy;
6175   Int2           trimByBool;
6176   Int4           trimCount;
6177   TexT           trimCountText;
6178   ButtoN         extendfeat;
6179   LisT           nuc_sequence_list_ctrl;
6180   ButtoN         addCitSub;
6181   CharPtr        seqstr;
6182   CharPtr        genestr;
6183   Int2           endval;
6184   Int2           frameshift;
6185   Boolean        adjustframe;
6186   Boolean        extendflag;
6187   BioseqPtr      extendedthis;
6188   SeqEntryPtr    sep;
6189   Boolean        rsult;
6190 } EditSeqEnds, PNTR EditSeqPtr;
6191 
6192 static Boolean GeneFindByNameFunc (GatherContextPtr gcp)
6193 
6194 {
6195   EditSeqPtr  esp;
6196   GeneRefPtr  grp;
6197   SeqFeatPtr  sfp;
6198 
6199   if (gcp == NULL) return TRUE;
6200   esp = (EditSeqPtr) gcp->userdata;
6201   if (esp == NULL) return TRUE;
6202   if (gcp->thistype != OBJ_SEQFEAT) return TRUE;
6203   sfp = (SeqFeatPtr) gcp->thisitem;
6204   if (sfp == NULL) return TRUE;
6205   if (sfp->data.choice != SEQFEAT_GENE) return TRUE;
6206   grp = (GeneRefPtr) sfp->data.value.ptrvalue;
6207   if (grp == NULL) return TRUE;
6208   if (StringICmp (grp->locus, esp->genestr) == 0) {
6209     esp->rsult = TRUE;
6210   }
6211   return TRUE;
6212 }
6213 
6214 static Boolean EditSeqEntryHasGene (BioseqPtr bsp, SeqEntryPtr sep, EditSeqPtr esp)
6215 
6216 {
6217   GatherScope  gs;
6218 
6219   if (esp->input_entityID == 0 || esp->sep == NULL) return FALSE;
6220   if (StringHasNoText (esp->genestr)) return TRUE;
6221   esp->rsult = FALSE;
6222   MemSet ((Pointer) (&gs), 0, sizeof (GatherScope));
6223   gs.seglevels = 1;
6224   gs.get_feats_location = TRUE;
6225   gs.scope = sep;
6226   MemSet ((Pointer)(gs.ignore), (int) (TRUE), (size_t) (OBJ_MAX * sizeof (Boolean)));
6227   gs.ignore [OBJ_BIOSEQ] = FALSE;
6228   gs.ignore [OBJ_BIOSEQ_SEG] = FALSE;
6229   gs.ignore [OBJ_SEQFEAT] = FALSE;
6230   gs.ignore [OBJ_SEQANNOT] = FALSE;
6231   GatherEntity (esp->input_entityID, (Pointer) esp, GeneFindByNameFunc, &gs);
6232   gs.target = SeqLocFree (gs.target);
6233   return esp->rsult;
6234 }
6235 
6236 static Boolean FixACDSFunc (GatherContextPtr gcp)
6237 
6238 {
6239   SeqFeatPtr    bestprot;
6240   ByteStorePtr  bs;
6241   BioseqPtr     bsp;
6242   Char          ch;
6243   CdRegionPtr   crp;
6244   EditSeqPtr    esp;
6245   Int2          frame;
6246   Boolean       partial5;
6247   Boolean       partial3;
6248   CharPtr       prot;
6249   CharPtr       ptr;
6250   SeqEntryPtr   sep;
6251   SeqFeatPtr    sfp;
6252   SeqIdPtr      sip;
6253   SeqLocPtr     slp;
6254 
6255   if (gcp == NULL) return TRUE;
6256   esp = (EditSeqPtr) gcp->userdata;
6257   if (esp == NULL) return TRUE;
6258   if (gcp->thistype != OBJ_SEQFEAT) return TRUE;
6259   sfp = (SeqFeatPtr) gcp->thisitem;
6260   if (sfp == NULL) return TRUE;
6261   if (sfp->data.choice != SEQFEAT_CDREGION) return TRUE;
6262   slp = SeqLocFindNext (sfp->location, NULL);
6263   if (slp == NULL) return TRUE;
6264   CheckSeqLocForPartial (slp, &partial5, &partial3);
6265   sip = SeqLocId (slp);
6266   if (sip == NULL) return TRUE;
6267   bsp = BioseqFind (sip);
6268   if (bsp == NULL || bsp != esp->extendedthis) return TRUE;
6269   if (esp->adjustframe) {
6270     if (GetOffsetInBioseq (slp, bsp, SEQLOC_START) != 0) return TRUE;
6271     crp = (CdRegionPtr) sfp->data.value.ptrvalue;
6272     if (crp == NULL) return TRUE;
6273     frame = crp->frame;
6274     if (frame == 0)
6275       frame = 1;
6276     if (esp->addOrTrimBool == ADD_TO_END)
6277       {
6278         frame--;
6279         frame += esp->frameshift;
6280         crp->frame = (frame % 3) + 1;
6281       }
6282     else if (esp->addOrTrimBool == TRIM_FROM_END)
6283       {
6284         frame = ABS(frame - esp->frameshift);
6285         crp->frame = 3 - (frame % 3);
6286       }
6287   } else {
6288     if (GetOffsetInBioseq (slp, bsp, SEQLOC_STOP) != bsp->length - 1)
6289       return TRUE;
6290   }
6291   sip = SeqLocId (sfp->product);
6292   if (sip == NULL) return TRUE;
6293   bsp = BioseqFind (sip);
6294   if (bsp == NULL) return TRUE;
6295   if (bsp->repr != Seq_repr_raw) return TRUE;
6296   if (bsp->mol != Seq_mol_aa) return TRUE;
6297   bestprot = FindBestProtein (esp->input_entityID, sfp->product);
6298   bs = ProteinFromCdRegionEx (sfp, FALSE, FALSE);
6299   if (bs == NULL) return TRUE;
6300   prot = BSMerge (bs, NULL);
6301   bs = BSFree (bs);
6302   if (prot == NULL) return TRUE;
6303   ptr = prot;
6304   ch = *ptr;
6305   while (ch != '\0') {
6306     *ptr = TO_UPPER (ch);
6307     ptr++;
6308     ch = *ptr;
6309   }
6310   bs = BSNew (1000);
6311   if (bs != NULL) {
6312     ptr = prot;
6313     /*
6314     if (prot [0] == '-') {
6315        ptr++;
6316     }
6317     */
6318     BSWrite (bs, (VoidPtr) ptr, (Int4) StringLen (ptr));
6319     bsp->seq_data = SeqDataFree (bsp->seq_data, bsp->seq_data_type);
6320     bsp->seq_data = (SeqDataPtr) bs;
6321     bsp->length = BSLen (bs);
6322     bsp->seq_data_type = Seq_code_ncbieaa;
6323   }
6324   if (bestprot == NULL) return TRUE;
6325   sep = SeqMgrGetSeqEntryForData (bsp);
6326   bestprot->location = SeqLocFree (bestprot->location);
6327   bestprot->location = CreateWholeInterval (sep);
6328   SetSeqLocPartial (bestprot->location, partial5, partial3);
6329   return TRUE;
6330 }
6331 
6332 static void FixAndRetranslateCDSs (BioseqPtr bsp, SeqEntryPtr sep,
6333                                    EditSeqPtr esp, Boolean adjustframe)
6334 
6335 {
6336   GatherScope  gs;
6337 
6338   if (esp->input_entityID == 0 || esp->sep == NULL) return;
6339   esp->adjustframe = adjustframe;
6340   MemSet ((Pointer) (&gs), 0, sizeof (GatherScope));
6341   gs.seglevels = 1;
6342   gs.get_feats_location = FALSE;
6343   gs.scope = sep;
6344   MemSet ((Pointer)(gs.ignore), (int) (TRUE), (size_t) (OBJ_MAX * sizeof (Boolean)));
6345   gs.ignore [OBJ_BIOSEQ] = FALSE;
6346   gs.ignore [OBJ_BIOSEQ_SEG] = FALSE;
6347   gs.ignore [OBJ_SEQFEAT] = FALSE;
6348   gs.ignore [OBJ_SEQANNOT] = FALSE;
6349   GatherEntity (esp->input_entityID, (Pointer) esp, FixACDSFunc, &gs);
6350   gs.target = SeqLocFree (gs.target);
6351 }
6352 
6353 static ValNodePtr CollectAndExtendSingleBaseFeatures (BioseqPtr bsp, Int2 whichend, Int4 len)
6354 
6355 {
6356   SeqMgrFeatContext  context;
6357   ValNodePtr         head = NULL;
6358   SeqFeatPtr         sfp;
6359   SeqLocPtr          slp;
6360   SeqPntPtr          spp;
6361 
6362   sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &context);
6363   while (sfp != NULL) {
6364     if (whichend == 1 && context.numivals == 1 && context.right == 0) {
6365       slp = sfp->location;
6366       if (slp != NULL && slp->choice == SEQLOC_PNT && slp->next == NULL) {
6367         spp = (SeqPntPtr) slp->data.ptrvalue;
6368         if (spp != NULL && spp->point == 0) {
6369           spp->point = 1;
6370           ValNodeAddPointer (&head, 1, (Pointer) sfp);
6371         }
6372       }
6373     } else if (whichend == 2 && context.numivals == 1 && context.left == bsp->length - 1) {
6374       slp = sfp->location;
6375       if (slp != NULL && slp->choice == SEQLOC_PNT && slp->next == NULL) {
6376         spp = (SeqPntPtr) slp->data.ptrvalue;
6377         if (spp != NULL && spp->point == bsp->length - 1) {
6378           spp->point = bsp->length - 2;
6379           ValNodeAddPointer (&head, 2, (Pointer) sfp);
6380         }
6381       }
6382     }
6383     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &context);
6384   }
6385 
6386   return head;
6387 }
6388 
6389 static void ReadjustSingleBaseFeatures (ValNodePtr head, BioseqPtr bsp, Int2 whichend, Int4 len)
6390 
6391 {
6392   SeqFeatPtr  sfp;
6393   SeqIntPtr   sintp;
6394   SeqLocPtr   slp;
6395   SeqPntPtr   spp;
6396   ValNodePtr  vnp;
6397 
6398   for (vnp = head; vnp != NULL; vnp = vnp->next) {
6399     sfp = (SeqFeatPtr) vnp->data.ptrvalue;
6400     if (sfp != NULL) {
6401       slp = sfp->location;
6402       if (slp != NULL && slp->choice == SEQLOC_PNT && slp->next == NULL) {
6403         spp = (SeqPntPtr) slp->data.ptrvalue;
6404         if (spp != NULL) {
6405           if (whichend == 1) {
6406             sintp = SeqIntNew ();
6407             if (sintp != NULL) {
6408               sintp->from = 0;
6409               sintp->to = spp->point - 1;
6410               sintp->strand = spp->strand;
6411               sintp->id = spp->id;
6412               spp->id = NULL;
6413               sintp->if_from = spp->fuzz;
6414               spp->fuzz = NULL;
6415               slp->choice = SEQLOC_INT;
6416               slp->data.ptrvalue = (Pointer) sintp;
6417               SeqPntFree (spp);
6418             }
6419           } else if (whichend == 2) {
6420             sintp = SeqIntNew ();
6421             if (sintp != NULL) {
6422               sintp->from = spp->point + 1;
6423               sintp->to = spp->point + 1 + len;
6424               sintp->strand = spp->strand;
6425               sintp->id = spp->id;
6426               spp->id = NULL;
6427               sintp->if_to = spp->fuzz;
6428               spp->fuzz = NULL;
6429               slp->choice = SEQLOC_INT;
6430               slp->data.ptrvalue = (Pointer) sintp;
6431               SeqPntFree (spp);
6432             }
6433           }
6434         }
6435       }
6436     }
6437   }
6438 }
6439 
6440 static void TrimFromSequenceEnd (EditSeqPtr  esp,
6441                                  SeqEntryPtr sep,
6442                                  BioseqPtr   bsp)
6443 {
6444   CharPtr currSeqStr;
6445   Int2    length;
6446   Int4    pos;
6447   Int4    trim_length;
6448 
6449   /* Get the current sequence string */
6450 
6451   currSeqStr = GetSequenceByBsp (bsp);
6452 
6453   /* Trim from either the 5' end (i.e., */
6454   /* the beginning of the string...     */
6455 
6456   if (esp->endval == EDIT_FIVE_PRIME)
6457   {
6458     /* Find end point */
6459 
6460     if (esp->trimByBool == TRIM_BY_SEQUENCE)
6461           {
6462             length = StringLen (esp->seqstr);
6463             if (StringNICmp (esp->seqstr, currSeqStr, length) != 0)
6464               return;
6465             pos = length - 1;
6466       trim_length = length;
6467           }
6468     else  if (esp->trimByBool == TRIM_BY_COUNT) 
6469     {
6470             pos = esp->trimCount - 1;
6471       trim_length = esp->trimCount;
6472     }
6473     else
6474             return;
6475       
6476     /* Trim from beginning of string to end point */
6477     
6478     esp->frameshift = trim_length;
6479     BioseqDelete (bsp->id, 0, pos, TRUE, FALSE);
6480     esp->extendedthis = bsp;
6481     FixAndRetranslateCDSs (bsp, sep, esp, TRUE);
6482 
6483     /* trim quality scores */
6484     TrimQualityScores (bsp, trim_length, TRUE);
6485   }
6486   
6487   /* .. or the 3' end (i.e., the */
6488   /* end of the string.          */
6489   
6490   else if (esp->endval == EDIT_THREE_PRIME)
6491   {
6492     /* Find trim point */
6493 
6494     if (esp->trimByBool == TRIM_BY_SEQUENCE)
6495           {
6496             length = StringLen (esp->seqstr);
6497             pos = bsp->length - length;
6498             if (StringICmp (esp->seqstr, &currSeqStr[pos]) != 0)
6499               return;
6500       trim_length = length;
6501           }
6502     else  if (esp->trimByBool == TRIM_BY_COUNT)
6503     {
6504             pos = bsp->length - esp->trimCount;
6505       trim_length = esp->trimCount;
6506     }
6507     else
6508             return;
6509       
6510     /* Trim from there to end of string */
6511     
6512     BioseqDelete (bsp->id, pos, bsp->length - 1, TRUE, FALSE);
6513     esp->extendedthis = bsp;
6514     FixAndRetranslateCDSs (bsp, sep, esp, FALSE);
6515 
6516     /* trim quality scores */
6517     TrimQualityScores (bsp, trim_length, FALSE);
6518   }
6519 }
6520 
6521 static void 
6522 AddToSequenceEnd 
6523 (EditSeqPtr  esp,
6524  SeqEntryPtr sep,
6525  BioseqPtr   bsp,
6526  LogInfoPtr lip)
6527 {
6528   ValNodePtr    head;
6529   Int4          len;
6530   Int4          pos;
6531   Uint1         residue;
6532   SeqPortPtr    spp;
6533   CharPtr       str;
6534   Char          terminal [2];
6535 
6536   pos = 0;
6537   if (esp->endval == 2) {
6538     pos = bsp->length;
6539   }
6540   if (esp->extendflag) {
6541     esp->frameshift = 0;
6542     terminal [0] = '\0';
6543     terminal [1] = '\0';
6544     residue = 0;
6545     if (esp->endval == 2) {
6546       spp = SeqPortNew (bsp, bsp->length - 1, -1, 0, Seq_code_iupacna);
6547     } else {
6548       spp = SeqPortNew (bsp, 0, -1, 0, Seq_code_iupacna);
6549     }
6550     if (spp != NULL) {
6551       residue = SeqPortGetResidue (spp);
6552       if (IS_residue (residue)) {
6553         terminal [0] = TO_LOWER ((Char) residue);
6554       }
6555     }
6556     SeqPortFree (spp);
6557     str = MemNew ((size_t) (StringLen (esp->seqstr) + 4));
6558     if (str != NULL) {
6559       head = NULL;
6560       if (esp->endval == 2) {
6561         esp->extendedthis = bsp;
6562         StringCpy (str, terminal);
6563         StringCat (str, esp->seqstr);
6564         len = StringLen (esp->seqstr);
6565         pos = bsp->length - 1;
6566         head = CollectAndExtendSingleBaseFeatures (bsp, 2, len);
6567         insertchar (str, pos, bsp->id, bsp->mol, FALSE);
6568         BioseqDelete (bsp->id, bsp->length - 1, bsp->length - 1,
6569                       TRUE, FALSE);
6570         ReadjustSingleBaseFeatures (head, bsp, 2, len);
6571         FixAndRetranslateCDSs (bsp, sep, esp, FALSE);
6572       } else {
6573         esp->frameshift = (Int2) StringLen (esp->seqstr);
6574         esp->extendedthis = bsp;
6575         StringCpy (str, esp->seqstr);
6576         StringCat (str, terminal);
6577         len = StringLen (esp->seqstr);
6578         pos = 1;
6579         head = CollectAndExtendSingleBaseFeatures (bsp, 1, len);
6580         insertchar (str, pos, bsp->id, bsp->mol, FALSE);
6581         BioseqDelete (bsp->id, 0, 0, TRUE, FALSE);
6582         ReadjustSingleBaseFeatures (head, bsp, 1, len);
6583         FixAndRetranslateCDSs (bsp, sep, esp, TRUE);
6584       }
6585       ValNodeFree (head);
6586       if (lip != NULL) {
6587         RemoveQualityScores (bsp, lip->fp, &(lip->data_in_log));
6588       }
6589     }
6590     MemFree (str);
6591   } else {
6592     insertchar (esp->seqstr, pos, bsp->id, bsp->mol, FALSE);
6593     if (lip != NULL) {
6594       RemoveQualityScores (bsp, lip->fp, &(lip->data_in_log));
6595     }
6596   }
6597 }
6598 
6599 
6600 static void DoEditSeqEndsProc (ButtoN b)
6601 
6602 {
6603   Char        ch;
6604   EditSeqPtr  esp;
6605   CharPtr     p, q;
6606   CharPtr     tempStr;
6607   ValNodePtr  sip_list, vnp;
6608   SeqIdPtr    sip;
6609   BioseqPtr   bsp;
6610   SeqEntryPtr sep;
6611   Boolean     add_cit_subs = FALSE;
6612   LogInfoPtr  lip;
6613 
6614   esp = (EditSeqPtr) GetObjectExtra (b);
6615   if (esp == NULL) {
6616     Remove (ParentWindow (b));
6617     return;
6618   }
6619   sip_list = GetSelectedSequenceList (esp->nuc_sequence_list_ctrl);
6620   if (sip_list == NULL)
6621   {
6622     Message (MSG_ERROR, "You have not specified any sequences to edit!");
6623     return;
6624   }
6625 
6626   Hide (esp->form);
6627   Update ();
6628   esp->seqstr = SaveStringFromText  (esp->seq);
6629   p = esp->seqstr;
6630   if (p != NULL) {
6631     /* remove any non-sequence characters */
6632     q = p;
6633     ch = *p;
6634     while (ch != '\0') {
6635       if (IS_ALPHA (ch)) {
6636         *q = ch;
6637         q++;
6638       }
6639       p++;
6640       ch = *p;
6641     }
6642     *q = '\0';
6643   }
6644   esp->genestr       = SaveStringFromText  (esp->genename);
6645   esp->endval        = GetValue (esp->whichend);
6646   esp->extendflag    = GetStatus (esp->extendfeat);
6647   esp->addOrTrimBool = GetValue (esp->addOrTrim);
6648   esp->trimByBool    = GetValue (esp->trimBy);
6649   tempStr            = SaveStringFromText (esp->trimCountText);
6650   if (tempStr != NULL)
6651     esp->trimCount   = atoi (tempStr);
6652   else
6653     esp->trimCount   = 0;
6654   
6655   add_cit_subs = GetStatus (esp->addCitSub);
6656 
6657   lip = OpenLog ("Quality Scores Affected");
6658   for (vnp = sip_list; vnp != NULL; vnp = vnp->next)
6659   {
6660     sip = (SeqIdPtr) vnp->data.ptrvalue;
6661     bsp = BioseqFind (sip);
6662     sep = SeqMgrGetSeqEntryForData (bsp);
6663     if (bsp != NULL && sep != NULL && EditSeqEntryHasGene (bsp, sep, esp))
6664     {
6665       if (esp->addOrTrimBool == 1)
6666         AddToSequenceEnd (esp, sep, bsp, lip);
6667       else
6668         TrimFromSequenceEnd (esp, sep, bsp);
6669       if (add_cit_subs)
6670       {
6671         AddCitSubToUpdatedSequence (bsp, esp->input_entityID, kSubmitterUpdateText);
6672       }
6673     }
6674   }
6675   CloseLog (lip);
6676   lip = FreeLog (lip);
6677 
6678   MemFree (esp->seqstr);
6679   MemFree (esp->genestr);
6680   ObjMgrSetDirtyFlag (esp->input_entityID, TRUE);
6681   ObjMgrSendMsg (OM_MSG_UPDATE, esp->input_entityID, 0, 0);
6682   Remove (esp->form);
6683 }
6684 
6685 static void EditSeqMessageProc (ForM f, Int2 mssg)
6686 
6687 {
6688   EditSeqPtr  esp;
6689 
6690   esp = (EditSeqPtr) GetObjectExtra (f);
6691   if (esp != NULL) {
6692     if (esp->appmessage != NULL) {
6693       esp->appmessage (f, mssg);
6694     }
6695   }
6696 }
6697 
6698 static void ChangeAddOrTrim_Callback (GrouP g)
6699 
6700 {
6701   EditSeqPtr  esp;
6702   Int2        val;
6703   Int2        trimByState;
6704 
6705   val = GetValue (g);
6706   esp = GetObjectExtra (g);
6707 
6708   switch (val) {
6709     case ADD_TO_END :
6710       SafeDisable (esp->trimBy);
6711       SafeEnable (esp->extendfeat);
6712       SafeDisable (esp->trimCountText);
6713       SafeEnable (esp->seq);
6714       break;
6715     case TRIM_FROM_END :
6716       SafeDisable (esp->extendfeat);
6717       SafeEnable (esp->trimBy);
6718       trimByState = GetValue (esp->trimBy);
6719       switch (trimByState) {
6720         case TRIM_BY_SEQUENCE :
6721           SafeDisable (esp->trimCountText);
6722           SafeEnable (esp->seq);
6723           break;
6724         case TRIM_BY_COUNT :
6725           SafeEnable (esp->trimCountText);
6726           SafeDisable (esp->seq);
6727           break;
6728         default :
6729           break;
6730       }
6731       break;
6732     default :
6733       break;
6734   }
6735 }
6736 
6737 static void ChangeTrimBy_Callback (GrouP g)
6738 
6739 {
6740   EditSeqPtr  esp;
6741   Int2        val;
6742 
6743   val = GetValue (g);
6744   esp = GetObjectExtra (g);
6745 
6746   switch (val) {
6747     case TRIM_BY_SEQUENCE :
6748       SafeDisable (esp->trimCountText);
6749       SafeEnable (esp->seq);
6750       break;
6751     case TRIM_BY_COUNT :
6752       SafeEnable (esp->trimCountText);
6753       SafeDisable (esp->seq);
6754       break;
6755     default :
6756       break;
6757   }
6758 }
6759 
6760 static void SelectAllSequencesForExtend (ButtoN b)
6761 {
6762   EditSeqPtr    esp;
6763 
6764   esp = (EditSeqPtr) GetObjectExtra (b);
6765   if (esp == NULL)
6766   {
6767     return;
6768   }
6769   SelectAllSequencesInListCtrl (esp->nuc_sequence_list_ctrl);  
6770 }
6771 
6772 static void UnSelectAllSequencesForExtend (ButtoN b)
6773 {
6774   EditSeqPtr    esp;
6775 
6776   esp = (EditSeqPtr) GetObjectExtra (b);
6777   if (esp == NULL)
6778   {
6779     return;
6780   }
6781   UnSelectAllSequencesInListCtrl (esp->nuc_sequence_list_ctrl);  
6782 }
6783 
6784 extern void EditSeqEndsProc (IteM i);
6785 
6786 extern void EditSeqEndsProc (IteM i)
6787 
6788 {
6789   ButtoN             b;
6790   BaseFormPtr        bfp;
6791   GrouP              c;
6792   EditSeqPtr         esp;
6793   GrouP              g;
6794   GrouP              h;
6795   GrouP              k;
6796   GrouP              p;
6797   GrouP              q;
6798   GrouP              r;
6799   GrouP              s;
6800   SeqEntryPtr        sep;
6801   StdEditorProcsPtr  sepp;
6802   WindoW             w;
6803 
6804 #ifdef WIN_MAC
6805   bfp = currentFormDataPtr;
6806 #else
6807   bfp = GetObjectExtra (i);
6808 #endif
6809   if (bfp == NULL) return;
6810   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
6811   if (sep == NULL) return;
6812   esp = (EditSeqPtr) MemNew (sizeof (EditSeqEnds));
6813   if (esp == NULL) return;
6814 
6815   w = FixedWindow (-50, -33, -10, -10, "Edit Sequence Ends", StdCloseWindowProc);
6816   SetObjectExtra (w, esp, StdCleanupFormProc);
6817   esp->form = (ForM) w;
6818   esp->formmessage = EditSeqMessageProc;
6819 
6820   sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
6821   if (sepp != NULL) {
6822     SetActivate (w, sepp->activateForm);
6823     esp->appmessage = sepp->handleMessages;
6824   }
6825 
6826   esp->input_entityID = bfp->input_entityID;
6827   esp->input_itemID = bfp->input_itemID;
6828   esp->input_itemtype = bfp->input_itemtype;
6829 
6830   esp->sep = sep;
6831 
6832   h = HiddenGroup (w, -1, 0, NULL);
6833   SetGroupSpacing (h, 10, 10);
6834 
6835   g = HiddenGroup (h, 2, 0, NULL);
6836 
6837   StaticPrompt (g, "End", 0, stdLineHeight, programFont, 'l');
6838   esp->whichend = HiddenGroup (g, 2, 0, NULL);
6839   RadioButton (esp->whichend, "5'");
6840   RadioButton (esp->whichend, "3'");
6841   SetValue (esp->whichend, 1);
6842 
6843   esp->addOrTrim = HiddenGroup (h, 2, 0, ChangeAddOrTrim_Callback);
6844   SetObjectExtra (esp->addOrTrim, esp, NULL);
6845   RadioButton (esp->addOrTrim, "Add to end");
6846   RadioButton (esp->addOrTrim, "Trim from end");
6847   SetValue (esp->addOrTrim, 1);
6848 
6849   k = HiddenGroup (h, 0, -2, NULL);
6850   StaticPrompt (k, "Sequence", 0, 0, programFont, 'l');
6851   esp->seq = ScrollText (k, 25, 5, programFont, TRUE, NULL);
6852 
6853   q = HiddenGroup (h, 2, 0, NULL);
6854   StaticPrompt (q, "Optional gene constraint", 0, dialogTextHeight,
6855                 programFont, 'l');
6856   esp->genename = DialogText (q, "", 14, NULL);
6857 
6858   esp->extendfeat = CheckBox (h, "Extend features", NULL);
6859 
6860   esp->trimBy = HiddenGroup (h, 2, 0, ChangeTrimBy_Callback);
6861   SetObjectExtra (esp->trimBy, esp, NULL);
6862   RadioButton (esp->trimBy, "Trim by sequence");
6863   RadioButton (esp->trimBy, "Trim by count");
6864   SetValue (esp->trimBy, 1);
6865   SafeDisable (esp->trimBy);
6866 
6867   p = HiddenGroup (h, 2, 0, NULL);
6868   StaticPrompt (p, "Trim count", 0, dialogTextHeight, programFont, 'l');
6869   esp->trimCountText = DialogText (p, "", 5, NULL);
6870   SafeDisable (esp->trimCountText);
6871   
6872   s = NormalGroup (h, -1, 0, "Choose Sequences To Edit", programFont, NULL);
6873   esp->nuc_sequence_list_ctrl = MakeSequenceListControl (s, sep, NULL, NULL, TRUE, FALSE);
6874   
6875   r = HiddenGroup (s, 2, 0, NULL);
6876   b = PushButton (r, "Select All", SelectAllSequencesForExtend);
6877   SetObjectExtra (b, esp, NULL);
6878   b = PushButton (r, "Unselect All", UnSelectAllSequencesForExtend);
6879   SetObjectExtra (b, esp, NULL);
6880   AlignObjects (ALIGN_CENTER, (HANDLE) esp->nuc_sequence_list_ctrl,
6881                 (HANDLE) r, NULL);
6882 
6883   esp->addCitSub = CheckBox (h, "Add Cit Subs to edited sequences", NULL);
6884   
6885   c = HiddenGroup (h, 4, 0, NULL);
6886   b = DefaultButton (c, "Accept", DoEditSeqEndsProc);
6887   SetObjectExtra (b, esp, NULL);
6888   PushButton (c, "Cancel", StdCancelButtonProc);
6889 
6890   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) esp->extendfeat,
6891                 (HANDLE) esp->addOrTrim, (HANDLE) esp->trimBy,
6892                 (HANDLE) k, (HANDLE) q, (HANDLE) p, 
6893                 (HANDLE) s, (HANDLE) esp->addCitSub, (HANDLE) c, NULL);
6894   RealizeWindow (w);
6895   Show (w);
6896   Select (w);
6897   Select (esp->seq);
6898   Update ();
6899 }
6900 
6901 static void SetAlignmentDim (SeqAlignPtr salp)
6902 {
6903   AMAlignIndex2Ptr amaip;
6904   DenseSegPtr      dsp;
6905   
6906   if (salp == NULL || salp->dim > 0 || salp->saip == NULL) return;
6907   
6908   if (salp->saip->indextype == INDEX_PARENT)
6909   {
6910     amaip = (AMAlignIndex2Ptr)(salp->saip);
6911     salp->dim = amaip->sharedaln->dim;
6912   }
6913   else if (salp->saip->indextype == INDEX_CHILD)
6914   {
6915     dsp = (DenseSegPtr)(salp->segs);
6916         salp->dim = dsp->dim;
6917   }
6918 }  
6919 
6920 static void IndexAlignmentSet (SeqAlignPtr salp)
6921 {
6922   SeqAlignPtr tmp_salp, next_salp;
6923   
6924   if (salp == NULL || salp->saip != NULL) return;
6925   
6926   if (salp->next != NULL && salp->dim > 2)
6927   {
6928         for (tmp_salp = salp; tmp_salp != NULL; tmp_salp = tmp_salp->next)
6929         {
6930           next_salp = tmp_salp->next;
6931           tmp_salp->next = NULL;
6932       if (tmp_salp->segtype == SAS_DENSEG  &&  tmp_salp->next == NULL) {
6933         AlnMgr2IndexSingleChildSeqAlign(tmp_salp);
6934       } else {
6935         AlnMgr2IndexSeqAlign(tmp_salp);
6936       }                 
6937       SetAlignmentDim (tmp_salp);
6938       tmp_salp->next = next_salp;
6939         }
6940   }
6941   else
6942   {
6943     if (salp->segtype == SAS_DENSEG  &&  salp->next == NULL) {
6944       AlnMgr2IndexSingleChildSeqAlign(salp);
6945     } else {
6946       AlnMgr2IndexSeqAlign(salp);
6947     }  
6948     SetAlignmentDim (salp);             
6949   }     
6950 }
6951 
6952 static void WriteSeqEntryAlignmentToFile (SeqEntryPtr sep, FILE *fp, Boolean Interleave)
6953 {
6954   BioseqSetPtr bssp;
6955   SeqAnnotPtr  sap;
6956   SeqAlignPtr  salp = NULL;
6957 
6958   if (sep == NULL || ! IS_Bioseq_set (sep)) return;
6959   bssp = (BioseqSetPtr) sep->data.ptrvalue;
6960   if (bssp == NULL) return;
6961   for (sap = bssp->annot; sap != NULL; sap = sap->next) {
6962     if (sap->type == 2) {
6963       salp = SeqAlignListDup((SeqAlignPtr) sap->data);
6964       IndexAlignmentSet (salp);
6965 
6966       if (Interleave) {
6967         if (salp->next != NULL)
6968         {
6969           Message (MSG_ERROR, "Unable to write segmented alignments as interleave");
6970           return;
6971         }
6972         WriteAlignmentInterleaveToFile (salp, fp, 40, FALSE);
6973       } else {
6974         WriteAlignmentContiguousToFile (salp, fp, 40, FALSE);
6975       }
6976       SeqAlignFree (salp);
6977       salp = NULL;
6978     }
6979   }
6980 
6981   for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
6982     WriteSeqEntryAlignmentToFile (sep, fp, Interleave);
6983   }
6984 }
6985 
6986 static void ExportAlignment (IteM i, Boolean Interleave)
6987 {
6988   BaseFormPtr bfp;
6989   SeqEntryPtr sep;
6990   Char        path [PATH_MAX];
6991   FILE *      fp;
6992 
6993 #ifdef WIN_MAC
6994   bfp = currentFormDataPtr;
6995 #else
6996   bfp = GetObjectExtra (i);
6997 #endif
6998   if (bfp == NULL) return;
6999   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
7000   if (sep == NULL) return;
7001 
7002   if (! GetOutputFileName (path, sizeof (path), "")) return;
7003   if (! StringHasNoText (path)) {
7004     fp = FileOpen (path, "w");
7005     if (fp != NULL) {
7006       WatchCursor ();
7007       Update();
7008       WriteSeqEntryAlignmentToFile (sep, fp, Interleave);
7009       ArrowCursor ();
7010       Update();
7011       FileClose (fp);
7012     } else {
7013       Message (MSG_ERROR, "Unable to open file");
7014     }
7015   }
7016 }
7017 
7018 extern void ExportAlignmentInterleave (IteM i)
7019 {
7020   ExportAlignment (i, TRUE);
7021 }
7022 
7023 extern void ExportAlignmentContiguous (IteM i)
7024 {
7025   ExportAlignment (i, FALSE);
7026 }
7027 
7028 static Int4 FindFeaturePos (SeqIdPtr sip, SeqAlignPtr salp, Int4 pos)
7029 {
7030   Int4        aln_row;
7031   Int4        new_pos;
7032   
7033   if (sip == NULL || salp == NULL) return pos;
7034   aln_row = AlnMgr2GetFirstNForSip(salp, sip);
7035   if (aln_row > 0)
7036   {
7037         new_pos = AlnMgr2MapSeqAlignToBioseq (salp, pos, aln_row);
7038         if (new_pos < 0)
7039         {
7040           return pos;
7041         }
7042         else
7043         {
7044           return new_pos;
7045         }
7046   }
7047   return pos;
7048 }
7049 
7050 static void FixFeatureIntervalSeqLoc (SeqLocPtr slp, SeqAlignPtr salp)
7051 {
7052   SeqIntPtr     sintp;
7053   SeqBondPtr    sbp;
7054   SeqPntPtr     spp;
7055   SeqIdPtr      tmpsip;
7056   SeqLocPtr     this_slp;
7057  
7058   if (slp == NULL || slp->data.ptrvalue == NULL || salp == NULL) return;
7059 
7060   tmpsip = SeqIdPtrFromSeqAlign (salp);
7061 
7062   switch (slp->choice)
7063   {
7064     case SEQLOC_INT:
7065       sintp = slp->data.ptrvalue;
7066       sintp->from = FindFeaturePos (sintp->id, salp, sintp->from);
7067       sintp->to = FindFeaturePos (sintp->id, salp, sintp->to);
7068       break;
7069         case SEQLOC_PNT:
7070           spp = slp->data.ptrvalue;
7071           spp->point = FindFeaturePos (spp->id, salp, spp->point);
7072           break;
7073     case SEQLOC_BOND:   /* bond -- 2 seqs */
7074       sbp = (SeqBondPtr)(slp->data.ptrvalue);
7075       spp = sbp->a;
7076           spp->point = FindFeaturePos (spp->id, salp, spp->point);
7077       spp = sbp->b;
7078           spp->point = FindFeaturePos (spp->id, salp, spp->point);
7079       break;
7080     case SEQLOC_MIX:    /* mix -- more than one seq */
7081     case SEQLOC_EQUIV:    /* equiv -- ditto */
7082     case SEQLOC_PACKED_INT:    /* packed int */
7083       for (this_slp = slp->data.ptrvalue; this_slp != NULL; this_slp = this_slp->next)
7084       {
7085         FixFeatureIntervalSeqLoc (this_slp, salp);
7086       }
7087       break;
7088     default:
7089       break;    
7090   }
7091 }
7092 
7093 typedef struct featurefixdata 
7094 {
7095   Uint2 entityID;
7096   SeqAlignPtr salp;     
7097 } FeatureFixData, PNTR FeatureFixPtr;
7098 
7099 static void FixFeatureIntervalCallback (SeqFeatPtr sfp, Pointer userdata)
7100 
7101 {
7102   BioseqPtr     bsp;
7103   FeatureFixPtr ffp;
7104  
7105   if (sfp == NULL || userdata == NULL) return;  
7106   
7107   ffp = (FeatureFixPtr) userdata;
7108  
7109   FixFeatureIntervalSeqLoc (sfp->location, ffp->salp);
7110   if (sfp->idx.subtype == FEATDEF_CDS)
7111   {
7112     bsp = BioseqFindFromSeqLoc (sfp->location);
7113         SeqEdTranslateOneCDS (sfp, bsp, ffp->entityID, Sequin_GlobalAlign2Seq);
7114   }
7115 }
7116 
7117 extern void FixFeatureIntervals (IteM i)
7118 {
7119   BaseFormPtr    bfp;
7120   SeqEntryPtr    sep;
7121   FeatureFixData ffd;
7122 
7123 #ifdef WIN_MAC
7124   bfp = currentFormDataPtr;
7125 #else
7126   bfp = GetObjectExtra (i);
7127 #endif
7128   if (bfp == NULL) return;
7129   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
7130   if (sep == NULL) return;
7131 
7132   ffd.entityID = bfp->input_entityID;
7133   ffd.salp = SeqAlignListDup((SeqAlignPtr) FindSeqAlignInSeqEntry (sep, OBJ_SEQALIGN));
7134   if (ffd.salp == NULL)
7135   {
7136     Message (MSG_ERROR, "No alignment present - cannot remap intervals");
7137     return;
7138   }
7139       
7140   if (ffd.salp->segtype == SAS_DENSEG  &&  ffd.salp->next == NULL) 
7141   {
7142     AlnMgr2IndexSingleChildSeqAlign(ffd.salp);
7143   } else {
7144     AlnMgr2IndexSeqAlign(ffd.salp);
7145   }
7146 
7147   VisitFeaturesInSep (sep, (Pointer) &ffd, FixFeatureIntervalCallback);
7148   SeqAlignFree (ffd.salp);
7149 
7150   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
7151   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
7152 }
7153 
7154 typedef struct objstringdata 
7155 {
7156   StringConstraintXPtr scp;
7157   Boolean found;        
7158 } ObjStringData, PNTR ObjStringPtr;
7159 
7160 static void LIBCALLBACK AsnWriteStringConstraintCallBack (AsnExpOptStructPtr pAEOS)
7161 
7162 {
7163   CharPtr        pchSource;
7164   ObjStringPtr   osp;
7165 
7166   osp = (ObjStringPtr) pAEOS->data;
7167   if (ISA_STRINGTYPE (AsnFindBaseIsa (pAEOS->atp))) 
7168   {
7169           pchSource = (CharPtr) pAEOS->dvp->ptrvalue;
7170     if (DoesStringMatchConstraintX (pchSource, osp->scp))
7171     {
7172       osp->found = TRUE;
7173     }
7174   }
7175 }
7176 
7177 static Boolean DoesBioseqMatchStringConstraint (BioseqPtr bsp, StringConstraintXPtr scp)
7178 
7179 {
7180   ObjMgrPtr         omp;
7181   ObjMgrTypePtr     omtp;
7182   AsnExpOptPtr      aeop;
7183   AsnIoPtr          aip;
7184   ObjStringData     osd;
7185 
7186   omp = ObjMgrGet ();
7187   if (omp == NULL) return FALSE;
7188   omtp = ObjMgrTypeFind (omp, OBJ_BIOSEQ, NULL, NULL);
7189   if (omtp == NULL) return FALSE;
7190   
7191   aip = AsnIoNullOpen ();
7192   aeop = AsnExpOptNew (aip, NULL, NULL, AsnWriteStringConstraintCallBack);
7193   if (aeop != NULL) {
7194     aeop->user_data = (Pointer) &osd;
7195   }
7196   osd.scp = scp;
7197 
7198   osd.found = FALSE;
7199   (omtp->asnwrite) (bsp, aip, NULL);
7200   AsnIoClose (aip);   
7201   
7202   if (scp != NULL && scp->not_present)
7203   {
7204     osd.found = ! osd.found;
7205   }
7206   
7207   return osd.found;
7208 }
7209 
7210 
7211 extern Boolean DoBioseqFeaturesMatchSequenceConstraintX (BioseqPtr bsp, ValNodePtr feat_list, StringConstraintXPtr scp)
7212 {
7213   AsnExpOptPtr            aeop;
7214   AsnIoPtr                aip;
7215   ObjStringData           osd;
7216   SeqFeatPtr              sfp;
7217   ObjMgrPtr               omp;
7218   ObjMgrTypePtr           omtp;
7219   SeqMgrFeatContext       fcontext;
7220   ValNodePtr              vnp;
7221   
7222   if (bsp == NULL) return FALSE;
7223   if (scp == NULL) return TRUE; 
7224   omp = ObjMgrGet ();
7225   if (omp == NULL) return FALSE;
7226   omtp = ObjMgrTypeFind (omp, OBJ_SEQFEAT, NULL, NULL);
7227   if (omtp == NULL) return FALSE;
7228 
7229   aip = AsnIoNullOpen ();
7230   osd.scp = scp;
7231   
7232   aeop = AsnExpOptNew (aip, NULL, NULL, AsnWriteStringConstraintCallBack);
7233   if (aeop != NULL) {
7234     aeop->user_data = (Pointer) &osd;
7235   }
7236 
7237   for (vnp = feat_list; vnp != NULL; vnp = vnp->next)
7238   {
7239     for (sfp = SeqMgrGetNextFeature (bsp, NULL, 0, vnp->choice, &fcontext);
7240          sfp != NULL;
7241          sfp = SeqMgrGetNextFeature (bsp, sfp, 0, vnp->choice, &fcontext))
7242     {
7243       osd.found = FALSE;
7244       (omtp->asnwrite) (sfp, aip, NULL);
7245       if (osd.found)
7246       {
7247         if (scp->not_present)
7248         {
7249           AsnIoClose (aip);
7250           return FALSE;
7251         }
7252         else
7253         {
7254           AsnIoClose (aip);
7255           return TRUE;
7256         }
7257       }
7258     }
7259   }
7260   AsnIoClose (aip);
7261   if (scp->not_present)
7262   {
7263     return TRUE;
7264   }
7265   else
7266   {
7267     return FALSE;
7268   }
7269 }
7270  
7271 
7272 typedef struct keywordform 
7273 {
7274   FORM_MESSAGE_BLOCK
7275   DialoG string_src_dlg;
7276   DialoG string_constraint_dlg;
7277   TexT   keyword_txt;
7278   
7279   ParseFieldPtr pfp;
7280   FilterSetPtr  fsp;
7281   CharPtr       keyword;
7282 } KeywordFormData, PNTR KeywordFormPtr;
7283 
7284 
7285 static void ApplyKeywordCallback (BioseqPtr bsp, Pointer userdata)
7286 {
7287   SeqEntryPtr             sep;
7288   ValNodePtr              vnp;
7289   KeywordFormPtr scfp;
7290   GBBlockPtr              gbp;
7291   GetSamplePtr            gsp;
7292   Boolean                 ok_to_add = TRUE;
7293   
7294   sep = SeqMgrGetSeqEntryForData (bsp);
7295   if (sep == NULL)
7296   {
7297     return;
7298   }
7299   
7300   scfp = (KeywordFormPtr) userdata;
7301   
7302   if (scfp->pfp != NULL && scfp->fsp != NULL)
7303   {
7304     gsp = GetSampleForSeqEntry (sep, bsp->idx.entityID, scfp->pfp, scfp->fsp);
7305     if (gsp == NULL || gsp->num_found == 0)
7306     {
7307       ok_to_add = FALSE;
7308     }
7309     gsp = GetSampleFree (gsp);
7310   }
7311   
7312   if (!ok_to_add)
7313   {
7314     return;
7315   }
7316       
7317         vnp = GetDescrOnSeqEntry (sep, Seq_descr_genbank);
7318         if (vnp == NULL) {
7319                 vnp = NewDescrOnSeqEntry (sep, Seq_descr_genbank);
7320                 if (vnp != NULL) {
7321                         vnp->data.ptrvalue = (Pointer) GBBlockNew ();
7322                 }
7323         }
7324         if (vnp == NULL) return;
7325         gbp = (GBBlockPtr) vnp->data.ptrvalue;
7326         if (gbp == NULL)
7327         {
7328           gbp = GBBlockNew ();
7329           vnp->data.ptrvalue = gbp;
7330         }
7331         if (gbp == NULL) return;
7332         
7333         for (vnp = gbp->keywords; vnp; vnp = vnp->next) {
7334                 if (StringCmp((CharPtr)vnp->data.ptrvalue, scfp->keyword) == 0) {
7335                         return;
7336                 }
7337         }
7338         ValNodeAddPointer (&(gbp->keywords), 0, StringSave (scfp->keyword));
7339 }
7340 
7341 static void RemoveKeywordCallback (BioseqPtr bsp, Pointer userdata)
7342 {
7343   SeqEntryPtr             sep;
7344   ValNodePtr              vnp, prev_keyword, next_keyword;
7345   KeywordFormPtr scfp;
7346   GBBlockPtr              gbp;
7347   GetSamplePtr            gsp;
7348   Boolean                 ok_to_remove = TRUE;
7349   
7350   sep = SeqMgrGetSeqEntryForData (bsp);
7351   if (sep == NULL)
7352   {
7353     return;
7354   }
7355   
7356   scfp = (KeywordFormPtr) userdata;
7357   
7358   if (scfp->pfp != NULL && scfp->fsp != NULL)
7359   {
7360     gsp = GetSampleForSeqEntry (sep, bsp->idx.entityID, scfp->pfp, scfp->fsp);
7361     if (gsp == NULL || gsp->num_found == 0)
7362     {
7363       ok_to_remove = FALSE;
7364     }
7365     gsp = GetSampleFree (gsp);
7366   }
7367   
7368   if (!ok_to_remove)
7369   {
7370     return;
7371   }
7372       
7373         vnp = GetDescrOnSeqEntry (sep, Seq_descr_genbank);
7374   /* no GenBank descriptor, no keywords to remove */
7375         if (vnp == NULL) return;
7376         
7377         gbp = (GBBlockPtr) vnp->data.ptrvalue;
7378         /* No GBBlock, no keywords to remove */
7379         if (gbp == NULL) return;
7380         
7381   prev_keyword = NULL;
7382         for (vnp = gbp->keywords; vnp; vnp = next_keyword) {
7383           next_keyword = vnp->next;
7384                 if (StringICmp((CharPtr)vnp->data.ptrvalue, scfp->keyword) == 0) {
7385                         if (prev_keyword == NULL)
7386                         {
7387                           gbp->keywords = next_keyword;
7388                         }
7389                         else
7390                         {
7391                           prev_keyword->next = next_keyword;
7392                         }
7393                         vnp->next = NULL;
7394                         ValNodeFreeData (vnp);
7395                 }
7396                 else
7397                 {
7398                   prev_keyword = vnp;
7399                 }
7400         }
7401 }
7402 
7403 static void ApplyKeyword (IteM i, CharPtr keyword)
7404 {
7405   BaseFormPtr     bfp;
7406   SeqEntryPtr     sep;
7407   KeywordFormData kfd;
7408 
7409 #ifdef WIN_MAC
7410   bfp = currentFormDataPtr;
7411 #else
7412   bfp = GetObjectExtra (i);
7413 #endif
7414   if (bfp == NULL) return;
7415   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
7416   if (sep == NULL) return;
7417   
7418   kfd.pfp = NULL;
7419   kfd.fsp = NULL;
7420   kfd.keyword = keyword;
7421   
7422   VisitBioseqsInSep (sep, &kfd, ApplyKeywordCallback);
7423 
7424   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
7425   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
7426   ArrowCursor ();
7427   Update ();   
7428 }
7429 
7430 extern void ApplyGDSKeyword (IteM i)
7431 {
7432   ApplyKeyword (i, "GDS");
7433 }
7434 
7435 extern void ApplyTPAInferentialKeyword (IteM i)
7436 {
7437   ApplyKeyword (i, "TPA:inferential");
7438 }
7439 
7440 extern void ApplyTPAExperimentalKeyword (IteM i)
7441 {
7442   ApplyKeyword (i, "TPA:experimental");
7443 }
7444 
7445 extern void ApplyTPAReassemblyKeyword (IteM i)
7446 {
7447   ApplyKeyword (i, "TPA:reassembly");
7448 }
7449 
7450 static void DoRemoveKeywords (ButtoN b)
7451 {
7452   KeywordFormPtr scfp;
7453   SeqEntryPtr    sep;
7454   
7455   scfp = (KeywordFormPtr) GetObjectExtra (b);
7456   if (scfp == NULL)
7457   {
7458     return;
7459   }
7460   
7461   scfp->pfp = (ParseFieldPtr) DialogToPointer (scfp->string_src_dlg);
7462   scfp->fsp = FilterSetNew ();
7463   scfp->fsp->scp = (StringConstraintXPtr) DialogToPointer (scfp->string_constraint_dlg);
7464   scfp->keyword = SaveStringFromText (scfp->keyword_txt);
7465   
7466   sep = GetTopSeqEntryForEntityID (scfp->input_entityID);
7467   if (sep == NULL) return;
7468   
7469   VisitBioseqsInSep (sep, scfp, RemoveKeywordCallback);
7470 
7471   scfp->fsp = FilterSetFree (scfp->fsp);
7472   scfp->pfp = ParseFieldFree (scfp->pfp);
7473 
7474   ObjMgrSetDirtyFlag (scfp->input_entityID, TRUE);
7475   ObjMgrSendMsg (OM_MSG_UPDATE, scfp->input_entityID, 0, 0);
7476   ArrowCursor ();
7477   Update ();   
7478   Remove (scfp->form);  
7479 }
7480 
7481 extern void RemoveKeywordWithStringConstraint (IteM i)
7482 {
7483   BaseFormPtr    bfp;
7484   KeywordFormPtr scfp;
7485   WindoW         w;
7486   PrompT         ppt;
7487   GrouP          h, g, c;
7488   ButtoN         b;
7489 
7490 #ifdef WIN_MAC
7491   bfp = currentFormDataPtr;
7492 #else
7493   bfp = GetObjectExtra (i);
7494 #endif
7495   if (bfp == NULL) return;
7496 
7497   scfp = (KeywordFormPtr) MemNew (sizeof (KeywordFormData));
7498   if (scfp == NULL) return;
7499   
7500   w = FixedWindow (-50, -33, -10, -10, "Remove Keywords", StdCloseWindowProc);
7501   SetObjectExtra (w, scfp, StdCleanupExtraProc);
7502   scfp->form = (ForM) w;
7503   scfp->input_entityID = bfp->input_entityID;
7504   
7505   h = HiddenGroup (w, -1, 0, NULL);
7506   SetGroupSpacing (h, 10, 10);
7507   
7508   g = HiddenGroup (h, 2, 0, NULL);
7509   SetGroupSpacing (g, 10, 10);
7510   StaticPrompt (g, "Remove Keyword", 0, 0, programFont, 'l');
7511   scfp->keyword_txt = DialogText (g, "", 30, NULL);
7512   
7513   ppt = StaticPrompt (h, "Where", 0, 0, programFont, 'l');
7514   scfp->string_src_dlg = ParseFieldDestDialogEx (h, NULL, NULL, FALSE, TRUE);
7515 
7516   scfp->string_constraint_dlg = StringConstraintDialogX (h, NULL, FALSE);
7517   
7518   c = HiddenGroup (h, 2, 0, NULL);
7519   b = PushButton (c, "Accept", DoRemoveKeywords);
7520   SetObjectExtra (b, scfp, NULL);
7521   b = PushButton (c, "Cancel", StdCancelButtonProc);
7522   
7523   AlignObjects (ALIGN_CENTER, (HANDLE) g,
7524                               (HANDLE) ppt,
7525                               (HANDLE) scfp->string_src_dlg,
7526                               (HANDLE) scfp->string_constraint_dlg,
7527                               (HANDLE) c,
7528                               NULL);
7529   RealizeWindow (w);
7530   Show (w);
7531   Select (w);
7532   Update ();
7533 }
7534 
7535 
7536 static CharPtr RNAstrandcmd = NULL;
7537 
7538 typedef struct rnastrand 
7539 {
7540   FORM_MESSAGE_BLOCK
7541   
7542   ParData rnaParFmt;
7543   ColData rnaColFmt[3];  
7544   
7545   DoC        doc;
7546   ButtoN     rev_feats;
7547   ButtoN     use_smart_btn;
7548   SeqEntryPtr sep;
7549   ValNodePtr sequence_list;
7550   Int4       num_sequences;
7551   BoolPtr    selected;
7552   Int2       lineheight;  
7553   CharPtr    database;
7554   Boolean    use_smart;
7555 } RNAStrandData, PNTR RNAStrandPtr;
7556 
7557 typedef enum 
7558 {
7559   RNAstrand_PLUS = 1,
7560   RNAstrand_MINUS,
7561   RNAstrand_MIXED,
7562   RNAstrand_NO_HITS,
7563   RNAstrand_UNEXPECTED,
7564   RNAstrand_PARSE_ERROR,
7565   RNAstrand_IN_PROGRESS
7566 } ERNAstrand_return_val;
7567 
7568 static CharPtr RNAstrand_strings[] = 
7569 { "Plus", "Minus", "Mixed", "No Hits", "Unexpected", "Parse Error", "In Progress" };
7570 
7571 
7572 typedef enum 
7573 {
7574   RNASTRANDGRP_ERROR = 0,
7575   RNASTRANDGRP_NO_HITS,
7576   RNASTRANDGRP_MIXED,
7577   RNASTRANDGRP_MINUS,
7578   RNASTRANDGRP_PLUS
7579 } ERNAstrand_group_num;
7580 
7581 static ERNAstrand_group_num GetRNAStrandGroupNum (ValNodePtr vnp)
7582 {
7583   if (vnp == NULL) return RNASTRANDGRP_ERROR;
7584   else if (vnp->choice == RNAstrand_NO_HITS) return RNASTRANDGRP_NO_HITS;
7585   else if (vnp->choice == RNAstrand_MINUS) return RNASTRANDGRP_MINUS;
7586   else if (vnp->choice == RNAstrand_MIXED) return RNASTRANDGRP_MIXED;
7587   else if (vnp->choice == RNAstrand_PLUS) return RNASTRANDGRP_PLUS;
7588   else return RNASTRANDGRP_ERROR;
7589 }
7590 
7591 
7592 static void LimitAlignmentResults (SeqAlignPtr salp, Int4 num_results)
7593 {
7594   Int4        k = 0;
7595   SeqAlignPtr tmp_salp, last_salp = NULL;
7596   
7597   while (salp != NULL && k < num_results)
7598   {
7599     last_salp = salp;
7600     salp = salp->next;
7601     k++;
7602   }
7603   if (last_salp != NULL)
7604   {
7605     last_salp->next = NULL;
7606   }
7607   while (salp != NULL)
7608   {
7609     tmp_salp = salp->next;
7610     salp->next = NULL;
7611     salp = SeqAlignFree (salp);
7612     salp = tmp_salp;
7613   }
7614 }
7615 
7616 
7617 static SBlastOptions*
7618 RNABlastOptionNew(void)
7619 
7620 {
7621         SBlastOptions* options;
7622         Int2           rval;
7623         Blast_SummaryReturn *extra_returns;
7624 
7625 
7626   extra_returns = Blast_SummaryReturnNew();
7627   rval = SBlastOptionsNew("blastn", &options,
7628                           extra_returns);
7629 
7630         if (options == NULL)
7631                 return NULL;
7632 
7633   /* This replaces:
7634    * options->expect_value = 1; 
7635    */
7636   SBlastOptionsSetEvalue(options, 1);
7637 
7638   /* This replaces:
7639    * options->filter_string = StringSave("m L"); 
7640    */
7641   SBlastOptionsSetFilterString(options, "m L");
7642   
7643   /* This replaces the following:
7644    * options->mb_template_length = 18;
7645    * options->mb_disc_type = MB_WORD_CODING; 
7646    * options->is_megablast_search = TRUE;
7647    * options->discontinuous = TRUE;
7648    */
7649   SBlastOptionsSetDiscMbParams(options, 18, MB_WORD_CODING);
7650 
7651   /* This replaces:
7652    * options->wordsize = 11; \
7653    */
7654         SBlastOptionsSetWordSize (options, 11);
7655         
7656   /* This replaces:
7657    * options->hitlist_size = 20; 
7658    */
7659   options->hit_options->hitlist_size = 20;
7660   
7661   /* This replaces the following:
7662    * options->multiple_hits_only  = TRUE;
7663    * options->window_size = 40; 
7664    */
7665   options->word_options->window_size = 40;
7666   
7667   /* This replaces the following:
7668    * options->reward = 1;
7669          * options->penalty = -3;
7670          * options->gap_open = 5;
7671          * options->gap_extend = 2; 
7672          */
7673   SBlastOptionsSetRewardPenaltyAndGapCosts(options, 2, -3, 5, 2, FALSE);
7674         
7675         extra_returns = Blast_SummaryReturnFree(extra_returns);
7676         return options;
7677 }
7678 
7679 #if 0
7680 const CharPtr kRNAStrandDatabaseName = "rRNAstrand";
7681 #else
7682 const CharPtr kRNAStrandDatabaseName = "rRNA_blast";
7683 #endif
7684 
7685 static Int4
7686 RNAScreenSequence(BioseqPtr bsp, CharPtr database, SeqAlignPtr PNTR seqalign_ptr)
7687 
7688 {
7689         SBlastOptions *blast_options;
7690         Int2 retval=0;
7691         SeqAlignPtr seqalign = NULL;
7692         SeqLocPtr   slp;
7693         SBlastSeqalignArray* seqalign_arr = NULL;
7694         Blast_SummaryReturn *extra_returns;
7695 
7696         if (bsp == NULL)
7697                 return -1;
7698 
7699         if (seqalign_ptr)
7700                 *seqalign_ptr = NULL;
7701 
7702         blast_options = RNABlastOptionNew();
7703         if (blast_options == NULL)
7704                 return -1;
7705         
7706         slp = SeqLocWholeNew(bsp);
7707         if (database == NULL) 
7708           database = kRNAStrandDatabaseName;
7709         
7710         extra_returns = Blast_SummaryReturnNew();
7711 
7712   retval = Blast_DatabaseSearch(slp, NULL, database, NULL, blast_options, NULL, &seqalign_arr, NULL, extra_returns);
7713         extra_returns = Blast_SummaryReturnFree(extra_returns);
7714         blast_options = SBlastOptionsFree(blast_options);  
7715         
7716         if (retval == 0 && seqalign_arr != NULL && seqalign_arr->num_queries >0)
7717         {
7718           seqalign = seqalign_arr->array[0];
7719           seqalign_arr->array[0] = NULL;
7720         }
7721         
7722         seqalign_arr = SBlastSeqalignArrayFree(seqalign_arr);
7723         
7724         /* limit results to first 20 alignments, as SMART does */
7725         LimitAlignmentResults (seqalign, 20);   
7726         
7727         if (seqalign)
7728         {
7729                 if (seqalign_ptr)
7730                         *seqalign_ptr = seqalign;
7731         }       
7732 
7733 
7734         return retval;
7735 }
7736 
7737 
7738 typedef struct rnastrandcollection
7739 {
7740   ValNodePtr sequence_list;
7741   Char       path [PATH_MAX];
7742   CharPtr    database;
7743   Int4       count;
7744   Int4       total;
7745   MonitorPtr mon;
7746 } RNAStrandCollectionData, PNTR RNAStrandCollectionPtr;
7747 
7748 static Uint1 GetStatusForAlignmentList (SeqAlignPtr salp)
7749 {
7750   Uint1 status = RNAstrand_NO_HITS;
7751   Uint1 strand;
7752   
7753   while (salp != NULL)
7754   {
7755     AlnMgr2IndexSingleChildSeqAlign(salp);
7756     strand = AlnMgr2GetNthStrand(salp, 1);
7757     if (status == RNAstrand_NO_HITS)
7758     {
7759       if (strand == Seq_strand_plus)
7760       {
7761         status = RNAstrand_PLUS;
7762       }
7763       else if (strand == Seq_strand_minus)
7764       {
7765         status = RNAstrand_MINUS;
7766       }
7767       else
7768       {
7769         return RNAstrand_UNEXPECTED;
7770       }
7771     }
7772     else if (strand == Seq_strand_plus)
7773     {
7774       if (status != RNAstrand_PLUS)
7775       {
7776         return RNAstrand_MIXED;
7777       }
7778     }
7779     else if (strand == Seq_strand_minus)
7780     {
7781       if (status != RNAstrand_MINUS)
7782       {
7783         return RNAstrand_MIXED;
7784       }
7785     }
7786     else
7787     {
7788       return RNAstrand_UNEXPECTED;
7789     }
7790     salp = salp->next;
7791   }
7792   return status;  
7793 }
7794 
7795 static void GetOneRNAStrandednessInfo (BioseqPtr bsp, Pointer userdata)
7796 {
7797   RNAStrandCollectionPtr rscp;
7798   SeqAlignPtr            salp = NULL;
7799   
7800   if (bsp == NULL || !ISA_na (bsp->mol) || userdata == NULL)
7801   {
7802     return;
7803   }
7804   
7805   rscp = (RNAStrandCollectionPtr) userdata;
7806 
7807   if (rscp->mon != NULL) {
7808     MonitorIntValue (rscp->mon, rscp->count);
7809   }
7810   (rscp->count)++;
7811   
7812   RNAScreenSequence(bsp, rscp->path, &salp);
7813 
7814   ValNodeAddPointer (&(rscp->sequence_list), 
7815                      GetStatusForAlignmentList(salp),
7816                      SeqIdFindBest (bsp->id, SEQID_GENBANK));
7817   salp = SeqAlignFree (salp);  
7818 }
7819 
7820 static void CountRNASequences (BioseqPtr bsp, Pointer userdata)
7821 {
7822   RNAStrandCollectionPtr rscp;
7823 
7824   if (bsp == NULL || !ISA_na (bsp->mol) || userdata == NULL)
7825   {
7826     return;
7827   }
7828   
7829   rscp = (RNAStrandCollectionPtr) userdata;
7830   
7831   rscp->total++;  
7832 }
7833 
7834 static ValNodePtr GetRNAStrandednessFromLocalDatabase (SeqEntryPtr sep, CharPtr database)
7835 {
7836   RNAStrandCollectionData rscd;
7837   
7838   if (sep == NULL) return NULL;
7839 
7840   rscd.path [0] = '\0';
7841   GetAppParam ("NCBI", "NCBI", "DATA", "", rscd.path, sizeof (rscd.path));
7842   FileBuildPath (rscd.path, NULL, database);
7843   
7844   rscd.database = database;
7845   rscd.sequence_list = NULL;
7846   rscd.total = 0;
7847   rscd.count = 0;
7848   rscd.mon = NULL;
7849   
7850   VisitBioseqsInSep (sep, &rscd, CountRNASequences);
7851   if (rscd.total > 2)
7852   {
7853     rscd.mon = MonitorIntNewEx ("RNA Strand Progress", 0, rscd.total - 1, FALSE);
7854   }
7855   
7856   VisitBioseqsInSep (sep, &rscd, GetOneRNAStrandednessInfo);  
7857   
7858   if (rscd.mon != NULL) {
7859     rscd.mon = MonitorFree (rscd.mon);
7860     Update ();
7861   }
7862   
7863   return rscd.sequence_list;
7864 }
7865 
7866 static void GetAccessionList (BioseqPtr bsp, Pointer userdata)
7867 {
7868   ValNodePtr PNTR sequence_list;
7869   SeqIdPtr        sip;
7870 
7871   if (bsp == NULL || userdata == NULL) return;
7872 
7873   sequence_list = (ValNodePtr PNTR) userdata;
7874 
7875   for (sip = bsp->id; sip != NULL; sip = sip->next)
7876   {
7877     if (sip->choice == SEQID_GENBANK)
7878     {
7879       ValNodeAddPointer (sequence_list, 0, sip);
7880       return;
7881     }
7882   }
7883 }
7884 
7885 
7886 /* Looks at a portion of the list of sequences for strand correction.
7887  * Returns the number of sequences examined.
7888  */
7889 static Int4
7890 GetSubListForRNAStrandCorrection
7891 (ValNodePtr start_list,
7892  Int4       num_seqs,
7893  CharPtr    RNAstrandcmd)
7894 {
7895   Int4                    seq_num, cmd_len = 0, k;
7896   ValNodePtr              vnp;
7897   FILE *                  fp;
7898   CharPtr                 args = NULL, cp, cp2, cmmd;
7899   Char                    tmp_id [256];
7900   Char                    path [PATH_MAX];
7901   Char                    file_line [256];
7902   Boolean                 found_id;
7903 #ifdef OS_MAC
7904   CharPtr                 cmd_format = "%s -a \'%s\' > %s"; /* just to allow compilation */
7905 #endif
7906 #ifdef OS_UNIX
7907   CharPtr                 cmd_format = "%s -a \'%s\' > %s";
7908 #endif
7909 #ifdef OS_MSWIN
7910   CharPtr                 cmd_format = "%s -a \"%s\" > %s";
7911 #endif
7912 
7913   if (start_list == NULL || num_seqs < 1 || StringHasNoText (RNAstrandcmd))
7914   {
7915     return 0;
7916   }
7917 
7918   TmpNam (path);
7919  
7920   /* calculate length of string needed for command */
7921   for (vnp = start_list, seq_num = 0;
7922            vnp != NULL && seq_num < num_seqs;
7923            vnp = vnp->next, seq_num++)
7924   {
7925     SeqIdWrite (vnp->data.ptrvalue, tmp_id, PRINTID_TEXTID_ACC_ONLY, sizeof (tmp_id) - 1);
7926     cmd_len += StringLen (tmp_id) + 3;
7927   }
7928 
7929   args = (CharPtr) MemNew (cmd_len * sizeof (Char));
7930   if (args == NULL)
7931   {
7932         Message (MSG_ERROR, "Unable to allocate memory for strand script argument list");
7933     return 0;
7934   }
7935 
7936   cp = args;
7937   for (vnp = start_list, seq_num = 0;
7938            vnp != NULL && seq_num < num_seqs;
7939            vnp = vnp->next, seq_num++)
7940   {
7941     SeqIdWrite (vnp->data.ptrvalue, cp, PRINTID_TEXTID_ACC_ONLY, cmd_len - (cp - args) - 1);
7942     cp += StringLen (cp);
7943     if (vnp->next != NULL && seq_num < num_seqs - 1)
7944     {
7945 #ifdef OS_UNIX
7946       StringCat (cp, ",");
7947       cp ++;
7948 #else
7949       StringCat (cp, ", ");
7950       cp += 2;
7951 #endif
7952     }
7953   }
7954 
7955 
7956   cmd_len += 3 + StringLen (cmd_format) + StringLen (RNAstrandcmd) + StringLen (path);
7957   cmmd = (CharPtr) MemNew (cmd_len * sizeof (Char));
7958   if (cmmd == NULL)
7959   {
7960     args = MemFree (args);
7961         Message (MSG_ERROR, "Unable to allocate memory for RNA strand script command");
7962     return 0;
7963   }
7964 
7965 #ifdef OS_UNIX
7966   sprintf (cmmd, cmd_format, RNAstrandcmd, args, path);
7967   system (cmmd);
7968 #endif
7969 #ifdef OS_MSWIN
7970   sprintf (cmmd, cmd_format, RNAstrandcmd, args, path);
7971   RunSilent (cmmd);
7972 #endif
7973  
7974   args = MemFree (args);
7975   cmmd = MemFree (cmmd);
7976  
7977   fp = FileOpen (path, "r");
7978   if (fp == NULL) {
7979     FileRemove (path);
7980     return 0;
7981   }
7982 
7983 
7984   while (fgets (file_line, sizeof (file_line) - 1, fp) != NULL)
7985   {
7986     /* find SeqId that matches file line */
7987     cp = StringChr (file_line, '\t');
7988     if (cp == NULL)
7989     {
7990       continue;
7991     }
7992     *cp = 0;
7993     cp++;
7994     cp2 = StringChr (cp, '\n');
7995     if (cp2 != NULL)
7996     {
7997       *cp2 = 0;
7998     }
7999     found_id = FALSE;
8000     for (vnp = start_list, seq_num = 0;
8001              vnp != NULL && seq_num < num_seqs;
8002              vnp = vnp->next, seq_num++)
8003         {
8004       SeqIdWrite (vnp->data.ptrvalue, tmp_id, PRINTID_TEXTID_ACC_ONLY, sizeof (tmp_id) - 1);
8005       if (StringCmp (tmp_id, file_line) == 0)
8006       {
8007         for (k = 1; k <= RNAstrand_IN_PROGRESS; k++)
8008         {
8009           if (StringCmp (cp, RNAstrand_strings [k - 1]) == 0
8010               || (k == RNAstrand_MIXED
8011                   && StringNCmp (cp, RNAstrand_strings [k - 1],
8012                                  StringLen (RNAstrand_strings[k - 1])) == 0))
8013           {
8014             vnp->choice = k;
8015           }
8016         }
8017       }
8018     }
8019   }
8020 
8021   FileClose (fp);
8022 
8023   FileRemove (path);
8024   return seq_num;
8025 }
8026 
8027 
8028 static ValNodePtr GetStrandednessFromSMART (SeqEntryPtr sep)
8029 {
8030   Char                    file_line [256];
8031   ValNodePtr              sequence_list = NULL, vnp;
8032   Int4                    num_sequences = 0, num_inspected;
8033 
8034   if (sep == NULL) return NULL;
8035 
8036   if (RNAstrandcmd == NULL) {
8037     if (GetAppParam ("SEQUIN", "RNACORRECT", "RNASTRAND", NULL, file_line, sizeof (file_line))) {
8038         RNAstrandcmd = StringSaveNoNull (file_line);
8039     }
8040   }
8041   if (RNAstrandcmd == NULL)
8042   {
8043     Message (MSG_ERROR, "RNASTRAND not set in config file!");
8044     return NULL;
8045   }
8046 
8047 
8048   VisitBioseqsInSep (sep, &sequence_list, GetAccessionList);
8049 
8050   if (sequence_list == NULL)
8051   {
8052     Message (MSG_ERROR, "No sequences with accession numbers found!\n");
8053     return NULL;
8054   }
8055 
8056   vnp = sequence_list;
8057   while ((num_inspected = GetSubListForRNAStrandCorrection (vnp, 25, RNAstrandcmd)) != 0)
8058   {
8059     num_sequences += num_inspected;
8060         while (num_inspected > 0 && vnp != NULL)
8061         {
8062           vnp = vnp->next;
8063           num_inspected --;
8064         }
8065   }
8066 
8067   return sequence_list;
8068 }
8069 
8070 
8071 static void DoOneReverse (ValNodePtr vnp, Boolean rev_feats, FILE *fp)
8072 {
8073   BioseqPtr   bsp;
8074   Char        str [128];
8075   SeqEntryPtr sep;
8076 
8077   if (vnp == NULL)
8078   {
8079     return;
8080   }
8081   
8082   /* reverse sequence */
8083   bsp = BioseqFind (vnp->data.ptrvalue);
8084   BioseqRevComp (bsp);
8085   sep = GetTopSeqEntryForEntityID (bsp->idx.entityID);
8086   VisitAlignmentsInSep (sep, (Pointer) bsp, ReverseBioseqInAlignment);
8087   
8088   if (fp != NULL && bsp != NULL && bsp->id != NULL) {
8089     SeqIdWrite (SeqIdFindBest (bsp->id, SEQID_GENBANK), str, PRINTID_REPORT, sizeof (str));
8090     fprintf (fp, "%s\n", str);
8091   }
8092   
8093   if (rev_feats)
8094   {
8095     ReverseBioseqFeatureStrands (bsp);
8096   }
8097 }
8098 
8099 static void RemoveAlignmentsWithSequenceCallback (SeqAnnotPtr sap, Pointer userdata)
8100 {
8101   SeqAlignPtr salp;
8102   SeqIdPtr    sip;
8103 
8104   if (sap == NULL || sap->type != 2 || userdata == NULL) return;
8105   salp = (SeqAlignPtr) sap->data;
8106   if (salp == NULL || salp->idx.deleteme) return;
8107   sip = (SeqIdPtr) userdata;
8108   while (sip != NULL && !sap->idx.deleteme) {
8109     if (FindSeqIdinSeqAlign (salp, sip)) {
8110           sap->idx.deleteme = TRUE;
8111         }
8112         sip = sip->next;
8113   }
8114 }
8115 
8116 extern void RemoveAlignmentsWithSequence (BioseqPtr bsp, Uint2 input_entityID)
8117 {
8118   SeqEntryPtr           topsep;
8119 
8120   if (bsp == NULL) return;
8121   topsep = GetTopSeqEntryForEntityID (input_entityID);
8122 
8123   VisitAnnotsInSep (topsep, bsp->id, RemoveAlignmentsWithSequenceCallback);
8124 }
8125 
8126 extern void FlipEntireAlignmentIfAllSequencesFlipped (SeqAnnotPtr sap, Pointer userdata)
8127 {
8128   SeqAlignPtr salp;
8129   ValNodePtr  vnp;
8130   BioseqPtr   bsp;
8131   SeqIdPtr    sip;
8132   Boolean     found;
8133   Int4 row, num_rows;
8134 
8135   if (sap == NULL || sap->type != 2 || userdata == NULL) return;
8136   salp = (SeqAlignPtr) sap->data;
8137   if (salp == NULL || salp->idx.deleteme) return;
8138   
8139   
8140   AlnMgr2IndexSingleChildSeqAlign(salp);
8141   num_rows = AlnMgr2GetNumRows(salp);
8142   for (row = 1; row <= num_rows; row++) {
8143     sip = AlnMgr2GetNthSeqIdPtr(salp, row);
8144     found = FALSE;
8145     vnp = (ValNodePtr)userdata;
8146     while (vnp != NULL && !found) {
8147       bsp = (BioseqPtr) vnp->data.ptrvalue;
8148       if (SeqIdOrderInBioseqIdList (sip, bsp->id) > 0) {
8149         found = TRUE;
8150       }
8151       vnp = vnp->next;
8152     }
8153     if (!found) return;
8154   }
8155   
8156   FlipAlignment(salp);      
8157 }
8158 
8159 
8160 static Boolean CheckForAlignmentsBeforeCorrection (RNAStrandPtr strand_info)
8161 {
8162   ValNodePtr vnp, seq_in_aln = NULL, aln_bsp = NULL;
8163   BioseqPtr  bsp;
8164   Char       id_str[255];
8165   CharPtr    msg;
8166   MsgAnswer  ans;
8167   Boolean    retval = TRUE;
8168   Int4       strand_num = 0;
8169   Uint2      entityID = 0;
8170 
8171 
8172   if (strand_info == NULL || strand_info->sequence_list == NULL) return FALSE;
8173 
8174   for (vnp = strand_info->sequence_list, strand_num = 0; vnp != NULL; vnp = vnp->next, strand_num++) {
8175     if (!strand_info->selected [strand_num]) continue;
8176     bsp = BioseqFind (vnp->data.ptrvalue);
8177     if (bsp != NULL && IsBioseqInAnyAlignment (bsp, bsp->idx.entityID)) {
8178       entityID = bsp->idx.entityID;
8179       SeqIdWrite (vnp->data.ptrvalue, id_str, PRINTID_REPORT, sizeof (id_str) - 1);
8180       ValNodeAddPointer (&seq_in_aln, 0, StringSave (id_str));
8181       ValNodeAddPointer (&aln_bsp, 0, bsp);
8182     }
8183   }
8184   if (seq_in_aln != NULL) {
8185         msg = CreateListMessage ("Sequence", 
8186                                  seq_in_aln->next == NULL 
8187                                  ? " is in an alignment, which will become invalid.  Do you want to remove the alignment?" 
8188                                  : " are in alignments, which will become invalid unless all of the sequences in these alignments are reversed.  Do you want to remove the alignments?",
8189                                  seq_in_aln);
8190         seq_in_aln = ValNodeFreeData (seq_in_aln);
8191     ans = Message (MSG_YNC, msg);
8192     msg = MemFree (msg);
8193     if (ans == ANS_YES) {
8194       /* remove the alignments */
8195       for (vnp = aln_bsp; vnp != NULL; vnp = vnp->next) {
8196           bsp = vnp->data.ptrvalue;
8197           RemoveAlignmentsWithSequence (bsp, bsp->idx.entityID);
8198           DeleteMarkedObjects (bsp->idx.entityID, 0, NULL);      
8199       }
8200     } else if (ans == ANS_CANCEL) {
8201       retval = FALSE;
8202     } else {
8203       VisitAnnotsInSep (GetTopSeqEntryForEntityID (entityID), aln_bsp, FlipEntireAlignmentIfAllSequencesFlipped);
8204     }
8205     aln_bsp = ValNodeFree (aln_bsp);
8206   }
8207   return retval;
8208 }
8209 
8210 static void DoRNACorrection (ButtoN b)
8211 {
8212   RNAStrandPtr strand_info;
8213   Int4         strand_num = 0;
8214   ValNodePtr   vnp;
8215   Boolean      rev_feats;
8216   FILE         *fp;
8217   Char         path [PATH_MAX];
8218   
8219   strand_info = (RNAStrandPtr) GetObjectExtra (b);
8220   if (strand_info == NULL)
8221   {
8222     return;
8223   }
8224   
8225   rev_feats = GetStatus (strand_info->rev_feats);
8226 
8227   /* check for alignments */
8228   if (!CheckForAlignmentsBeforeCorrection (strand_info)) {
8229     return;
8230   }
8231 
8232   TmpNam (path);
8233   fp = FileOpen (path, "w");
8234   if (fp != NULL) {
8235     for (vnp = strand_info->sequence_list, strand_num = 0;
8236          vnp != NULL; 
8237          vnp = vnp->next, strand_num++)
8238     {
8239       if (strand_info->selected [strand_num])
8240       {
8241         /* reverse sequence */
8242         DoOneReverse (vnp, rev_feats, fp);
8243       }
8244     }
8245   
8246     FileClose (fp);
8247     LaunchGeneralTextViewer (path, "Flipped Sequences");
8248     FileRemove (path);  
8249   } else {
8250     Message (MSG_ERROR, "Unable to open file for flip report");
8251   }
8252     
8253   ObjMgrSetDirtyFlag (strand_info->input_entityID, TRUE);
8254   ObjMgrSendMsg (OM_MSG_UPDATE, strand_info->input_entityID, 0, 0);
8255   Remove (strand_info->form);
8256   Update ();
8257 }
8258 
8259 static void CleanupRNAStrandFormProc (GraphiC g, Pointer data)
8260 {
8261   RNAStrandPtr strand_info;
8262   
8263   if (data != NULL)  
8264   {
8265     strand_info = (RNAStrandPtr) data;
8266     strand_info->sequence_list = ValNodeFree (strand_info->sequence_list);
8267     strand_info->selected = MemFree (strand_info->selected);
8268     strand_info = MemFree (strand_info);
8269   }
8270 }
8271 
8272 static Int4 GetSeqNumFromListPos (Int4 list_pos, ValNodePtr sequence_list)
8273 {
8274   Int4       seq_num = 0, list_offset;
8275   ValNodePtr vnp;
8276   ERNAstrand_group_num group;
8277   
8278   if (sequence_list == NULL)
8279   {
8280     return 0;
8281   }
8282 
8283   list_offset = -1;  
8284   for (group = RNASTRANDGRP_ERROR; group <= RNASTRANDGRP_PLUS && list_offset != list_pos; group++) 
8285   {
8286     for (vnp = sequence_list, seq_num = -1; 
8287          vnp != NULL && list_offset != list_pos; 
8288          vnp = vnp->next, seq_num++) 
8289     {
8290       if (GetRNAStrandGroupNum(vnp) == group) 
8291       {
8292         list_offset ++;
8293       }
8294     }
8295   }
8296   
8297   return seq_num;
8298 }
8299 
8300 static void ReleaseRNAStrand (DoC d, PoinT pt)
8301 
8302 {
8303   Int2            col;
8304   RNAStrandPtr    strand_info;
8305   Int2            item;
8306   RecT            rct;
8307   Int2            row;
8308   Int4            seq_num;
8309 
8310   strand_info = (RNAStrandPtr) GetObjectExtra (d);
8311   if (strand_info != NULL && strand_info->selected != NULL) {
8312     MapDocPoint (d, pt, &item, &row, &col, &rct);
8313     rct.left += 1;
8314     rct.right = rct.left + strand_info->lineheight;
8315     rct.bottom = rct.top + (rct.right - rct.left);
8316     if (row == 1 && col == 3 && PtInRect (pt, &rct))
8317     {
8318       seq_num = GetSeqNumFromListPos (item - 1, strand_info->sequence_list);
8319       if (seq_num > -1 && seq_num < strand_info->num_sequences)
8320       {
8321         if (strand_info->selected [seq_num]) {
8322           strand_info->selected [seq_num] = FALSE;
8323         } else {
8324           strand_info->selected [seq_num] = TRUE;
8325         }
8326         InsetRect (&rct, -1, -1);
8327         InvalRect (&rct);
8328         Update ();
8329       }
8330     }
8331   }
8332 }
8333 
8334 static void DrawRNAStrand (DoC d, RectPtr r, Int2 item, Int2 firstLine)
8335 
8336 {
8337   RNAStrandPtr strand_info;
8338   RecT         rct;
8339   RecT         doc_rect;
8340   Int4         seq_num;
8341 
8342   strand_info = (RNAStrandPtr) GetObjectExtra (d);
8343   
8344   if (strand_info == NULL || r == NULL 
8345       || item < 1 || item > strand_info->num_sequences 
8346       || firstLine != 0)
8347   {
8348     return;
8349   }
8350   
8351   rct = *r;
8352   rct.right --;
8353   rct.left = rct.right - strand_info->lineheight;
8354   rct.bottom = rct.top + (rct.right - rct.left);
8355   
8356   /* make sure we don't draw a box where we aren't drawing text */
8357   ObjectRect (strand_info->doc, &doc_rect);
8358   InsetRect (&doc_rect, 4, 4);
8359   if (rct.bottom > doc_rect.bottom)
8360   {
8361     return;
8362   }
8363   
8364   FrameRect (&rct);
8365   
8366   seq_num = GetSeqNumFromListPos (item - 1, strand_info->sequence_list);
8367   if (seq_num > -1 && seq_num < strand_info->num_sequences) {
8368     if (strand_info->selected != NULL && strand_info->selected [seq_num]) {
8369       MoveTo (rct.left, rct.top);
8370       LineTo (rct.right - 1, rct.bottom - 1);
8371       MoveTo (rct.left, rct.bottom - 1);
8372       LineTo (rct.right - 1, rct.top);
8373     }
8374   }
8375 }
8376 
8377 static void GetRNAStrandDesc (ValNodePtr vnp, CharPtr doc_line)
8378 {
8379   if (vnp == NULL || doc_line == NULL) return;
8380   
8381   if (vnp->choice == RNAstrand_MINUS) {
8382     StringCat (doc_line, "\tMINUS\t\n");
8383   } else if (vnp->choice == RNAstrand_PLUS) {
8384     StringCat (doc_line, "\tPLUS\t\n");
8385   } else {
8386     StringCat (doc_line, "\t");
8387     if (vnp->choice == 0)
8388     {
8389       StringCat (doc_line, "Unknown error");
8390     }
8391     else
8392     {
8393       StringCat (doc_line, RNAstrand_strings [vnp->choice - 1]);
8394     }
8395     StringCat (doc_line, "\t\n");
8396   }   
8397 }
8398 
8399 static void RedrawRNAStrandDialog (RNAStrandPtr strand_info)
8400 {
8401   Int4         strand_num;
8402   Char         doc_line [500];
8403   ValNodePtr   vnp;
8404   ERNAstrand_group_num group_num;
8405   
8406   if (strand_info == NULL)
8407   {
8408     return;
8409   }
8410 
8411   Reset (strand_info->doc);
8412   
8413   for (group_num = RNASTRANDGRP_ERROR;
8414        group_num <= RNASTRANDGRP_PLUS;
8415        group_num++) 
8416   {
8417     for (vnp = strand_info->sequence_list, strand_num = 0;
8418          vnp != NULL;
8419          vnp = vnp->next, strand_num++)
8420     {    
8421       if (GetRNAStrandGroupNum(vnp) != group_num) continue;
8422       SeqIdWrite (vnp->data.ptrvalue, doc_line, PRINTID_TEXTID_ACC_ONLY, 255);
8423       GetRNAStrandDesc (vnp, doc_line);
8424       AppendText (strand_info->doc, doc_line, &(strand_info->rnaParFmt), strand_info->rnaColFmt, programFont);
8425       if (group_num == RNASTRANDGRP_MINUS) strand_info->selected[strand_num] = TRUE;
8426     }
8427   }  
8428 
8429   UpdateDocument (strand_info->doc, 0, 0);  
8430 }
8431 
8432 static void RefreshRNAStrandDialog (ButtoN b)
8433 {
8434   RNAStrandPtr strand_info;
8435   ValNodePtr   new_seq_list;
8436   
8437   strand_info = (RNAStrandPtr) GetObjectExtra (b);
8438   if (strand_info == NULL)
8439   {
8440     return;
8441   }
8442 
8443   if (strand_info->use_smart) {
8444     new_seq_list = GetStrandednessFromSMART (strand_info->sep);
8445   } else { 
8446     new_seq_list = GetRNAStrandednessFromLocalDatabase (strand_info->sep, strand_info->database); 
8447   }
8448   
8449   if (new_seq_list == NULL)
8450   {
8451     Message (MSG_ERROR, "Unable to refresh sequence list.");
8452     return;
8453   }
8454   strand_info->sequence_list = ValNodeFree (strand_info->sequence_list);
8455   strand_info->sequence_list = new_seq_list;
8456     
8457   RedrawRNAStrandDialog (strand_info);
8458 }
8459 
8460 
8461 static void ChangeStrandSmart (ButtoN b)
8462 {
8463   RNAStrandPtr strand_info;
8464   
8465   strand_info = (RNAStrandPtr) GetObjectExtra (b);
8466   if (strand_info == NULL)
8467   {
8468     return;
8469   }
8470   strand_info->use_smart = GetStatus (strand_info->use_smart_btn);
8471   RefreshRNAStrandDialog (strand_info->use_smart_btn); 
8472 }
8473 
8474 
8475 static Int2 CorrectRNAStrandednessForEntityID (Uint2 entityID, Boolean use_smart)
8476 
8477 {
8478   SeqEntryPtr             sep;
8479   ValNodePtr              sequence_list = NULL;
8480   RNAStrandPtr            strand_info;
8481   WindoW                  w;
8482   GrouP                   h, c;
8483   ButtoN                  b;
8484   RecT                    r;
8485   ButtoN                  refresh_btn;
8486 
8487   sep = GetTopSeqEntryForEntityID (entityID);
8488   if (sep == NULL) return OM_MSG_RET_ERROR;
8489 
8490   if (use_smart)
8491   {
8492     sequence_list = GetStrandednessFromSMART (sep);
8493   }
8494   else 
8495   {  
8496     sequence_list = GetRNAStrandednessFromLocalDatabase (sep, kRNAStrandDatabaseName); 
8497   }
8498   
8499   if (sequence_list == NULL)
8500   {
8501     return OM_MSG_RET_ERROR;
8502   }
8503   
8504   strand_info = (RNAStrandPtr) MemNew (sizeof (RNAStrandData));
8505   if (strand_info == NULL)
8506   {
8507     return OM_MSG_RET_ERROR;
8508   }
8509   
8510   strand_info->input_entityID = entityID;
8511   strand_info->sep = sep;
8512   strand_info->sequence_list = sequence_list;
8513   strand_info->num_sequences = ValNodeLen (sequence_list);
8514   strand_info->selected = (BoolPtr) MemNew (strand_info->num_sequences * sizeof (Boolean));
8515   strand_info->database = kRNAStrandDatabaseName;
8516   strand_info->use_smart = use_smart;
8517 
8518   /* initialize document paragraph format */
8519   strand_info->rnaParFmt.openSpace = FALSE;
8520   strand_info->rnaParFmt.keepWithNext = FALSE;
8521   strand_info->rnaParFmt.keepTogether = FALSE;
8522   strand_info->rnaParFmt.newPage = FALSE;
8523   strand_info->rnaParFmt.tabStops = FALSE;
8524   strand_info->rnaParFmt.minLines = 0;
8525   strand_info->rnaParFmt.minHeight = 0;
8526   
8527   /* initialize document column format */
8528   strand_info->rnaColFmt[0].pixWidth = 0;
8529   strand_info->rnaColFmt[0].pixInset = 0;
8530   strand_info->rnaColFmt[0].charWidth = 80;
8531   strand_info->rnaColFmt[0].charInset = 0;
8532   strand_info->rnaColFmt[0].font = NULL;
8533   strand_info->rnaColFmt[0].just = 'l';
8534   strand_info->rnaColFmt[0].wrap = TRUE;
8535   strand_info->rnaColFmt[0].bar = FALSE;
8536   strand_info->rnaColFmt[0].underline = FALSE;
8537   strand_info->rnaColFmt[0].left = FALSE;
8538   strand_info->rnaColFmt[0].last = FALSE;
8539   strand_info->rnaColFmt[1].pixWidth = 0;
8540   strand_info->rnaColFmt[1].pixInset = 0;
8541   strand_info->rnaColFmt[1].charWidth = 80;
8542   strand_info->rnaColFmt[1].charInset = 0;
8543   strand_info->rnaColFmt[1].font = NULL;
8544   strand_info->rnaColFmt[1].just = 'l';
8545   strand_info->rnaColFmt[1].wrap = TRUE;
8546   strand_info->rnaColFmt[1].bar = FALSE;
8547   strand_info->rnaColFmt[1].underline = FALSE;
8548   strand_info->rnaColFmt[1].left = FALSE;
8549   strand_info->rnaColFmt[1].last = FALSE;
8550   strand_info->rnaColFmt[2].pixWidth = 0;
8551   strand_info->rnaColFmt[2].pixInset = 0;
8552   strand_info->rnaColFmt[2].charWidth = 80;
8553   strand_info->rnaColFmt[2].charInset = 0;
8554   strand_info->rnaColFmt[2].font = NULL;
8555   strand_info->rnaColFmt[2].just = 'l';
8556   strand_info->rnaColFmt[2].wrap = TRUE;
8557   strand_info->rnaColFmt[2].bar = FALSE;
8558   strand_info->rnaColFmt[2].underline = FALSE;
8559   strand_info->rnaColFmt[2].left = FALSE;
8560   strand_info->rnaColFmt[2].last = TRUE;
8561     
8562   w = FixedWindow (50, 33, -10, -10, "Correct RNA Strandedness", NULL);
8563   SetObjectExtra (w, strand_info, CleanupRNAStrandFormProc);
8564   strand_info->form = (ForM) w;
8565   
8566   h = HiddenGroup (w, -1, 0, NULL);
8567   SetGroupSpacing (h, 10, 10);
8568   
8569   strand_info->doc = DocumentPanel (h, stdCharWidth * 27, stdLineHeight * 8);
8570   SetObjectExtra (strand_info->doc, strand_info, NULL);
8571   SetDocAutoAdjust (strand_info->doc, TRUE);
8572   SetDocProcs (strand_info->doc, NULL, NULL, ReleaseRNAStrand, NULL); 
8573   SetDocShade (strand_info->doc, DrawRNAStrand, NULL, NULL, NULL);
8574 
8575   SelectFont (programFont);
8576   strand_info->lineheight = LineHeight ();
8577   
8578   ObjectRect (strand_info->doc, &r);
8579   InsetRect (&r, 4, 4);
8580   strand_info->rnaColFmt[0].pixWidth = (r.right - r.left - strand_info->lineheight) / 2;
8581   strand_info->rnaColFmt[1].pixWidth = (r.right - r.left - strand_info->lineheight) / 2;
8582   strand_info->rnaColFmt[2].pixWidth = strand_info->lineheight;
8583 
8584   refresh_btn = PushButton (h, "Refresh Strand Results", RefreshRNAStrandDialog);
8585   SetObjectExtra (refresh_btn, strand_info, NULL);
8586   strand_info->rev_feats = CheckBox (h, "Also reverse features", NULL);
8587   SetStatus (strand_info->rev_feats, FALSE);
8588   strand_info->use_smart_btn = CheckBox (h, "Use SMART for strand information", ChangeStrandSmart);
8589   SetObjectExtra (strand_info->use_smart_btn, strand_info, NULL);
8590   SetStatus (strand_info->use_smart_btn, strand_info->use_smart);
8591   
8592   c = HiddenGroup (h, 2, 0, NULL);
8593   b = PushButton (c, "Autocorrect Minus Strands", DoRNACorrection);
8594   SetObjectExtra (b, strand_info, NULL);
8595   b = PushButton (c, "Cancel", StdCancelButtonProc);
8596 
8597   AlignObjects (ALIGN_CENTER, (HANDLE) strand_info->doc,
8598                               (HANDLE) refresh_btn,
8599                               (HANDLE) strand_info->use_smart_btn,
8600                               (HANDLE) strand_info->rev_feats,
8601                               (HANDLE) c,
8602                               NULL);  
8603   RedrawRNAStrandDialog (strand_info);
8604   Show (w);
8605   return OM_MSG_RET_OK;
8606 }
8607 
8608 
8609 static Int2 LIBCALLBACK CorrectRNAStrandednessEx (Pointer data, Boolean use_smart)
8610 {
8611   OMProcControlPtr ompcp;
8612 
8613   ompcp = (OMProcControlPtr) data;
8614   if (ompcp == NULL)
8615   {
8616     Message (MSG_ERROR, "You must select something!");
8617     return OM_MSG_RET_ERROR;
8618   }
8619 
8620   return CorrectRNAStrandednessForEntityID (ompcp->input_entityID, use_smart);
8621 }
8622 
8623 
8624 extern Int2 LIBCALLBACK CorrectRNAStrandedness (Pointer data)
8625 {
8626   return CorrectRNAStrandednessEx (data, FALSE);
8627 }
8628 extern Int2 LIBCALLBACK CorrectRNAStrandednessUseSmart (Pointer data)
8629 {
8630   return CorrectRNAStrandednessEx (data, TRUE);
8631 }
8632 
8633 extern void CorrectRNAStrandednessMenuItem (IteM i)
8634 {
8635   BaseFormPtr   bfp;
8636 
8637 #ifdef WIN_MAC
8638   bfp = currentFormDataPtr;
8639 #else
8640   bfp = GetObjectExtra (i);
8641 #endif
8642   if (bfp == NULL) return;
8643 
8644   CorrectRNAStrandednessForEntityID (bfp->input_entityID, TRUE);
8645 }
8646 
8647 
8648 /* collection_date has a controlled format.  
8649  * It is YYYY or Mmm-YYYY or DD-Mmm-YYYY where Mmm = Jan, Feb, Mar, Apr, May, 
8650  *                                                   Jun, Jul, Aug, Sep, Oct, 
8651  *                                                   Nov, Dec
8652  * This function will convert other formats  to this format.
8653  * For instance, September 12, 2004 should be converted to 12-Sep-2004
8654  * 12/15/2003 should be converted to 15-Dec-2003.  
8655  * 
8656  * If the date supplied is ambiguous (01/03/05), can you allow the indexer to choose which field goes in Mmm and which in DD.
8657  */
8658 
8659 typedef struct parsecollectiondate
8660 {
8661   Int4    num_successful;
8662   Int4    num_unsuccessful;
8663   Boolean month_first;
8664 } ParseCollectionDateData, PNTR ParseCollectionDatePtr;
8665 
8666 static void ParseCollectionDateCallback (BioSourcePtr biop, Pointer userdata)
8667 {
8668   SubSourcePtr           ssp;
8669   CharPtr                reformatted_date = NULL;
8670   ParseCollectionDatePtr pcdp;
8671   
8672   if (biop == NULL || biop->subtype == NULL || userdata == NULL)
8673   {
8674     return;
8675   }
8676   
8677   pcdp = (ParseCollectionDatePtr) userdata;
8678   
8679   ssp = biop->subtype;
8680   while (ssp != NULL)
8681   {
8682     if (ssp->subtype == SUBSRC_collection_date)
8683     {
8684       reformatted_date = ReformatDateStringEx (ssp->name, pcdp->month_first, NULL);
8685       if (reformatted_date == NULL)
8686       {
8687         pcdp->num_unsuccessful ++;
8688       }
8689       else
8690       {
8691         ssp->name = MemFree (ssp->name);
8692         ssp->name = reformatted_date;
8693         pcdp->num_successful ++;
8694       }
8695     }
8696     ssp = ssp->next;
8697   }
8698 }
8699 
8700 static void CountParseCollectionDateCallback (BioSourcePtr biop, Pointer userdata)
8701 {
8702   SubSourcePtr           ssp;
8703   CharPtr                reformatted_date = NULL;
8704   ParseCollectionDatePtr pcdp;
8705   
8706   if (biop == NULL || biop->subtype == NULL || userdata == NULL)
8707   {
8708     return;
8709   }
8710   
8711   pcdp = (ParseCollectionDatePtr) userdata;
8712   
8713   ssp = biop->subtype;
8714   while (ssp != NULL)
8715   {
8716     if (ssp->subtype == SUBSRC_collection_date)
8717     {
8718       reformatted_date = ReformatDateStringEx (ssp->name, pcdp->month_first, NULL);
8719       if (reformatted_date == NULL)
8720       {
8721         pcdp->num_unsuccessful++;
8722       }
8723       else
8724       {
8725         MemFree (reformatted_date);
8726         pcdp->num_successful ++;
8727       }
8728     }
8729     ssp = ssp->next;
8730   }
8731 }
8732 
8733 static void ParseCollectionDate (IteM i, Boolean month_first)