NCBI C Toolkit Cross Reference

C/sequin/sequin5.c


  1 /*   sequin5.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:  sequin5.c
 27 *
 28 * Author:  Jonathan Kans
 29 *
 30 * Version Creation Date:   8/26/97
 31 *
 32 * $Revision: 6.684 $
 33 *
 34 * File Description:
 35 *
 36 * Modifications:  
 37 * --------------------------------------------------------------------------
 38 * Date     Name        Description of modification
 39 * -------  ----------  -----------------------------------------------------
 40 *
 41 *
 42 * ==========================================================================
 43 */
 44 
 45 #define USE_BLAST3
 46 
 47 #include "sequin.h"
 48 #include <document.h>
 49 #include <biosrc.h>
 50 #include <jzcoll.h>
 51 #include <objsub.h>
 52 #ifdef USE_BLAST3
 53 #include <netblap3.h> 
 54 #else
 55 #include <netblap2.h>
 56 #include <blast2.h>
 57 #endif
 58 #include <dust.h>
 59 #include <pobutil.h>
 60 #include <saledit.h>
 61 #include <salstruc.h>
 62 #include <salfiles.h>
 63 #include <salign.h>
 64 #include <salsap.h>
 65 #include <gbfeat.h>
 66 #include <gbftdef.h>
 67 #include <satutil.h>
 68 #include <rpsutil.h>
 69 #include <subutil.h>
 70 #include <explore.h>
 71 #include <import.h>
 72 #include <salutil.h>
 73 
 74 #include <asn2gnbp.h> /* added for  parse to flatfile */
 75 #include <sqnutils.h> /* added to include SeqEdTranslateOneCDS */
 76 #include <seqpanel.h>
 77 #include <salpanel.h>
 78 #include <tax3api.h> /* added for specific-host corrections */
 79 #include <findrepl.h>
 80 #include <valid.h> /* added for latloncountry conflict checking */
 81 #include <vsmutil.h>
 82 
 83 static void CommonLaunchBioseqViewer (SeqEntryPtr sep, CharPtr path, Boolean directToEditor)
 84 
 85 {
 86   BioseqPtr     bsp;
 87   BioseqSetPtr  bssp;
 88   Pointer       dataptr;
 89   Uint2         datatype;
 90   Uint2         entityID;
 91   Int2          handled;
 92 
 93   if (sep != NULL) {
 94     if (IS_Bioseq (sep)) {
 95       datatype = OBJ_BIOSEQ;
 96     } else if (IS_Bioseq_set (sep)) {
 97       datatype = OBJ_BIOSEQSET;
 98     } else {
 99       sep = SeqEntryFree (sep);
100       return;
101     }
102     dataptr = (Pointer) sep->data.ptrvalue;
103     entityID = ObjMgrRegister (datatype, dataptr);
104     if (dataptr != NULL && entityID > 0) {
105       if (datatype == OBJ_SEQSUB || datatype == OBJ_SEQENTRY ||
106           datatype == OBJ_BIOSEQ || datatype == OBJ_BIOSEQSET) {
107         WatchCursor ();
108         sep = GetTopSeqEntryForEntityID (entityID);
109         if (sep == NULL) {
110           sep = SeqEntryNew ();
111           if (sep != NULL) {
112             if (datatype == OBJ_BIOSEQ) {
113               bsp = (BioseqPtr) dataptr;
114               sep->choice = 1;
115               sep->data.ptrvalue = bsp;
116               SeqMgrSeqEntry (SM_BIOSEQ, (Pointer) bsp, sep);
117             } else if (datatype == OBJ_BIOSEQSET) {
118               bssp = (BioseqSetPtr) dataptr;
119               sep->choice = 2;
120               sep->data.ptrvalue = bssp;
121               SeqMgrSeqEntry (SM_BIOSEQSET, (Pointer) bssp, sep);
122             } else {
123               sep = SeqEntryFree (sep);
124             }
125           }
126           sep = GetTopSeqEntryForEntityID (entityID);
127         }
128         if (sep != NULL) {
129           SeqEntryPack (sep);
130         }
131         if (directToEditor) {
132           handled = GatherProcLaunch (OMPROC_EDIT, FALSE, entityID, 1,
133                                       OBJ_BIOSEQ, 0, 0, OBJ_BIOSEQ, 0);
134         } else {
135           if (sep != NULL) {
136             if (! leaveAsOldAsn) {
137               MySeqEntryToAsn3 (sep, TRUE, FALSE, FALSE);
138             }
139           }
140           seqviewprocs.filepath = path;
141           seqviewprocs.forceSeparateViewer = TRUE;
142           handled = GatherProcLaunch (OMPROC_VIEW, FALSE, entityID, 1,
143                                       OBJ_BIOSEQ, 0, 0, OBJ_BIOSEQ, 0);
144           seqviewprocs.filepath = NULL;
145         }
146         ArrowCursor ();
147         if (handled != OM_MSG_RET_DONE || handled == OM_MSG_RET_NOPROC) {
148           Message (MSG_FATAL, "Unable to launch viewer.");
149           SeqEntryFree (sep);
150           return;
151         } else {
152           SendHelpScrollMessage (helpForm, "Editing the Record", NULL);
153         }
154         ObjMgrSetOptions (OM_OPT_FREE_IF_NO_VIEW, entityID);
155         ObjMgrSetDirtyFlag (entityID, TRUE);
156       } else {
157         Message (MSG_ERROR, "Unable to process object type %d.", (int) datatype);
158         ObjMgrDelete (datatype, dataptr);
159       }
160     }
161   }
162 }
163 
164 extern void FastaNucDirectToSeqEdProc (IteM i)
165 
166 {
167   FILE         *fp;
168   Char         path [PATH_MAX];
169   SeqEntryPtr  sep;
170 
171   if (! GetInputFileName (path, sizeof (path), "", "TEXT")) return;
172   fp = FileOpen (path, "r");
173   if (fp == NULL) return;
174   sep = SequinFastaToSeqEntryEx (fp, TRUE, NULL, TRUE, NULL);
175   FileClose (fp);
176   CommonLaunchBioseqViewer (sep, path, TRUE);
177 }
178 
179 #define BUFSIZE 128
180 
181 static CharPtr GetSequenceString (BioseqPtr bsp)
182 
183 {
184   Char          buf [BUFSIZE + 5];
185   Int2          j;
186   ByteStorePtr  raw;
187   CharPtr       sequence = NULL;
188   SeqPortPtr    spp;
189   Uint1         u1Residue;
190 
191   if (bsp == NULL) return NULL;
192   if (! ISA_na (bsp->mol)) return NULL;
193   spp = SeqPortNew (bsp, 0, -1, 0, Seq_code_iupacna);
194   if (spp == NULL) return NULL;
195   raw = BSNew (bsp->length + 5);
196   if (raw == NULL) {
197     SeqPortFree (spp);
198     return NULL;
199   }
200 
201   j = 0;
202   buf [0] = '\0';
203   while ((u1Residue = SeqPortGetResidue (spp)) != SEQPORT_EOF) {
204     if (IS_residue (u1Residue)) {
205       u1Residue = TO_UPPER(u1Residue);
206       if (u1Residue == 'U') {
207         u1Residue = 'T';
208       }
209       buf [j] = (Char) u1Residue;
210       j++;
211       if (j >= BUFSIZE) {
212         BSWrite (raw, buf, j * sizeof (Char));
213         j = 0;
214       }
215     }
216   }
217   buf [j] = '\0';
218   if (j >= 0) {
219     BSWrite (raw, buf, j * sizeof (Char));
220   }
221   sequence = BSMerge (raw, NULL);
222   BSFree (raw);
223   SeqPortFree (spp);
224   return sequence;
225 }
226 
227 static Boolean LookForSearchString (CharPtr title, CharPtr str, CharPtr tmp, size_t maxsize)
228 
229 {
230   CharPtr  ptr;
231 
232   ptr = StringISearch (title, str);
233   if (ptr != NULL) {
234     StringNCpy_0 (tmp, ptr + StringLen (str), maxsize);
235      ptr = StringChr (tmp, ']');
236      if (ptr != NULL) {
237        *ptr = '\0';
238      }
239     return TRUE;
240   }
241   return FALSE;
242 }
243 
244 typedef struct geneextendlist {
245   GeneRefPtr  grp;
246   SeqLocPtr   slp;
247   ObjMgrPtr   omp;
248   Boolean     rsult;
249   Char        label [41];
250 } GeneExtendList, PNTR GeneExtendPtr;
251 
252 static Boolean GeneExtendFunc (GatherContextPtr gcp)
253 
254 {
255   BioseqPtr      bsp;
256   GeneExtendPtr  gep;
257   GeneRefPtr     grp;
258   Boolean        hasNulls;
259   ObjMgrTypePtr  omtp;
260   SeqFeatPtr     sfp;
261   SeqLocPtr      slp;
262   Char           thislabel [41];
263 
264   if (gcp == NULL) return TRUE;
265 
266   gep = (GeneExtendPtr) gcp->userdata;
267   if (gep == NULL ) return TRUE;
268 
269   thislabel [0] = '\0';
270 
271   if (gcp->thistype == OBJ_SEQFEAT) {
272     sfp = (SeqFeatPtr) gcp->thisitem;
273     if (sfp != NULL && sfp->data.choice == SEQFEAT_GENE && sfp->data.value.ptrvalue != NULL) {
274       grp = (GeneRefPtr) sfp->data.value.ptrvalue;
275       omtp = ObjMgrTypeFind (gep->omp, gcp->thistype, NULL, NULL);
276       if (omtp == NULL) {
277         return TRUE;
278       }
279       if (omtp->labelfunc != NULL) {
280         (*(omtp->labelfunc)) (gcp->thisitem, thislabel, 40, OM_LABEL_CONTENT);
281       }
282       if (thislabel [0] != '\0') {
283         if (StringICmp (thislabel, gep->label) == 0) {
284           if (/* SeqLocCompare (gep->slp, sfp->location) != SLC_NO_MATCH */
285               SeqLocAinB (gep->slp, sfp->location) <= 0) {
286             bsp = GetBioseqGivenSeqLoc (sfp->location, gcp->entityID);
287             if (bsp != NULL) {
288               slp = SeqLocMerge (bsp, sfp->location, gep->slp, TRUE, FALSE, FALSE);
289               if (slp != NULL) {
290                 sfp->location = SeqLocFree (sfp->location);
291                 sfp->location = slp;
292                 if (bsp->repr == Seq_repr_seg) {
293                   slp = SegLocToPartsEx (bsp, sfp->location, TRUE);
294                   sfp->location = SeqLocFree (sfp->location);
295                   sfp->location = slp;
296                   hasNulls = LocationHasNullsBetween (sfp->location);
297                   sfp->partial = (sfp->partial || hasNulls);
298                 }
299                 FreeAllFuzz (slp);
300                 gep->rsult = TRUE;
301               }
302             }
303           }
304           return FALSE;
305         }
306       }
307     }
308   }
309   return TRUE;
310 }
311 
312 static Boolean OligoExtendGene (GeneRefPtr grp, SeqEntryPtr nsep, SeqLocPtr slp)
313 
314 {
315   GeneExtendList  gel;
316   GatherScope     gs;
317   ObjMgrTypePtr   omtp;
318   SeqFeatPtr      sfp;
319 
320   if (grp == NULL || nsep == NULL || slp == NULL) return FALSE;
321   gel.grp = grp;
322   gel.slp = slp;
323   gel.omp = ObjMgrGet ();
324   gel.label [0] = '\0';
325   gel.rsult = FALSE;
326   omtp = ObjMgrTypeFind (gel.omp, OBJ_SEQFEAT, NULL, NULL);
327   if (omtp != NULL && omtp->labelfunc != NULL) {
328     sfp = SeqFeatNew ();
329     if (sfp != NULL) {
330       sfp->data.choice = SEQFEAT_GENE;
331       sfp->data.value.ptrvalue = (Pointer) grp;
332       (*(omtp->labelfunc)) ((Pointer) sfp, gel.label, 40, OM_LABEL_CONTENT);
333       sfp->data.value.ptrvalue = NULL;
334       SeqFeatFree (sfp);
335     }
336   }
337   MemSet ((Pointer)(&gs), 0, sizeof (GatherScope));
338   gs.seglevels = 1;
339   gs.get_feats_location = TRUE;
340   MemSet((Pointer)(gs.ignore), (int)(TRUE), (size_t)(OBJ_MAX * sizeof(Boolean)));
341   gs.ignore[OBJ_BIOSEQ] = FALSE;
342   gs.ignore[OBJ_BIOSEQ_SEG] = FALSE;
343   gs.ignore[OBJ_SEQFEAT] = FALSE;
344   gs.ignore[OBJ_SEQANNOT] = FALSE;
345   GatherSeqEntry (nsep, (Pointer) &gel, GeneExtendFunc, &gs);
346   return gel.rsult;
347 }
348 
349 static void AddGBQual (SeqFeatPtr sfp, CharPtr qual, CharPtr val)
350 
351 {
352   GBQualPtr  gbq;
353   GBQualPtr  last;
354 
355   if (sfp == NULL || StringHasNoText (qual) || StringHasNoText (val)) return;
356   gbq = GBQualNew ();
357   if (gbq == NULL) return;
358   gbq->qual = StringSave (qual);
359   gbq->val = StringSave (val);
360   if (sfp->qual == NULL) {
361     sfp->qual = gbq;
362   } else {
363     last = sfp->qual;
364     while (last->next != NULL) {
365       last = last->next;
366     }
367     last->next = gbq;
368   }
369 }
370 
371 static void ProcessOligoDefline (SeqFeatPtr sfp, CharPtr title, SeqEntryPtr nsep)
372 
373 {
374   BioseqPtr   bsp;
375   GeneRefPtr  grp;
376   SeqFeatPtr  gsfp;
377   SeqLocPtr   gslp;
378   Boolean     hasNulls;
379   SeqIdPtr    sip;
380   Char        tmp [256];
381 
382   if (sfp == NULL || StringHasNoText (title) || nsep == NULL) return;
383   if (LookForSearchString (title, "[comment=", tmp, sizeof (tmp) - 1)) {
384     sfp->comment = StringSave (tmp);
385   }
386   if (LookForSearchString (title, "[stdname=", tmp, sizeof (tmp) - 1)) {
387     AddGBQual (sfp, "standard_name", tmp);
388   }
389   if (LookForSearchString (title, "[conditions=", tmp, sizeof (tmp) - 1)) {
390     AddGBQual (sfp, "PCR_conditions", tmp);
391   }
392   if (LookForSearchString (title, "[gene=", tmp, sizeof (tmp) - 1)) {
393     grp = CreateNewGeneRef (tmp, NULL, NULL, FALSE);
394     if (grp != NULL) {
395       /*
396       slp = AsnIoMemCopy ((Pointer) sfp->location,
397                           (AsnReadFunc) SeqLocAsnRead,
398                           (AsnWriteFunc) SeqLocAsnWrite);
399       if (slp != NULL || slp->choice == SEQLOC_INT) {
400         sintp = (SeqIntPtr) slp->data.ptrvalue;
401         if (sintp != NULL) {
402           if (sintp->strand == Seq_strand_minus) {
403             sintp->strand = Seq_strand_plus;
404           } else if (sintp->strand == Seq_strand_plus) {
405             sintp->strand = Seq_strand_minus;
406           }
407         }
408       }
409       */
410       if (OligoExtendGene (grp, nsep, sfp->location) /* || OligoExtendGene (grp, nsep, slp) */) {
411         grp = GeneRefFree (grp);
412       } else {
413         gsfp = CreateNewFeature (nsep, NULL, SEQFEAT_GENE, NULL);
414         if (gsfp != NULL) {
415           gsfp->data.value.ptrvalue = (Pointer) grp;
416           gsfp->location = SeqLocFree (gsfp->location);
417           gsfp->location = AsnIoMemCopy ((Pointer) sfp->location,
418                                         (AsnReadFunc) SeqLocAsnRead,
419                                         (AsnWriteFunc) SeqLocAsnWrite);
420           sip = SeqLocId (gsfp->location);
421           if (sip != NULL) {
422             bsp = BioseqFind (sip);
423           } else {
424             bsp = (BioseqPtr) nsep->data.ptrvalue;
425           }
426           if (bsp != NULL) {
427             gslp = SeqLocMerge (bsp, gsfp->location, NULL, TRUE, FALSE, FALSE);
428             if (gslp != NULL) {
429               gsfp->location = SeqLocFree (gsfp->location);
430               gsfp->location = gslp;
431               if (bsp->repr == Seq_repr_seg) {
432                 gslp = SegLocToPartsEx (bsp, gsfp->location, TRUE);
433                 gsfp->location = SeqLocFree (gsfp->location);
434                 gsfp->location = gslp;
435                 hasNulls = LocationHasNullsBetween (gsfp->location);
436                 gsfp->partial = (gsfp->partial || hasNulls);
437               }
438               FreeAllFuzz (gslp);
439             }
440           }
441         }
442       }
443       /* SeqLocFree (slp); */
444     }
445   }
446 }
447 
448 static void ProcessOligo (SeqEntryPtr sep, CharPtr sequence, CharPtr title)
449 
450 {
451   BioseqSetPtr  bssp;
452   ImpFeatPtr    ifp;
453   BioseqPtr     nbsp;
454   SeqEntryPtr   nsep;
455   SeqFeatPtr    sfp;
456   SeqLocPtr     slp;
457 
458   if (sep == NULL || sequence == NULL) return;
459   if (IS_Bioseq_set (sep)) {
460     bssp = (BioseqSetPtr) sep->data.ptrvalue;
461     if (bssp != NULL && (bssp->_class == 7 ||
462                          (IsPopPhyEtcSet (bssp->_class)))) {
463       for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
464         ProcessOligo (sep, sequence, title);
465       }
466       return;
467     }
468   }
469   nsep = FindNucSeqEntry (sep);
470   if (nsep == NULL) return;
471   if (! IS_Bioseq (nsep)) return;
472   nbsp = (BioseqPtr) nsep->data.ptrvalue;
473   if (nbsp == NULL) return;
474   slp = StringSearchInBioseq (nbsp->id, sequence);
475   if (slp == NULL) return;
476   ifp = ImpFeatNew ();
477   if (ifp != NULL) {
478     ifp->key = StringSave ("primer_bind");
479     sfp = CreateNewFeature (nsep, NULL, SEQFEAT_IMP, NULL);
480     if (sfp != NULL) {
481       sfp->data.value.ptrvalue = (Pointer) ifp;
482       sfp->location = SeqLocFree (sfp->location);
483       sfp->location = slp;
484       ProcessOligoDefline (sfp, title, nsep);
485     }
486   }
487 }
488 
489 extern void ParseInOligoPrimers (IteM i)
490 
491 {
492   BaseFormPtr  bfp;
493   BioseqPtr    bsp;
494   CharPtr      extension;
495   FILE         *fp;
496   SeqEntryPtr  nextsep;
497   Char         path [PATH_MAX];
498   SeqEntryPtr  sep;
499   CharPtr      sequence;
500   CharPtr      title;
501 
502 #ifdef WIN_MAC
503   bfp = currentFormDataPtr;
504 #else
505   bfp = GetObjectExtra (i);
506 #endif
507   if (bfp == NULL) return;
508   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
509   if (sep == NULL) return;
510   extension = GetAppProperty ("FastaNucExtension");
511   if (! GetInputFileName (path, sizeof (path), extension, "TEXT")) return;
512   fp = FileOpen (path, "r");
513   if (fp == NULL) return;
514   WatchCursor ();
515   Update ();
516 
517   nextsep = SequinFastaToSeqEntryEx (fp, TRUE, NULL, FALSE, NULL);
518   while (nextsep != NULL) {
519     if (IS_Bioseq (nextsep)) {
520       bsp = (BioseqPtr) nextsep->data.ptrvalue;
521       sequence = GetSequenceString (bsp);
522       title = SeqEntryGetTitle (nextsep);
523       ProcessOligo (sep, sequence, title);
524       MemFree (sequence);
525     }
526     SeqEntryFree (nextsep);
527     nextsep = SequinFastaToSeqEntryEx (fp, TRUE, NULL, FALSE, NULL);
528   }
529 
530   FileClose (fp);
531   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
532   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
533   ArrowCursor ();
534   Update ();
535 }
536 
537 typedef struct edlocdata {
538   FORM_MESSAGE_BLOCK
539   SeqIdPtr      sip;
540   BioseqPtr     bsp;
541   TexT          locusname;
542   PrompT        accnnumber;
543   Boolean       refgene;
544 } EdLocData, PNTR EdLocPtr;
545 
546 static CharPtr AllToUpper (CharPtr str)
547 
548 {
549   Char          ch;
550   CharPtr       ptr;
551 
552   if (str != NULL) {
553     ptr = str;
554     ch = *ptr;
555     while (ch != '\0') {
556       *ptr = TO_UPPER (ch);
557       ptr++;
558       ch = *ptr;
559     }
560   }
561   return str;
562 }
563 
564 static void EditLocusActnProc (ForM f)
565 
566 {
567   BioseqPtr     bsp;
568   Uint1         choice = SEQID_GENBANK;
569   Int2          count;
570   SeqIdPtr      id;
571   EdLocPtr      elp;
572   Int2          len;
573   Char          num [16];
574   BioseqPtr     part;
575   CharPtr       ptr;
576   Char          str [64];
577   SeqIdPtr      sip;
578   SeqLocPtr     slp;
579   Char          tmp [76];
580   TextSeqIdPtr  tsip;
581   ValNode       vn;
582 
583   elp = (EdLocPtr) GetObjectExtra (f);
584   if (elp != NULL) {
585     sip = elp->sip;
586     bsp = elp->bsp;
587     if (elp->refgene) {
588       choice = SEQID_OTHER;
589     }
590     if (indexerVersion && sip == NULL && bsp != NULL && bsp->id != NULL) {
591       id = bsp->id;
592       while (id->next != NULL) {
593         id = sip->next;
594       }
595       tsip = TextSeqIdNew ();
596       if (tsip != NULL) {
597         sip = ValNodeNew (NULL);
598         if (sip != NULL) {
599           sip->choice = choice;
600           sip->data.ptrvalue = (Pointer) tsip;
601         } else {
602           TextSeqIdFree (tsip);
603         }
604         id->next = sip;
605         SeqMgrReplaceInBioseqIndex (bsp);
606       }
607     }
608     if (sip == NULL) return;
609     tsip = (TextSeqIdPtr) sip->data.ptrvalue;
610     if (tsip == NULL) return;
611     tsip->accession = MemFree (tsip->accession);
612     GetTitle (elp->accnnumber, str, sizeof (str) - 1);
613     TrimSpacesAroundString (str);
614     if (! StringHasNoText (str)) {
615       tsip->accession = StringSave (AllToUpper (str));
616     }
617     tsip->name = MemFree (tsip->name);
618     GetTitle (elp->locusname, str, sizeof (str) - 1);
619     if (str [0] != '\0') {
620       if (elp->refgene) {
621         tsip->name = StringSave (str);
622       } else {
623         tsip->name = StringSave (AllToUpper (str));
624       }
625     }
626     if (bsp != NULL && bsp->repr == Seq_repr_seg && bsp->seq_ext != NULL) {
627       if (StringNCmp (str, "SEG_", 4) != 0) {
628         sprintf (tmp, "SEG_%s", str);
629         tsip->name = MemFree (tsip->name);
630         tsip->name = StringSave (tmp);
631         SeqMgrReplaceInBioseqIndex (bsp);
632       }
633       vn.choice = SEQLOC_MIX;
634       vn.next = NULL;
635       vn.data.ptrvalue = bsp->seq_ext;
636       count = 0;
637       slp = SeqLocFindNext (&vn, NULL);
638       while (slp != NULL) {
639         if (slp->choice != SEQLOC_NULL) {
640           count++;
641         }
642         slp = SeqLocFindNext (&vn, slp);
643       }
644       if (count < 10) {
645         len = 1;
646       } else if (count < 100) {
647         len = 2;
648       } else {
649         len = 3;
650       }
651       count = 0;
652       slp = SeqLocFindNext (&vn, NULL);
653       while (slp != NULL) {
654         if (slp->choice != SEQLOC_NULL) {
655           count++;
656           sprintf (num, "%*d", (int) len, (int) count);
657           for (ptr = num; *ptr != '\0'; ptr++) {
658             if (*ptr == ' ') {
659               *ptr = '0';
660             }
661           }
662           sprintf (tmp, "%s%s", str, num);
663           sip = SeqLocId (slp);
664           if (sip != NULL) {
665             part = BioseqFind (sip);
666             if (part != NULL && part->id != NULL) {
667               id = part->id;
668               while (id->choice != choice && id->next != NULL) {
669                 id = id->next;
670               }
671               if (id->choice != choice) {
672                 tsip = TextSeqIdNew ();
673                 if (tsip != NULL) {
674                   sip = ValNodeNew (NULL);
675                   if (sip != NULL) {
676                     sip->choice = choice;
677                     sip->data.ptrvalue = (Pointer) tsip;
678                   } else {
679                     TextSeqIdFree (tsip);
680                   }
681                   id->next = sip;
682                   id = sip;
683                 }
684               }
685               if (id->choice == choice) {
686                 tsip = (TextSeqIdPtr) id->data.ptrvalue;
687                 if (tsip != NULL) {
688                   tsip->name = MemFree (tsip->name);
689                   if (tmp [0] != '\0') {
690                     if (elp->refgene) {
691                       tsip->name = StringSave (tmp);
692                     } else {
693                       tsip->name = StringSave (AllToUpper (tmp));
694                     }
695                   }
696                 }
697               }
698               SeqMgrReplaceInBioseqIndex (part);
699             }
700           }
701         }
702         slp = SeqLocFindNext (&vn, slp);
703       }
704     }
705     ObjMgrSetDirtyFlag (elp->input_entityID, TRUE);
706     ObjMgrSendMsg (OM_MSG_UPDATE, elp->input_entityID, 0, 0);
707   }
708 }
709 
710 static void EditLocusMessage (ForM f, Int2 mssg)
711 
712 {
713   EdLocPtr  elp;
714 
715   elp = (EdLocPtr) GetObjectExtra (f);
716   if (elp != NULL) {
717     switch (mssg) {
718       case VIB_MSG_CLOSE :
719         Remove (f);
720         break;
721       case VIB_MSG_CUT :
722         StdCutTextProc (NULL);
723         break;
724       case VIB_MSG_COPY :
725         StdCopyTextProc (NULL);
726         break;
727       case VIB_MSG_PASTE :
728         StdPasteTextProc (NULL);
729         break;
730       case VIB_MSG_DELETE :
731         StdDeleteTextProc (NULL);
732         break;
733       default :
734         if (elp->appmessage != NULL) {
735           elp->appmessage (f, mssg);
736         }
737         break;
738     }
739   }
740 }
741 
742 #define NUM_ORDER 16
743 
744 static SeqIdPtr SeqIdFindGenBankOrOther (SeqIdPtr sip)
745 
746 {
747   Uint1  order [NUM_ORDER];
748 
749   SeqIdBestRank (order, NUM_ORDER);
750   order [SEQID_LOCAL] = 255;
751   order [SEQID_GENBANK] = 1;
752   order [SEQID_EMBL] = 2;
753   order [SEQID_PIR] = 255;
754   order [SEQID_SWISSPROT] = 255;
755   order [SEQID_DDBJ] = 3;
756   order [SEQID_PRF] = 255;
757   order [SEQID_PDB] = 255;
758   order [SEQID_PATENT] = 255;
759   order [SEQID_OTHER] = 2;
760   order [SEQID_GENERAL] = 255;
761   order [SEQID_GIBBSQ] = 255;
762   order [SEQID_GIBBMT] = 255;
763   order [SEQID_GIIM] = 255;
764   order [SEQID_GI] = 255;
765   return SeqIdSelect (sip, order, NUM_ORDER);
766 }
767 
768 void EditLocusProc (IteM i)
769 
770 {
771   ButtoN             b;
772   BaseFormPtr        bfp;
773   BioseqPtr          bsp;
774   GrouP              c;
775   EdLocPtr           elp;
776   GrouP              g;
777   StdEditorProcsPtr  sepp;
778   SeqIdPtr           sip;
779   TextSeqIdPtr       tsip;
780   WindoW             w;
781 
782 #ifdef WIN_MAC
783   bfp = currentFormDataPtr;
784 #else
785   bfp = GetObjectExtra (i);
786 #endif
787   if (bfp == NULL) return;
788   if (bfp->input_itemtype != OBJ_BIOSEQ) return;
789   bsp = GetBioseqGivenIDs (bfp->input_entityID, bfp->input_itemID, bfp->input_itemtype);
790   if (bsp == NULL) return;
791   sip = SeqIdFindGenBankOrOther (bsp->id);
792   /*if (sip == NULL) return;*/
793   elp = (EdLocPtr) MemNew (sizeof (EdLocData));
794   if (elp == NULL) return;
795   w = MovableModalWindow (-50, -33, -10, -10,
796                           "Locus and Accession Number",
797                           StdCloseWindowProc);
798   SetObjectExtra (w, elp, StdCleanupFormProc);
799   elp->form = (ForM) w;
800   elp->actproc = EditLocusActnProc;
801   elp->formmessage = EditLocusMessage;
802 
803   elp->input_entityID = bfp->input_entityID;
804   elp->input_itemID = bfp->input_itemID;
805   elp->input_itemtype = bfp->input_itemtype;
806 
807 #ifndef WIN_MAC
808   CreateStdEditorFormMenus (w);
809 #endif
810 
811   sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
812   if (sepp != NULL) {
813     SetActivate (w, sepp->activateForm);
814     elp->appmessage = sepp->handleMessages;
815   }
816 
817   g = HiddenGroup (w, 2, 0, NULL);
818   elp->sip = sip;
819   elp->bsp = bsp;
820   StaticPrompt (g, "Locus: ", 0, dialogTextHeight, systemFont, 'l');
821   elp->locusname = DialogText (g, "", 20, NULL);
822   StaticPrompt (g, "Accession: ", 0, stdLineHeight, systemFont, 'l');
823   elp->accnnumber = StaticPrompt (g, "", 20 * stdCharWidth, stdLineHeight, systemFont, 'l');
824   c = HiddenGroup (w, 2, 0, NULL);
825   b = DefaultButton (c, "Accept", StdAcceptFormButtonProc);
826   SetObjectExtra (b, elp, NULL);
827   PushButton (c, "Cancel", StdCancelButtonProc);
828   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL);
829   if (sip != NULL) {
830     tsip = (TextSeqIdPtr) sip->data.ptrvalue;
831     if (tsip != NULL) {
832       SetTitle (elp->locusname, tsip->name);
833       SetTitle (elp->accnnumber, tsip->accession);
834     }
835     if (sip->choice == SEQID_OTHER) {
836       elp->refgene = TRUE;
837     }
838   }
839   RealizeWindow (w);
840   Select (elp->locusname);
841   Show (w);
842   Select (w);
843   Update ();
844 }
845 
846 typedef struct accntolocal 
847 {
848   Boolean make_secondary;
849   Boolean convert_prots;
850   Boolean convert_nucs;
851 } AccnToLocalData, PNTR AccnToLocalPtr;
852 
853 static SeqIdPtr LocalSeqIdFromAccession (SeqIdPtr sip, CharPtr str, Int4 str_size)
854 {
855   TextSeqIdPtr  tsip;
856   CharPtr       text;
857   SeqIdPtr      new_sip;
858   ObjectIdPtr   oip;
859 
860   if (sip == NULL || str == NULL || str_size < 1)
861   {
862     return NULL;
863   }
864   if (sip->choice != SEQID_GENBANK 
865       && sip->choice != SEQID_EMBL 
866       && sip->choice != SEQID_DDBJ)
867   {
868     return NULL;
869   }
870   if (sip->data.ptrvalue == NULL)
871   {
872     return NULL;
873   }
874   new_sip = ValNodeNew (NULL);
875   if (new_sip == NULL)
876   {
877     return NULL;
878   }
879   tsip = (TextSeqIdPtr) sip->data.ptrvalue;
880   text = NULL;
881   str [0] = '\0';
882   if (tsip->accession != NULL) {
883     text = tsip->accession;
884   } else if (tsip->name != NULL) {
885     text = tsip->name;
886   }
887   if (text != NULL) {
888     StringNCpy_0 (str, text, str_size);
889     oip = ObjectIdNew ();
890     if (oip != NULL) {
891       oip->str = StringSave (text);
892       new_sip->choice = SEQID_LOCAL;
893       new_sip->data.ptrvalue = (Pointer) oip;
894     }
895   }
896   return new_sip;
897 }
898 
899 static void SeqIdSwap (SeqIdPtr sip1, SeqIdPtr sip2)
900 {
901   ValNode       tmp_sip;
902 
903   if (sip1 == NULL || sip2 == NULL)
904   {
905     return;
906   }
907   
908   tmp_sip.choice = sip1->choice;
909   tmp_sip.data.ptrvalue = sip1->data.ptrvalue;
910   sip1->choice = sip2->choice;
911   sip1->data.ptrvalue = sip2->data.ptrvalue;
912   sip2->choice = tmp_sip.choice;
913   sip2->data.ptrvalue = tmp_sip.data.ptrvalue;
914 }
915 
916 static void ConvertSeqIdListToLocalID (SeqIdPtr sip, SeqEntryPtr sep, AccnToLocalPtr atlp)
917 
918 {
919   GBBlockPtr    gbp;
920   Char          str [32];
921   ValNodePtr    vnp;
922   BioseqPtr     bsp;
923   SeqIdPtr      new_sip = NULL;
924   
925   if (atlp == NULL) return;
926 
927   while (sip != NULL) 
928   {
929     bsp = BioseqFind (sip);
930     if (bsp == NULL)
931     {
932       new_sip = LocalSeqIdFromAccession (sip, str, sizeof (str));
933       if (new_sip != NULL)
934       {
935         bsp = BioseqFind (new_sip);
936       }
937     }
938     if (bsp == NULL)
939     {
940       /* have to skip */
941     }
942     else if (ISA_na (bsp->mol) && !atlp->convert_nucs)
943     {
944       /* don't convert the nucleotide ID */
945     }
946     else if (ISA_aa (bsp->mol) && ! atlp->convert_prots)
947     {
948       /* don't convert the protein ID */
949     }
950     else if ((sip->choice == SEQID_GENBANK 
951           || sip->choice == SEQID_EMBL 
952           || sip->choice == SEQID_DDBJ)
953           && sip->data.ptrvalue != NULL)
954     {
955       new_sip = LocalSeqIdFromAccession (sip, str, sizeof (str));
956       if (new_sip != NULL)
957       {
958         /* replace old sip values with new  - new_sip will now be ready for freeing */
959         SeqIdSwap (sip, new_sip);
960                 
961         /* make secondary if needed */
962         if (atlp->make_secondary && sep != NULL)
963         {
964           vnp = SeqEntryGetSeqDescr (sep, Seq_descr_genbank, NULL);
965           if (vnp == NULL) {
966             vnp = CreateNewDescriptor (sep, Seq_descr_genbank);
967             if (vnp != NULL) {
968               gbp = GBBlockNew ();
969               vnp->data.ptrvalue = (Pointer) gbp;
970             }
971           }
972           if (vnp != NULL) {
973             gbp = (GBBlockPtr) vnp->data.ptrvalue;
974             if (gbp != NULL) {
975               for (vnp = gbp->extra_accessions;
976                    vnp != NULL && StringICmp (vnp->data.ptrvalue, str) != 0;
977                    vnp = vnp->next) continue;
978               if (vnp == NULL) {
979                 vnp = ValNodeCopyStr (&(gbp->extra_accessions), 0, str);
980               }
981             }
982           }
983         }
984       }
985     }
986     new_sip = SeqIdFree (new_sip);
987     sip = sip->next;
988   }
989 }
990 
991 static void ConvertSeqLocListToLocalID (SeqLocPtr slp, AccnToLocalPtr atlp)
992 
993 {
994   SeqLocPtr      loc;
995   PackSeqPntPtr  psp;
996   SeqBondPtr     sbp;
997   SeqIntPtr      sinp;
998   SeqIdPtr       sip;
999   SeqPntPtr      spp;
1000 
1001   while (slp != NULL) {
1002     switch (slp->choice) {
1003       case SEQLOC_NULL :
1004         break;
1005       case SEQLOC_EMPTY :
1006       case SEQLOC_WHOLE :
1007         sip = (SeqIdPtr) slp->data.ptrvalue;
1008         ConvertSeqIdListToLocalID (sip, NULL, atlp);
1009         break;
1010       case SEQLOC_INT :
1011         sinp = (SeqIntPtr) slp->data.ptrvalue;
1012         if (sinp != NULL) {
1013           sip = sinp->id;
1014           ConvertSeqIdListToLocalID (sip, NULL, atlp);
1015         }
1016         break;
1017       case SEQLOC_PNT :
1018         spp = (SeqPntPtr) slp->data.ptrvalue;
1019         if (spp != NULL) {
1020           sip = spp->id;
1021           ConvertSeqIdListToLocalID (sip, NULL, atlp);
1022         }
1023         break;
1024       case SEQLOC_PACKED_PNT :
1025         psp = (PackSeqPntPtr) slp->data.ptrvalue;
1026         if (psp != NULL) {
1027           sip = psp->id;
1028           ConvertSeqIdListToLocalID (sip, NULL, atlp);
1029         }
1030         break;
1031       case SEQLOC_PACKED_INT :
1032       case SEQLOC_MIX :
1033       case SEQLOC_EQUIV :
1034         loc = (SeqLocPtr) slp->data.ptrvalue;
1035         while (loc != NULL) {
1036           ConvertSeqLocListToLocalID (loc, atlp);
1037           loc = loc->next;
1038         }
1039         break;
1040       case SEQLOC_BOND :
1041         sbp = (SeqBondPtr) slp->data.ptrvalue;
1042         if (sbp != NULL) {
1043           spp = (SeqPntPtr) sbp->a;
1044           if (spp != NULL) {
1045             sip = spp->id;
1046             ConvertSeqIdListToLocalID (sip, NULL, atlp);
1047           }
1048           spp = (SeqPntPtr) sbp->b;
1049           if (spp != NULL) {
1050             sip = spp->id;
1051             ConvertSeqIdListToLocalID (sip, NULL, atlp);
1052           }
1053         }
1054         break;
1055       case SEQLOC_FEAT :
1056         break;
1057       default :
1058         break;
1059     }
1060     slp = slp->next;
1061   }
1062 }
1063 
1064 static Boolean ChangeAccessionToLocalID (GatherContextPtr gcp)
1065 
1066 {
1067   BioseqPtr      bsp;
1068   AccnToLocalPtr atlp;
1069   SeqEntryPtr    sep;
1070   SeqFeatPtr     sfp;
1071   SeqIdPtr       sip;
1072   SeqLocPtr      slp;
1073 
1074   if (gcp == NULL || gcp->userdata == NULL) return TRUE;
1075   atlp = (AccnToLocalPtr) gcp->userdata;
1076   if (gcp->thisitem == NULL) return TRUE;
1077   switch (gcp->thistype) {
1078     case OBJ_BIOSEQ :
1079       sep = NULL;
1080       bsp = (BioseqPtr) gcp->thisitem;
1081       if (atlp->make_secondary)
1082       {
1083         sep = SeqMgrGetSeqEntryForData (bsp);
1084       }
1085       sip = bsp->id;
1086       ConvertSeqIdListToLocalID (sip, sep, atlp);
1087       SeqMgrReplaceInBioseqIndex (bsp);
1088       break;
1089     case OBJ_SEQFEAT :
1090       sfp = (SeqFeatPtr) gcp->thisitem;
1091       slp = sfp->location;
1092       ConvertSeqLocListToLocalID (slp, atlp);
1093       slp = sfp->product;
1094       ConvertSeqLocListToLocalID (slp, atlp);
1095       break;
1096     default :
1097       break;
1098   }
1099   return TRUE;
1100 }
1101 
1102 static void ConvertToLocalProc (IteM i, Boolean convert_nucs, Boolean convert_prots)
1103 
1104 {
1105   MsgAnswer       ans;
1106   BaseFormPtr     bfp;
1107   GatherScope     gs;
1108   AccnToLocalData atld;
1109 
1110 #ifdef WIN_MAC
1111   bfp = currentFormDataPtr;
1112 #else
1113   bfp = GetObjectExtra (i);
1114 #endif
1115   if (bfp == NULL) return;
1116   if (bfp->input_itemtype != OBJ_BIOSEQ) return;
1117   ans = Message (MSG_OKC, "Are you sure you want to convert accessions to local IDs?");
1118   if (ans == ANS_CANCEL) return;
1119   ans = Message (MSG_OKC, "Are you REALLY sure you want to convert accessions to local IDs?");
1120   if (ans == ANS_CANCEL) return;
1121   ans = Message (MSG_YN, "Do you want to make the original accessions secondary?");
1122   atld.make_secondary = (Boolean) (ans == ANS_YES);
1123   atld.convert_nucs = convert_nucs;
1124   atld.convert_prots = convert_prots;
1125   MemSet ((Pointer) (&gs), 0, sizeof (GatherScope));
1126   gs.seglevels = 1;
1127   MemSet((Pointer) (gs.ignore), (int) (TRUE), (size_t) (OBJ_MAX * sizeof (Boolean)));
1128   gs.ignore[OBJ_BIOSEQ] = FALSE;
1129   gs.ignore[OBJ_BIOSEQ_SEG] = FALSE;
1130   gs.ignore[OBJ_SEQFEAT] = FALSE;
1131   gs.ignore[OBJ_SEQANNOT] = FALSE;
1132   GatherEntity (bfp->input_entityID, (Pointer) &atld, ChangeAccessionToLocalID, &gs);
1133   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1134   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1135 }
1136 
1137 extern void ConvertToLocalProcOnlyNucs (IteM i)
1138 {
1139   ConvertToLocalProc (i, TRUE, FALSE);
1140 }
1141 
1142 extern void ConvertToLocalProcOnlyProts (IteM i)
1143 {
1144   ConvertToLocalProc (i, FALSE, TRUE);
1145 }
1146 
1147 extern void ConvertToLocalProcAll (IteM i)
1148 {
1149   ConvertToLocalProc (i, TRUE, TRUE);
1150 }
1151  
1152 static SeqIdPtr SeqIdFindBestForPromotion (SeqIdPtr sip)
1153 
1154 {
1155   return SeqIdFindBest (sip, 0);
1156 }
1157 
1158 static SeqIdPtr SeqIdFindWorstForPromotion (SeqIdPtr sip)
1159 
1160 {
1161   return SeqIdFindWorst (sip);
1162 }
1163 
1164 static void PromoteSeqId (SeqIdPtr sip, Boolean alsoCheckLocalAccn, Boolean findWorst)
1165 
1166 {
1167   SeqIdPtr     bestid, newid, oldid;
1168   BioseqPtr    bsp;
1169   ObjectIdPtr  oip;
1170   TextSeqId    tsi;
1171   SeqId        vn;
1172 
1173   bsp = BioseqFind (sip);
1174   if (bsp == NULL && alsoCheckLocalAccn && sip->choice == SEQID_LOCAL) {
1175     oip = (ObjectIdPtr) sip->data.ptrvalue;
1176     if (oip != NULL && (! StringHasNoText (oip->str))) {
1177       MemSet ((Pointer) &vn, 0, sizeof (SeqId));
1178       MemSet ((Pointer) &tsi, 0, sizeof (TextSeqId));
1179       tsi.accession = oip->str;
1180       vn.choice = SEQID_GENBANK;
1181       vn.data.ptrvalue = (Pointer) &tsi;
1182       bsp = BioseqFind (&vn);
1183     }
1184   }
1185   if (bsp == NULL) return;
1186 
1187   if (findWorst) {
1188     bestid = SeqIdFindWorstForPromotion (bsp->id);
1189   } else {
1190     bestid = SeqIdFindBestForPromotion (bsp->id);
1191   }
1192   if (bestid == NULL) return;
1193   newid = SeqIdDup (bestid);
1194   if (newid == NULL) return;
1195 
1196   oldid = ValNodeNew (NULL);
1197   if (oldid == NULL) return;
1198 
1199   MemCopy (oldid, sip, sizeof (ValNode));
1200   oldid->next = NULL;
1201 
1202   sip->choice = newid->choice;
1203   sip->data.ptrvalue = newid->data.ptrvalue;
1204 
1205   SeqIdFree (oldid);
1206   ValNodeFree (newid);
1207 
1208   SeqIdStripLocus (sip);
1209 }
1210 
1211 static void PromoteSeqIdList (SeqIdPtr sip, Boolean alsoCheckLocalAccn, Boolean findWorst)
1212 
1213 {
1214   while (sip != NULL) {
1215     PromoteSeqId (sip, alsoCheckLocalAccn, findWorst);
1216     sip = sip->next;
1217   }
1218 }
1219 
1220 static void PromoteSeqLocList (SeqLocPtr slp, Boolean alsoCheckLocalAccn, Boolean findWorst)
1221 
1222 {
1223   SeqLocPtr      loc;
1224   PackSeqPntPtr  psp;
1225   SeqBondPtr     sbp;
1226   SeqIntPtr      sinp;
1227   SeqIdPtr       sip;
1228   SeqPntPtr      spp;
1229 
1230   while (slp != NULL) {
1231     switch (slp->choice) {
1232       case SEQLOC_NULL :
1233         break;
1234       case SEQLOC_EMPTY :
1235       case SEQLOC_WHOLE :
1236         sip = (SeqIdPtr) slp->data.ptrvalue;
1237         PromoteSeqIdList (sip, alsoCheckLocalAccn, findWorst);
1238         break;
1239       case SEQLOC_INT :
1240         sinp = (SeqIntPtr) slp->data.ptrvalue;
1241         if (sinp != NULL) {
1242           sip = sinp->id;
1243           PromoteSeqIdList (sip, alsoCheckLocalAccn, findWorst);
1244         }
1245         break;
1246       case SEQLOC_PNT :
1247         spp = (SeqPntPtr) slp->data.ptrvalue;
1248         if (spp != NULL) {
1249           sip = spp->id;
1250           PromoteSeqIdList (sip, alsoCheckLocalAccn, findWorst);
1251         }
1252         break;
1253       case SEQLOC_PACKED_PNT :
1254         psp = (PackSeqPntPtr) slp->data.ptrvalue;
1255         if (psp != NULL) {
1256           sip = psp->id;
1257           PromoteSeqIdList (sip, alsoCheckLocalAccn, findWorst);
1258         }
1259         break;
1260       case SEQLOC_PACKED_INT :
1261       case SEQLOC_MIX :
1262       case SEQLOC_EQUIV :
1263         loc = (SeqLocPtr) slp->data.ptrvalue;
1264         while (loc != NULL) {
1265           PromoteSeqLocList (loc, alsoCheckLocalAccn, findWorst);
1266           loc = loc->next;
1267         }
1268         break;
1269       case SEQLOC_BOND :
1270         sbp = (SeqBondPtr) slp->data.ptrvalue;
1271         if (sbp != NULL) {
1272           spp = (SeqPntPtr) sbp->a;
1273           if (spp != NULL) {
1274             sip = spp->id;
1275             PromoteSeqIdList (sip, alsoCheckLocalAccn, findWorst);
1276           }
1277           spp = (SeqPntPtr) sbp->b;
1278           if (spp != NULL) {
1279             sip = spp->id;
1280             PromoteSeqIdList (sip, alsoCheckLocalAccn, findWorst);
1281           }
1282         }
1283         break;
1284       case SEQLOC_FEAT :
1285         break;
1286       default :
1287         break;
1288     }
1289     slp = slp->next;
1290   }
1291 }
1292 
1293 static Boolean PromoteIDsProc (GatherObjectPtr gop, Boolean findWorst)
1294 
1295 {
1296   CodeBreakPtr  cbp;
1297   CdRegionPtr   crp;
1298   RnaRefPtr     rrp;
1299   SeqFeatPtr    sfp;
1300   tRNAPtr       trp;
1301 
1302   if (gop->itemtype != OBJ_SEQFEAT) return TRUE;
1303   sfp = (SeqFeatPtr) gop->dataptr;
1304   if (sfp == NULL) return TRUE;
1305 
1306   PromoteSeqLocList (sfp->location, FALSE, findWorst);
1307 
1308   PromoteSeqLocList (sfp->product, FALSE, findWorst);
1309 
1310   switch (sfp->data.choice) {
1311     case SEQFEAT_CDREGION :
1312       crp = (CdRegionPtr) sfp->data.value.ptrvalue;
1313       if (crp != NULL && crp->code_break != NULL) {
1314         for (cbp = crp->code_break; cbp != NULL; cbp = cbp->next) {
1315           PromoteSeqLocList (cbp->loc, FALSE, findWorst);
1316         }
1317       }
1318       break;
1319     case SEQFEAT_RNA :
1320       rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
1321       if (rrp != NULL && rrp->type == 3 && rrp->ext.choice == 2) {
1322         trp = rrp->ext.value.ptrvalue;
1323         if (trp != NULL && trp->anticodon != NULL) {
1324           PromoteSeqLocList (trp->anticodon, FALSE, findWorst);
1325         }
1326       }
1327       break;
1328     default :
1329       break;
1330   }
1331 
1332   return TRUE;
1333 }
1334 
1335 static Boolean PromoteBestIDsProc (GatherObjectPtr gop)
1336 
1337 {
1338   return PromoteIDsProc (gop, FALSE);
1339 }
1340 
1341 void PromoteToBestIDProc (IteM i)
1342 
1343 {
1344   BaseFormPtr  bfp;
1345   SeqEntryPtr  oldscope, sep;
1346 
1347 #ifdef WIN_MAC
1348   bfp = currentFormDataPtr;
1349 #else
1350   bfp = GetObjectExtra (i);
1351 #endif
1352   if (bfp == NULL) return;
1353   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1354   if (sep == NULL) return;
1355 
1356   oldscope = SeqEntrySetScope (sep);
1357 
1358   GatherObjectsInEntity (bfp->input_entityID, 0, NULL, PromoteBestIDsProc, NULL, NULL);
1359 
1360   SeqEntrySetScope (oldscope);
1361 
1362   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1363   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1364 }
1365 
1366 static Boolean PromoteWorstIDsProc (GatherObjectPtr gop)
1367 
1368 {
1369   return PromoteIDsProc (gop, TRUE);
1370 }
1371 
1372 void PromoteToWorstIDProc (IteM i)
1373 
1374 {
1375   BaseFormPtr  bfp;
1376   SeqEntryPtr  oldscope, sep;
1377 
1378 #ifdef WIN_MAC
1379   bfp = currentFormDataPtr;
1380 #else
1381   bfp = GetObjectExtra (i);
1382 #endif
1383   if (bfp == NULL) return;
1384   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1385   if (sep == NULL) return;
1386 
1387   oldscope = SeqEntrySetScope (sep);
1388 
1389   GatherObjectsInEntity (bfp->input_entityID, 0, NULL, PromoteWorstIDsProc, NULL, NULL);
1390 
1391   SeqEntrySetScope (oldscope);
1392 
1393   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1394   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1395 }
1396 
1397 static void ChangeGBNameIDs (SeqIdPtr sip, Pointer userdata)
1398 
1399 {
1400   Char          buf [80];
1401   ObjectIdPtr   oip;
1402   TextSeqIdPtr  tsip;
1403 
1404   if (sip == NULL || sip->choice != SEQID_GENBANK) return;
1405   tsip = (TextSeqIdPtr) sip->data.ptrvalue;
1406   if (tsip == NULL) return;
1407   if (tsip->accession != NULL || StringHasNoText (tsip->name)) return;
1408   StringNCpy (buf, tsip->name, sizeof (buf));
1409   TrimSpacesAroundString (buf);
1410   oip = ObjectIdNew ();
1411   if (oip == NULL) return;
1412   oip->str = StringSave (buf);
1413   sip->choice = SEQID_LOCAL;
1414   sip->data.ptrvalue = (Pointer) oip;
1415   TextSeqIdFree (tsip);
1416 }
1417 
1418 static void ChangeGBNameBioseq (BioseqPtr bsp, Pointer userdata)
1419 
1420 {
1421   VisitSeqIdsInBioseq (bsp, userdata, ChangeGBNameIDs);
1422   SeqMgrReplaceInBioseqIndex (bsp);
1423 }
1424 
1425 static void ChangeGBNameFeature (SeqFeatPtr sfp, Pointer userdata)
1426 
1427 {
1428   VisitSeqIdsInSeqFeat (sfp, userdata, ChangeGBNameIDs);
1429 }
1430 
1431 void ChangeGenBankNameToLocal (IteM i)
1432 
1433 {
1434   BaseFormPtr  bfp;
1435   SeqEntryPtr  oldscope, sep;
1436 
1437 #ifdef WIN_MAC
1438   bfp = currentFormDataPtr;
1439 #else
1440   bfp = GetObjectExtra (i);
1441 #endif
1442   if (bfp == NULL) return;
1443   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1444   if (sep == NULL) return;
1445 
1446   oldscope = SeqEntrySetScope (sep);
1447 
1448   VisitBioseqsInSep (sep, NULL, ChangeGBNameBioseq);
1449   VisitFeaturesInSep (sep, NULL, ChangeGBNameFeature);
1450 
1451   SeqEntrySetScope (oldscope);
1452 
1453   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1454   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1455 }
1456 
1457 static Boolean PromoteAlignIDsProc (GatherObjectPtr gop)
1458 
1459 {
1460   DenseDiagPtr  ddp;
1461   DenseSegPtr   dsp;
1462   PackSegPtr    psp;
1463   SeqAlignPtr   sap;
1464   SeqLocPtr     slp;
1465   StdSegPtr     ssp;
1466 
1467   if (gop->itemtype != OBJ_SEQALIGN) return TRUE;
1468   sap = (SeqAlignPtr) gop->dataptr;
1469   if (sap == NULL) return TRUE;
1470 
1471   switch (sap->segtype) {
1472     case SAS_DENDIAG :
1473       for (ddp = sap->segs; ddp != NULL; ddp = ddp->next) {
1474         PromoteSeqIdList (ddp->id, TRUE, FALSE);
1475       }
1476       break;
1477     case SAS_DENSEG :
1478       dsp = sap->segs;
1479       if (dsp != NULL) {
1480         PromoteSeqIdList (dsp->ids, TRUE, FALSE);
1481       }
1482       break;
1483     case SAS_STD :
1484       for (ssp = sap->segs; ssp != NULL; ssp = ssp->next) {
1485         PromoteSeqIdList (ssp->ids, TRUE, FALSE);
1486         for (slp = ssp->loc; slp != NULL; slp = slp->next) {
1487           PromoteSeqLocList (slp, TRUE, FALSE);
1488         }
1489       }
1490       break;
1491     case SAS_PACKED :
1492       psp = (PackSegPtr) sap->segs;
1493       if (psp != NULL) {
1494         PromoteSeqIdList (psp->ids, TRUE, FALSE);
1495       }
1496       break;
1497     default :
1498       break;
1499   }
1500 
1501   return TRUE;
1502 }
1503 
1504 extern void PromoteAlignsToBestIDProc (IteM i);
1505 void PromoteAlignsToBestIDProc (IteM i)
1506 
1507 {
1508   BaseFormPtr  bfp;
1509   SeqEntryPtr  oldscope, sep;
1510 
1511 #ifdef WIN_MAC
1512   bfp = currentFormDataPtr;
1513 #else
1514   bfp = GetObjectExtra (i);
1515 #endif
1516   if (bfp == NULL) return;
1517   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1518   if (sep == NULL) return;
1519 
1520   oldscope = SeqEntrySetScope (sep);
1521 
1522   GatherObjectsInEntity (bfp->input_entityID, 0, NULL, PromoteAlignIDsProc, NULL, NULL);
1523 
1524   SeqEntrySetScope (oldscope);
1525 
1526   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1527   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1528 }
1529 
1530 static Boolean RemoveGBIDsProc (GatherObjectPtr gop)
1531 
1532 {
1533   BioseqPtr      bsp;
1534   SeqIdPtr       nextid, sip;
1535   SeqIdPtr PNTR  previd;
1536 
1537   if (gop->itemtype != OBJ_BIOSEQ) return TRUE;
1538   bsp = (BioseqPtr) gop->dataptr;
1539   if (bsp == NULL) return TRUE;
1540 
1541   previd = (SeqIdPtr PNTR) &(bsp->id);
1542   sip = bsp->id;
1543   while (sip != NULL) {
1544     nextid = sip->next;
1545     if (sip->choice == SEQID_GENBANK) {
1546       *previd = sip->next;
1547       sip->next = NULL;
1548       SeqIdFree (sip);
1549     } else {
1550       previd = (SeqIdPtr PNTR) &(sip->next);
1551     }
1552     sip = sip->next;
1553   }
1554 
1555   return TRUE;
1556 }
1557 
1558 void RemoveGBIDsFromBioseqs (IteM i)
1559 
1560 {
1561   MsgAnswer    ans;
1562   BaseFormPtr  bfp;
1563 
1564 #ifdef WIN_MAC
1565   bfp = currentFormDataPtr;
1566 #else
1567   bfp = GetObjectExtra (i);
1568 #endif
1569   if (bfp == NULL) return;
1570 
1571   ans = Message (MSG_OKC, "Currently deletes all GenBank SeqIDs");
1572   if (ans == ANS_CANCEL) return;
1573 
1574   GatherObjectsInEntity (bfp->input_entityID, 0, NULL, RemoveGBIDsProc, NULL, NULL);
1575 
1576   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1577   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1578 }
1579 
1580 static Boolean RemoveGBProtIDsProc (GatherObjectPtr gop)
1581 
1582 {
1583   BioseqPtr      bsp;
1584   SeqIdPtr       nextid, sip;
1585   SeqIdPtr PNTR  previd;
1586 
1587   if (gop->itemtype != OBJ_BIOSEQ) return TRUE;
1588   bsp = (BioseqPtr) gop->dataptr;
1589   if (bsp == NULL) return TRUE;
1590   if (! ISA_aa (bsp->mol)) return TRUE;
1591 
1592   previd = (SeqIdPtr PNTR) &(bsp->id);
1593   sip = bsp->id;
1594   while (sip != NULL) {
1595     nextid = sip->next;
1596     if (sip->choice == SEQID_GENBANK) {
1597       *previd = sip->next;
1598       sip->next = NULL;
1599       SeqIdFree (sip);
1600     } else {
1601       previd = (SeqIdPtr PNTR) &(sip->next);
1602     }
1603     sip = sip->next;
1604   }
1605 
1606   return TRUE;
1607 }
1608 
1609 void RemoveGBIDsFromProteins (IteM i)
1610 
1611 {
1612   MsgAnswer    ans;
1613   BaseFormPtr  bfp;
1614 
1615 #ifdef WIN_MAC
1616   bfp = currentFormDataPtr;
1617 #else
1618   bfp = GetObjectExtra (i);
1619 #endif
1620   if (bfp == NULL) return;
1621 
1622   ans = Message (MSG_OKC, "Currently deletes all GenBank SeqIDs");
1623   if (ans == ANS_CANCEL) return;
1624 
1625   GatherObjectsInEntity (bfp->input_entityID, 0, NULL, RemoveGBProtIDsProc, NULL, NULL);
1626 
1627   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1628   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1629 }
1630 
1631 static Boolean RemoveGIProc (GatherObjectPtr gop)
1632 
1633 {
1634   BioseqPtr      bsp;
1635   SeqIdPtr       nextid, sip;
1636   SeqIdPtr PNTR  previd;
1637 
1638   if (gop->itemtype != OBJ_BIOSEQ) return TRUE;
1639   bsp = (BioseqPtr) gop->dataptr;
1640   if (bsp == NULL) return TRUE;
1641 
1642   previd = (SeqIdPtr PNTR) &(bsp->id);
1643   sip = bsp->id;
1644   while (sip != NULL) {
1645     nextid = sip->next;
1646     if (sip->choice == SEQID_GI) {
1647       *previd = sip->next;
1648       sip->next = NULL;
1649       SeqIdFree (sip);
1650     } else {
1651       previd = (SeqIdPtr PNTR) &(sip->next);
1652     }
1653     sip = sip->next;
1654   }
1655 
1656   return TRUE;
1657 }
1658 
1659 void RemoveGIsFromBioseqs (IteM i)
1660 
1661 {
1662   MsgAnswer    ans;
1663   BaseFormPtr  bfp;
1664 
1665 #ifdef WIN_MAC
1666   bfp = currentFormDataPtr;
1667 #else
1668   bfp = GetObjectExtra (i);
1669 #endif
1670   if (bfp == NULL) return;
1671 
1672   ans = Message (MSG_OKC, "Currently deletes all GI SeqIDs");
1673   if (ans == ANS_CANCEL) return;
1674 
1675   GatherObjectsInEntity (bfp->input_entityID, 0, NULL, RemoveGIProc, NULL, NULL);
1676 
1677   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1678   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1679 }
1680 
1681 
1682 typedef struct blastfields {
1683   BlastNet3Hptr        bl3hp;
1684   BLAST_OptionsBlkPtr  options;
1685 } BlastFields, PNTR BlastFieldsPtr;
1686 
1687 #define EXPECT_VALUE 0.01
1688 
1689 static void BlastCDD (BioseqPtr bsp, Pointer userdata)
1690 
1691 {
1692   BlastFieldsPtr       bfp;
1693   BlastNet3Hptr        bl3hp;
1694   BLAST_OptionsBlkPtr  options;
1695   ValNodePtr           error_returns = NULL;
1696   SeqAlignPtr          salp;
1697 
1698   if (! ISA_aa (bsp->mol)) return;
1699   bfp = (BlastFieldsPtr) userdata;
1700   bl3hp = bfp->bl3hp;
1701   options = bfp->options;
1702   if (bl3hp == NULL) return;
1703 
1704   /* do blast search */
1705 
1706   salp = BlastBioseqNet (bl3hp, bsp, "blastp", "cdd", options,
1707                          NULL, &error_returns, NULL);
1708 
1709   /* BlastErrorPrintExtra (error_returns, TRUE, stdout); */
1710 
1711   /* annotation function now moved to rpsutil in toolkit for common use */
1712 
1713   AnnotateRegionsFromCDD (bsp, salp, EXPECT_VALUE);
1714 
1715   /* clean up */
1716 
1717   SeqAlignSetFree (salp);
1718 }
1719 
1720 extern void SimpleCDDBlastProc (IteM i)
1721 
1722 {
1723   BaseFormPtr          bfp;
1724   SeqEntryPtr          sep;
1725   BlastFields          bf;
1726   BlastNet3Hptr        bl3hp = NULL;
1727   BLAST_OptionsBlkPtr  options = NULL;
1728   BlastResponsePtr     response = NULL;
1729 
1730 #ifdef WIN_MAC
1731   bfp = currentFormDataPtr;
1732 #else
1733   bfp = GetObjectExtra (i);
1734 #endif
1735   if (bfp == NULL) return;
1736   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1737   if (sep == NULL) return;
1738 
1739   TransientSetAppParam ("NCBI", "NETBLAST", "SERVICE_NAME", "rpsblast");
1740 
1741   if (! BlastInit ("Sequin", &bl3hp, &response)) return;
1742 
1743   response = BlastResponseFree (response); 
1744   options = BLASTOptionNew ("blastp", TRUE);
1745   if (options == NULL) return;
1746 
1747   options->is_rps_blast = TRUE;
1748   options->filter = FILTER_SEG;
1749   options->expect_value  = (Nlm_FloatHi) EXPECT_VALUE;
1750   options->hitlist_size = 5000;
1751 
1752   /* blast fetch enable needed to retrieve by general SeqID */
1753 
1754   BlastNetBioseqFetchEnable (bl3hp, "cdd", FALSE, TRUE);
1755 
1756   bf.bl3hp = bl3hp;
1757   bf.options = options;
1758 
1759   WatchCursor ();
1760   Update ();
1761 
1762   FreeCDDRegions (sep);
1763 
1764   VisitBioseqsInSep (sep, (Pointer) &bf, BlastCDD);
1765 
1766   RemoveDuplicateCDDs (sep);
1767 
1768   BlastFini (bl3hp);
1769   options = BLASTOptionDelete (options);
1770   BlastNetBioseqFetchDisable (bl3hp, "cdd", FALSE);
1771 
1772   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1773   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1774   ArrowCursor ();
1775   Update ();
1776 }
1777 /*#endif*/
1778 
1779 
1780 extern Boolean DoBuildContig (void)
1781 
1782 {
1783   MsgAnswer    ans;
1784   BioseqPtr    bsp;
1785   Pointer      dataptr;
1786   Uint2        datatype;
1787   Uint2        entityID;
1788   FILE         *fp;
1789   Int2         handled;
1790   Char         path [PATH_MAX];
1791   SeqEntryPtr  sep;
1792 
1793   if (! GetInputFileName (path, sizeof (path), NULL, "TEXT")) return FALSE;
1794   fp = FileOpen (path, "r");
1795   if (fp == NULL) return FALSE;
1796   ans = Message (MSG_YN, "Are coordinates on the master (as opposed to the individual accession)?");
1797   sep = ReadContigList (fp, (Boolean) (ans == ANS_YES));
1798   FileClose (fp);
1799   if (sep == NULL || sep->choice != 1) return FALSE;
1800 
1801   bsp = (BioseqPtr) sep->data.ptrvalue;
1802   if (bsp == NULL) return FALSE;
1803   datatype = OBJ_BIOSEQ;
1804   dataptr = (Pointer) bsp;
1805   entityID = ObjMgrRegister (datatype, dataptr);
1806   if (dataptr == NULL || entityID == 0) return FALSE;
1807 
1808   WatchCursor ();
1809   Update ();
1810   handled = GatherProcLaunch (OMPROC_VIEW, FALSE, entityID, 1,
1811                               OBJ_BIOSEQ, 0, 0, OBJ_BIOSEQ, 0);
1812   ArrowCursor ();
1813   Update ();
1814 
1815   if (handled != OM_MSG_RET_DONE || handled == OM_MSG_RET_NOPROC) {
1816     Message (MSG_FATAL, "Unable to launch viewer.");
1817     SeqEntryFree (sep);
1818     return FALSE;
1819   }
1820 
1821   ObjMgrSetOptions (OM_OPT_FREE_IF_NO_VIEW, entityID);
1822   ObjMgrSetDirtyFlag (entityID, TRUE);
1823   return TRUE;
1824 }
1825 
1826 static void DoParseTrinomial (BioSourcePtr biop, Pointer userdata)
1827 
1828 {
1829   BinomialOrgNamePtr  bonp;
1830   OrgModPtr           omp;
1831   OrgNamePtr          onp;
1832   OrgRefPtr           orp;
1833   CharPtr             str;
1834 
1835   if (biop == NULL) return;
1836   orp = biop->org;
1837   if (orp == NULL) return;
1838   onp = orp->orgname;
1839   if (onp == NULL) return;
1840   if (onp->choice != 1) return;
1841   bonp = (BinomialOrgNamePtr) onp->data;
1842   if (bonp == NULL) return;
1843   if (StringHasNoText (bonp->subspecies)) return;
1844   for (omp = onp->mod; omp != NULL; omp = omp->next) {
1845     if (omp->subtype == ORGMOD_sub_species) return;
1846   }
1847   str = bonp->subspecies;
1848   if (StringNICmp (str, "subsp. ", 7) == 0) {
1849     str += 7;
1850     if (StringHasNoText (str)) return;
1851   }
1852   omp = OrgModNew ();
1853   if (omp == NULL) return;
1854   omp->subtype = ORGMOD_sub_species;
1855   omp->subname = StringSave (str);
1856   omp->next = onp->mod;
1857   onp->mod = omp;
1858 }
1859 
1860 extern void ParseTrinomial (IteM i);
1861 extern void ParseTrinomial (IteM i)
1862 
1863 {
1864   BaseFormPtr  bfp;
1865   SeqEntryPtr  sep;
1866 
1867 #ifdef WIN_MAC
1868   bfp = currentFormDataPtr;
1869 #else
1870   bfp = GetObjectExtra (i);
1871 #endif
1872   if (bfp == NULL) return;
1873   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1874   if (sep == NULL) return;
1875 
1876   VisitBioSourcesInSep (sep, NULL, DoParseTrinomial);
1877 
1878   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1879   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1880   Update ();
1881 }
1882 
1883 
1884 
1885 #define NUM_SITES 27
1886 static CharPtr siteString [NUM_SITES] = {
1887   "", "active site", "binding site", "cleavage site", "inhibition site", "modified site",
1888   "glycosylation site", "myristoylation site", "mutagenized site", "metal binding site",
1889   "phosphorylation site", "acetylation site", "amidation site", "methylation site",
1890   "hydroxylation site", "sulfatation site", "oxidative deamination site",
1891   "pyrrolidone carboxylic acid site", "gamma carboxyglutamic acid site",
1892   "blocked site", "lipid binding site", "np binding site", "DNA binding site",
1893   "signal peptide", "transit peptide", "transmembrane region", "nitrosylation"
1894 };
1895 
1896 /*=========================================================================*/
1897 /*                                                                         */
1898 /* SeqLocAdjustByOffset ()                                                 */
1899 /*                                                                         */
1900 /*=========================================================================*/
1901 
1902 extern void SeqLocAdjustByOffset (SeqLocPtr slp,
1903                   Int4 offset)
1904 {
1905   SeqIntPtr sinp;
1906 
1907   switch (slp->choice) {
1908   case SEQLOC_INT :
1909     sinp = (SeqIntPtr) slp->data.ptrvalue;
1910     if (NULL == sinp)
1911       break;
1912     sinp->from += offset;
1913     sinp->to   += offset;
1914     break;
1915   case SEQLOC_EMPTY :
1916   case SEQLOC_NULL :
1917   case SEQLOC_WHOLE :
1918   case SEQLOC_PNT :
1919   case SEQLOC_PACKED_PNT :
1920   case SEQLOC_PACKED_INT :
1921   case SEQLOC_MIX :
1922   case SEQLOC_EQUIV :
1923   case SEQLOC_BOND :
1924   case SEQLOC_FEAT :
1925   default :
1926     break;
1927   }
1928 }
1929 
1930 /*=========================================================================*/
1931 /*                                                                         */
1932 /* MoveProteinFeatures ()                                                  */
1933 /*                                                                         */
1934 /*=========================================================================*/
1935 
1936 static void MoveProteinFeatures (SeqFeatPtr destSfp,
1937                  SeqFeatPtr srcSfp,
1938                  Int4Ptr    offsetPtr)
1939 {
1940   SeqFeatPtr copySfp;
1941   SeqIdPtr   destSip;
1942 
1943   while (NULL != srcSfp) {
1944 
1945     /* Make a copy of the source feature */
1946     
1947     copySfp = SeqFeatCopy (srcSfp);
1948     copySfp->next = NULL;
1949     
1950     /* Adjust the location of the source feature */
1951     
1952     destSip = SeqLocId (destSfp->location);
1953     SeqLocReplaceLocalID (copySfp->location, destSip);
1954     SeqLocAdjustByOffset (copySfp->location, *offsetPtr);
1955 
1956     /* Attach it to the end of the linked */
1957     /* list of destination features.      */
1958 
1959     if (NULL == destSfp)
1960       destSfp = copySfp;
1961     else {
1962       while (destSfp->next != NULL)
1963     destSfp = destSfp->next;
1964       destSfp->next = copySfp;
1965     }
1966 
1967     /* Mark the source feature to be deleted */
1968     
1969     srcSfp->idx.deleteme = TRUE;
1970 
1971     /* Go to the next source feature */
1972 
1973     srcSfp = srcSfp->next;
1974   }
1975     
1976   /* Return successfully */
1977   
1978   return;
1979 }
1980       
1981 /*=========================================================================*/
1982 /*                                                                         */
1983 /* MoveProteinAnnots ()                                                    */
1984 /*                                                                         */
1985 /*=========================================================================*/
1986 
1987 static void MoveProteinAnnots (BioseqPtr destBsp,
1988                    BioseqPtr sourceBsp,
1989                    Int4Ptr   offsetPtr)
1990 {
1991   SeqAnnotPtr sourceSap;
1992   SeqAnnotPtr destSap;
1993   SeqAnnotPtr lastDestSap;
1994   SeqFeatPtr  destSfp;
1995   SeqFeatPtr  sourceSfp;
1996 
1997   /* Find end of destination annotation list */
1998 
1999   if (NULL == destBsp->annot)
2000     lastDestSap = destBsp->annot;
2001   else
2002     for (lastDestSap = destBsp->annot;
2003      lastDestSap->next != NULL;
2004      lastDestSap = lastDestSap->next) {
2005     }
2006 
2007   /* For each source SeqAnnot ... */
2008 
2009   sourceSap = sourceBsp->annot;
2010   while (NULL != sourceSap) {
2011 
2012     /* ... if not feature table then */
2013     /*     add to end of dest annots */
2014     
2015     if (sourceBsp->annot->type != 1) {
2016       if (NULL == lastDestSap)
2017     lastDestSap = sourceBsp->annot;
2018       else {
2019     lastDestSap->next = sourceBsp->annot;
2020     lastDestSap = lastDestSap->next;
2021       }
2022       lastDestSap->next = NULL;
2023     }
2024     
2025     /* ... Else if feature table then  */
2026     /*     if there is a dest feature  */
2027     /*     table merge them, otherwise */
2028     /*     add to end of dest annots   */
2029 
2030     else {
2031 
2032       /* Find a destination feature table to merge with */
2033 
2034       destSap = destBsp->annot;
2035       while ((destSap != NULL) && (destSap->type != 1))
2036     destSap = destSap->next;
2037 
2038       /* If no destination feature table found */
2039       /* then just add to end of list.         */
2040 
2041       if (NULL == destSap) {
2042     if (NULL == lastDestSap)
2043       lastDestSap = sourceBsp->annot;
2044     else {
2045       lastDestSap->next = sourceBsp->annot;
2046       lastDestSap = lastDestSap->next;
2047     }
2048     lastDestSap->next = NULL;
2049       }
2050 
2051       /* Otherwise, move all the features */
2052       /* from the source feature table to */
2053       /* the destination one.             */
2054 
2055       else {
2056     sourceSfp = (SeqFeatPtr) sourceBsp->annot->data;
2057     destSfp   = (SeqFeatPtr) destSap->data;
2058     MoveProteinFeatures (destSfp, sourceSfp, offsetPtr);
2059       }
2060     }
2061 
2062     sourceSap->idx.deleteme = TRUE;
2063     sourceSap = sourceSap->next;
2064   }
2065     
2066   return;
2067 }
2068 
2069 
2070 static Boolean ConvertImpToSpecialRNA 
2071 (SeqFeatPtr sfp,
2072  Uint2      featdef_to,
2073  Pointer    extradata)
2074 {
2075   RnaRefPtr          rrp;
2076 
2077   if (sfp == NULL || sfp->data.choice != SEQFEAT_IMP)
2078   {
2079     return FALSE;
2080   }
2081   rrp = RnaRefNew ();
2082   if (rrp != NULL) {
2083     sfp->data.value.ptrvalue = ImpFeatFree ((ImpFeatPtr) sfp->data.value.ptrvalue);
2084     sfp->data.choice = SEQFEAT_RNA;
2085     sfp->data.value.ptrvalue = (Pointer) rrp;
2086     if (featdef_to == FEATDEF_precursor_RNA) {
2087       rrp->type = 1;
2088     } else {
2089       rrp->type = 255;
2090     }
2091   }
2092   return TRUE;
2093 }
2094 
2095 static Boolean ConvertRegionToRNA 
2096 (SeqFeatPtr sfp,
2097  Uint2      featdef_to,
2098  Pointer    extradata)
2099 {
2100   RnaRefPtr  rrp;
2101   CharPtr    str;
2102 
2103   if (sfp == NULL || sfp->data.choice != SEQFEAT_REGION)
2104   {
2105     return FALSE;
2106   }
2107 
2108   rrp = RnaRefNew ();
2109   if (NULL == rrp)
2110   {
2111     return FALSE;
2112   }
2113 
2114   str = (CharPtr) sfp->data.value.ptrvalue;
2115   sfp->data.choice = SEQFEAT_RNA;
2116   sfp->data.value.ptrvalue = (Pointer) rrp;
2117 
2118   if (featdef_to == FEATDEF_precursor_RNA) {
2119     rrp->type = 1;
2120   } else {
2121     rrp->type = 255;
2122   }
2123 
2124   if (! StringHasNoText (str)) {
2125     rrp->ext.choice = 1;
2126     rrp->ext.value.ptrvalue = str;
2127   }
2128   return TRUE;
2129 }
2130 
2131 static Boolean ConvertImpToRNA 
2132 (SeqFeatPtr sfp,
2133  Uint2      featdef_to,
2134  Pointer    extradata)
2135 {
2136   RnaRefPtr  rrp;
2137 
2138   if (sfp == NULL || sfp->data.choice != SEQFEAT_IMP)
2139   {
2140     return FALSE;
2141   }
2142 
2143   rrp = RnaRefNew ();
2144   if (NULL == rrp)
2145     return FALSE;
2146 
2147   sfp->data.value.ptrvalue =
2148     ImpFeatFree ((ImpFeatPtr) sfp->data.value.ptrvalue);
2149   sfp->data.choice = SEQFEAT_RNA;
2150   sfp->data.value.ptrvalue = (Pointer) rrp;
2151 
2152   switch (featdef_to) {
2153   case FEATDEF_preRNA :
2154     rrp->type = 1;
2155     break;
2156   case FEATDEF_mRNA :
2157     rrp->type = 2;
2158     break;
2159   case FEATDEF_tRNA :
2160     rrp->type = 3;
2161     break;
2162   case FEATDEF_rRNA :
2163     rrp->type = 4;
2164     break;
2165   case FEATDEF_snRNA :
2166     rrp->type = 5;
2167     break;
2168   case FEATDEF_scRNA :
2169     rrp->type = 6;
2170     break;
2171   case FEATDEF_snoRNA :
2172     rrp->type = 7;
2173     break;
2174   case FEATDEF_ncRNA :
2175     rrp->type = 8;
2176     rrp->ext.choice = 3;
2177     rrp->ext.value.ptrvalue = RNAGenNew ();
2178     break;
2179   case FEATDEF_tmRNA :
2180     rrp->type = 9;
2181     rrp->ext.choice = 3;
2182     rrp->ext.value.ptrvalue = RNAGenNew ();
2183     break;
2184   case FEATDEF_misc_RNA:
2185     rrp->type = 10;
2186     rrp->ext.choice = 3;
2187     rrp->ext.value.ptrvalue = RNAGenNew ();
2188     break;
2189   case FEATDEF_otherRNA :
2190     rrp->type = 255;
2191     rrp->ext.choice = 1;
2192     rrp->ext.value.ptrvalue = StringSave ("misc_RNA");
2193     break;
2194   default :
2195     break;
2196   }
2197   return TRUE;
2198 }
2199 
2200 static Boolean ConvertCommentToMiscFeat (SeqFeatPtr sfp, Uint2 featdef_to, Pointer extradata)
2201 {
2202   ImpFeatPtr ifp;
2203 
2204   if (sfp == NULL || sfp->data.choice != SEQFEAT_COMMENT || sfp->data.value.ptrvalue != NULL)
2205   {
2206     return FALSE;
2207   }
2208   
2209   ifp = ImpFeatNew ();
2210   if (ifp != NULL) {
2211     ifp->key = StringSave ("misc_feature");
2212     sfp->data.choice = SEQFEAT_IMP;
2213     sfp->data.value.ptrvalue = (Pointer) ifp;
2214     return TRUE;
2215   }
2216   return FALSE;
2217 }
2218 
2219 static Boolean ConvertGeneToMiscFeat 
2220 (SeqFeatPtr sfp,
2221  Uint2      featdef_to,
2222  Pointer    extradata)
2223 {
2224   return ConvertGeneToMiscFeatFunc (sfp, featdef_to);
2225 }
2226 
2227 static Boolean ConvertRNAToMiscFeat
2228 (SeqFeatPtr sfp,
2229  Uint2      featdef_to,
2230  Pointer    extradata)
2231 {
2232   GBQualPtr  gbqual, q_p, q_n;
2233   ImpFeatPtr ifp;
2234   CharPtr    rnaname, newnote;
2235   RnaRefPtr  rrp;
2236   Int4       note_len = 0;
2237 
2238   if (sfp == NULL || sfp->data.choice != SEQFEAT_RNA)
2239   {
2240     return FALSE;
2241   }
2242 
2243   ifp = ImpFeatNew ();
2244   if (NULL == ifp)
2245   {
2246     return FALSE;
2247   }
2248 
2249   rnaname = NULL;
2250   rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
2251   if (rrp != NULL && rrp->type != 255 && rrp->ext.choice == 1) {
2252     if (rrp->ext.choice == 1) {
2253       rnaname = (CharPtr) rrp->ext.value.ptrvalue;
2254       rrp->ext.value.ptrvalue = NULL;
2255       note_len = StringLen (rnaname) + 2;
2256     }
2257   }
2258 
2259   sfp->data.value.ptrvalue =
2260     RnaRefFree ((RnaRefPtr) sfp->data.value.ptrvalue);
2261   sfp->data.choice = SEQFEAT_IMP;
2262   sfp->data.value.ptrvalue = (Pointer) ifp;
2263   ifp->key = StringSave ("misc_feature");
2264 
2265   for (gbqual = sfp->qual; gbqual != NULL; gbqual = gbqual->next) {
2266     if (StringCmp (gbqual->qual, "product") == 0) {
2267       note_len += StringLen (gbqual->val) + 2;
2268     }
2269   }
2270   
2271   if (note_len > 0) {
2272     if (!StringHasNoText (sfp->comment)) {
2273       note_len += StringLen (sfp->comment) + 2;
2274     }
2275     newnote = (CharPtr) MemNew (sizeof (Char) * (note_len + 1));
2276     if (!StringHasNoText (sfp->comment)) {
2277       StringCpy (newnote, sfp->comment);
2278       StringCat (newnote, "; ");
2279     }
2280     if (rnaname != NULL) {
2281       StringCat (newnote, rnaname);
2282       StringCat (newnote, "; ");
2283       rnaname = MemFree (rnaname);
2284     }
2285     gbqual = sfp->qual;
2286     q_p = NULL;
2287     while (gbqual != NULL) {
2288       q_n = gbqual->next;
2289       if (StringCmp (gbqual->qual, "product") == 0) {
2290         StringCat (newnote, gbqual->val);
2291         if (q_p == NULL) {
2292           sfp->qual = q_n;
2293         } else {
2294           q_p->next = q_n;
2295         }
2296         gbqual->next = NULL;
2297         gbqual = GBQualFree (gbqual);
2298       } else {
2299         q_p = gbqual;
2300       }
2301       gbqual = q_n;
2302     }
2303     /* trim trailing semicolon */
2304     newnote[note_len - 2] = 0;
2305     sfp->comment = MemFree (sfp->comment);
2306     sfp->comment = newnote;
2307   }
2308 
2309   return TRUE;
2310 }
2311 
2312 static Boolean ConvertSiteToMiscFeat
2313 (SeqFeatPtr sfp,
2314  Uint2      featdef_to,
2315  Pointer    extradata)
2316 {
2317   GBQualPtr  gbqual;
2318   ImpFeatPtr ifp;
2319   Int2       sitetype;
2320 
2321   if (sfp == NULL || sfp->data.choice != SEQFEAT_SITE)
2322   {
2323     return FALSE;
2324   }
2325 
2326   ifp = ImpFeatNew ();
2327   if (NULL == ifp)
2328   {
2329     return FALSE;
2330   }
2331 
2332   sitetype = (Int2) sfp->data.value.intvalue;
2333   sfp->data.choice = SEQFEAT_IMP;
2334   sfp->data.value.ptrvalue = (Pointer) ifp;
2335   ifp->key = StringSave ("misc_feature");
2336   if (sitetype > 0 && sitetype < NUM_SITES) {
2337     gbqual = GBQualNew ();
2338     if (gbqual != NULL) {
2339       gbqual->qual = StringSave ("note");
2340       gbqual->val = StringSave (siteString [sitetype]);
2341       gbqual->next = sfp->qual;
2342       sfp->qual = gbqual;
2343     }
2344   }
2345   return TRUE;
2346 }
2347 
2348 static Boolean ConvertProtToRegion 
2349 (SeqFeatPtr sfp,
2350  Uint2      featdef_to,
2351  Pointer    extradata)
2352 {
2353   ProtRefPtr prp;
2354   ValNodePtr vnp;
2355   CharPtr    str;
2356 
2357   if (sfp == NULL || sfp->data.choice != SEQFEAT_PROT)
2358   {
2359     return FALSE;
2360   }
2361   prp = (ProtRefPtr) sfp->data.value.ptrvalue;
2362   if (NULL == prp)
2363   {
2364     return FALSE;
2365   }
2366 
2367   vnp = prp->name;
2368   if (vnp != NULL && vnp->next == NULL) {
2369     str = (CharPtr) vnp->data.ptrvalue;
2370     if (! StringHasNoText (str)) {
2371       vnp->data.ptrvalue = NULL;
2372       sfp->data.value.ptrvalue = ProtRefFree (prp);
2373       sfp->data.choice = SEQFEAT_REGION;
2374       sfp->data.value.ptrvalue = (Pointer) str;
2375     }
2376   }
2377   return TRUE;
2378 }
2379 
2380 
2381 static Boolean ConvertRegionToProt
2382 (SeqFeatPtr sfp,
2383  Uint2      featdef_to,
2384  Pointer    extradata)
2385 {
2386   return ConvertRegionToProtFunc (sfp, featdef_to);
2387 }
2388 
2389 
2390 static Boolean ConvertRNAToNcRNA
2391 (SeqFeatPtr sfp)
2392 {
2393   RnaRefPtr  rrp;
2394   tRNAPtr    trp;
2395   RNAGenPtr  rgp = NULL;
2396   
2397   if (sfp == NULL || sfp->data.choice != SEQFEAT_RNA) return FALSE;
2398   
2399   rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
2400   if (NULL == rrp) {
2401     rrp = RnaRefNew ();
2402     sfp->data.value.ptrvalue = rrp;
2403   }
2404 
2405   if (rrp->ext.choice == 2) {
2406     trp = (tRNAPtr) rrp->ext.value.ptrvalue;
2407     if (trp != NULL) {
2408       trp->anticodon = SeqLocFree (trp->anticodon);
2409       trp = MemFree (trp);
2410       rrp->ext.value.ptrvalue = trp;
2411     }
2412     rrp->ext.choice = 0;
2413   } 
2414 
2415   /* might be converting from other ncRNA, tmRNA, or misc_RNA */
2416   if (rrp->ext.choice == 1) {
2417     rgp = RNAGenNew ();
2418     rgp->product = rrp->ext.value.ptrvalue;
2419     rrp->ext.choice = 3;
2420     rrp->ext.value.ptrvalue = rgp;
2421   } else if (rrp->ext.choice == 0) {
2422     rgp = RNAGenNew ();
2423     rrp->ext.choice = 3;
2424     rrp->ext.value.ptrvalue = rgp;
2425   } else if (rrp->ext.choice == 3) {
2426     rgp = rrp->ext.value.ptrvalue;
2427     if (rgp == NULL) {
2428       rgp = RNAGenNew ();
2429       rrp->ext.value.ptrvalue = rgp;
2430     }
2431   }
2432 
2433   if (rgp != NULL) {
2434     if (rrp->type == 5) {
2435       rgp->_class = StringSave ("snRNA");
2436     } else if (rrp->type == 6) {
2437       rgp->_class = StringSave ("scRNA");
2438     } else if (rrp->type == 7) {
2439       rgp->_class = StringSave ("snoRNA");
2440     }
2441   }
2442 
2443   rrp->type = 8;
2444   return TRUE;
2445 }
2446 
2447 
2448 static void ConvertFromncRNAtoMiscRNA (SeqFeatPtr sfp)
2449 {
2450   RnaRefPtr rrp;
2451   RNAGenPtr rgp;
2452   CharPtr tmp;
2453 
2454   if (sfp == NULL || sfp->data.choice != SEQFEAT_RNA) return;
2455   rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
2456   if (rrp == NULL || rrp->ext.choice != 3) {
2457     return;
2458   }
2459 
2460   rgp = (RNAGenPtr) rrp->ext.value.ptrvalue;
2461   if (rgp == NULL) {
2462     return;
2463   }
2464 
2465   /* if no product but has comment, promote comment to product */
2466   if (rgp->product == NULL && !StringHasNoText (sfp->comment)) {
2467     rgp->product = sfp->comment;
2468     sfp->comment = NULL;
2469   }
2470   
2471   /* move ncRNA_class elsewhere */
2472   if (!StringHasNoText (rgp->_class)) {
2473     if (StringCmp (rgp->_class, "other") == 0) {
2474       rgp->_class = MemFree (rgp->_class);
2475     } else if (rgp->product == NULL) {
2476       rgp->product = rgp->_class;
2477       rgp->_class = NULL;
2478     } else {
2479       if (StringHasNoText (sfp->comment)) {
2480         sfp->comment = MemFree (sfp->comment);
2481         sfp->comment = StringSave (rgp->_class);
2482       } else {
2483         tmp = (CharPtr) MemNew (sizeof (Char) * (StringLen (sfp->comment) + StringLen (rgp->_class) + 3));
2484         sprintf (tmp, "%s; %s", sfp->comment, rgp->_class);
2485         sfp->comment = MemFree (sfp->comment);
2486         sfp->comment = tmp;
2487       }
2488       rgp->_class = MemFree (rgp->_class);
2489     }
2490   }    
2491 }
2492 
2493 
2494 static Boolean ConvertRNAToRNA 
2495 (SeqFeatPtr sfp,
2496  Uint2      featdef_to,
2497  Pointer    extradata)
2498 {
2499   RnaRefPtr  rrp;
2500   Boolean    from_misc = FALSE, to_misc = FALSE;
2501   GBQualPtr  gbq, gbq_p = NULL;
2502 
2503   rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
2504   if (NULL == rrp)
2505     return FALSE;
2506 
2507   if (rrp->type == 255) {
2508     from_misc = TRUE;
2509   }
2510 
2511   switch (featdef_to) {
2512     case FEATDEF_preRNA :
2513       rrp->type = 1;
2514       break;
2515     case FEATDEF_mRNA :
2516       rrp->type = 2;
2517       break;
2518     case FEATDEF_tRNA :
2519       rrp->type = 3;
2520       break;
2521     case FEATDEF_rRNA :
2522       rrp->type = 4;
2523       break;
2524     case FEATDEF_snRNA :
2525       rrp->type = 5;
2526       to_misc = TRUE;
2527       break;
2528     case FEATDEF_scRNA :
2529       rrp->type = 6;
2530       to_misc = TRUE;
2531       break;
2532     case FEATDEF_snoRNA :
2533       rrp->type = 7;
2534       to_misc = TRUE;
2535       break;
2536     case FEATDEF_ncRNA :
2537       return ConvertRNAToNcRNA (sfp);
2538       break;
2539     case FEATDEF_otherRNA :
2540       rrp->type = 255;
2541       ConvertFromncRNAtoMiscRNA (sfp);
2542       break;
2543     default:
2544       break;
2545   }
2546   if (from_misc && !to_misc && rrp->ext.choice == 1 && StringCmp (rrp->ext.value.ptrvalue, "misc_RNA") == 0) {
2547     /* move product qual to string */
2548     gbq = sfp->qual;
2549     while (gbq != NULL && StringCmp (gbq->qual, "product") != 0) {
2550       gbq_p = gbq;
2551       gbq = gbq->next;
2552     }
2553     if (gbq == NULL) {
2554       rrp->ext.value.ptrvalue = MemFree (rrp->ext.value.ptrvalue);
2555       rrp->ext.choice = 0;
2556     } else {
2557       rrp->ext.value.ptrvalue = MemFree (rrp->ext.value.ptrvalue);
2558       rrp->ext.value.ptrvalue = gbq->val;
2559       gbq->val = NULL;
2560       if (gbq_p == NULL) {
2561         sfp->qual = gbq->next;
2562       } else {
2563         gbq_p->next = gbq->next;
2564       }
2565       gbq->next = NULL;
2566       gbq = GBQualFree (gbq);
2567     }
2568   }
2569   return TRUE;
2570 }
2571 
2572 static Boolean ConvertProtToProt 
2573 (SeqFeatPtr sfp,
2574  Uint2      featdef_to,
2575  Pointer    extradata)
2576 {
2577   return ConvertProtToProtFunc (sfp, featdef_to);
2578 }
2579 
2580 
2581 static Boolean ConvertImpToProt (SeqFeatPtr sfp, Uint2 featdef_to, Pointer extradata)
2582 {
2583   return ConvertImpToProtFunc (sfp, featdef_to);
2584 }
2585 
2586 
2587 static Boolean ConvertProtToImp (SeqFeatPtr sfp, Uint2 featdef_to, Pointer extradata)
2588 {
2589   return ConvertProtToImpFunc (sfp, featdef_to);
2590 }
2591 
2592 
2593 static Boolean ConvertBioSrcToRepeatRegionEx (SeqFeatPtr sfp, Uint2 featdef_to, Pointer extradata)
2594 {
2595   return ConvertBioSrcToRepeatRegion (sfp, featdef_to);
2596 }
2597 
2598 
2599 static Boolean ConvertCDSToMatPeptide (SeqFeatPtr sfp, Uint2 featdef_to, Pointer extradata)
2600 {
2601   return AutoConvertCDSToMiscFeat (sfp, extradata == NULL ? TRUE : !(*((BoolPtr) extradata)));
2602 }
2603 
2604 
2605 static Boolean ConvertMiscFeatureToCDSFunction (SeqFeatPtr sfp, Uint2 featdef_to, Pointer extradata)
2606 {
2607   return ConvertMiscFeatToCodingRegion (sfp);
2608 }
2609 
2610 
2611 extern EnumFieldAssoc  enum_bond_alist [];
2612 extern EnumFieldAssoc  enum_site_alist [];
2613 
2614 
2615 static GbFeatName EditQualifierList[] = {
2616  {"allele", Class_text}, 
2617  {"anticodon", Class_pos_aa},
2618  {"bound_moiety", Class_text},
2619  {"chromosome", Class_text},
2620  {"citation", Class_bracket_int},
2621  {"codon", Class_seq_aa},
2622  {"codon_start", Class_int_or}, 
2623  {"compare", Class_text },
2624  {"cons_splice", Class_site},
2625  {"db_xref", Class_text},
2626  {"direction", Class_L_R_B}, 
2627  {"EC_number", Class_ecnum},
2628  {"evidence", Class_exper}, 
2629  {"exception", Class_text},
2630  {"experiment", Class_text},
2631  {"frequency", Class_text}, 
2632  {"function", Class_text},
2633  {"gene", Class_text}, 
2634  {"gdb_xref", Class_text},
2635  {"label", Class_token},
2636  {"map", Class_text},
2637  {"mobile_element", Class_text}, 
2638  {"mod_base", Class_token}, {"note", Class_note},
2639  {"number", Class_number}, 
2640 #ifdef INTERNAL_NCBI_SEQUIN
2641  {"old_locus_tag", Class_text},
2642 #endif
2643  {"operon", Class_text},
2644  {"organism", Class_text},
2645  {"partial", Class_none}, {"PCR_conditions", Class_text},
2646  {"phenotype", Class_text},
2647  {"plasmid", Class_text}, {"product", Class_text},
2648  {"pseudo", Class_none},
2649  {"rearranged", Class_none}, { "replace", Class_text},
2650  {"rpt_family", Class_text}, {"rpt_type", Class_rpt},
2651  {"rpt_unit", Class_token}, {"rpt_unit_seq", Class_token}, {"rpt_unit_range", Class_token},
2652  {"satellite", Class_text},
2653  {"sequenced_mol", Class_text},
2654  {"standard_name", Class_text},
2655  {"translation", Class_text}, {"transl_except", Class_pos_aa},
2656  {"transl_table", Class_int},
2657  {"usedin", Class_token},
2658  {"focus", Class_none},
2659  {"protein_id", Class_text},
2660  {"organelle", Class_text}, {"transcript_id", Class_text},
2661  {"transgenic", Class_none}, {"environmental_sample", Class_none},
2662  {"locus_tag", Class_text}, {"mol_type", Class_text},
2663  {"segment", Class_text}
2664 };
2665 
2666 const Int4 NumEditQualifiers = sizeof (EditQualifierList) / sizeof (GbFeatName);
2667 #define QUAL_EVIDENCE 13
2668 #define QUAL_EXPERIMENT 15
2669 
2670 
2671 static ENUM_ALIST(biosource_genome_alistX)
2672   {" ",                    0},
2673   {"Apicoplast",          16},
2674   {"Chloroplast",          2},
2675   {"Chromatophore",       22},
2676   {"Chromoplast",          3},
2677   {"Chromosome",          21},
2678   {"Cyanelle",            12},
2679   {"Endogenous-virus",    19},
2680   {"Extrachromosomal",     8},
2681   {"Genomic",              1},
2682   {"Hydrogenosome",       20},
2683   {"Insertion Sequence",  11},
2684   {"Kinetoplast",          4},
2685   {"Leucoplast",          17},
2686   {"Macronuclear",         7},
2687   {"Mitochondrion",        5},
2688   {"Nucleomorph",         15},
2689   {"Plasmid",              9},
2690   {"Plastid",              6},
2691   {"Proplastid",          18},
2692   {"Proviral",            13},
2693   {"Transposon",          10},
2694 END_ENUM_ALIST
2695 
2696 static ENUM_ALIST(orgref_textfield_alist)
2697   {" ",                    0},
2698   {"Scientific Name",      1},
2699   {"Common Name",          2},
2700   {"Lineage",              3},
2701   {"Division",             4},
2702 END_ENUM_ALIST
2703 
2704 typedef struct sourceformdata {
2705   FEATURE_FORM_BLOCK
2706 
2707   Int2           type;
2708   ButtoN         applyToParts;
2709   TexT           onlyThisPart;
2710   GrouP          sourceGroup;
2711   GrouP          modGrp;
2712   GrouP          genGrp;
2713   GrouP          refGrp;
2714   GrouP          txtGrp;
2715   GrouP          originGrp;
2716   PopuP          frommod;
2717   PopuP          tomod;
2718   PopuP          fromgen;
2719   PopuP          togen;
2720   PopuP          fromref;
2721   PopuP          toref;
2722   PopuP          toorigin;
2723   PopuP          fromorigin;
2724   TexT           findthis;
2725   TexT           replacewith;
2726   GrouP          applyChoiceGrp;  /* This is the group for the radio buttons for the
2727                                    * constraint on which biosources to operate on.
2728                                    */
2729   PopuP          qual_to_have;    /* This is the control that indicates which qualifier
2730                                    * should be present to operate on a biosource.
2731                                    */
2732   TexT           text_to_have;    /* This is the control that indicates the text that
2733                                    * should be present in the biosource to be operated on.
2734                                    */
2735   Int4           applyChoiceVal;  /* This is the value of the applyChoiceGrp choice. */
2736   CharPtr        text_to_have_str;/* This is the contents of the text_to_have box. */
2737   Int4           qual_to_have_val;/* This is the subtype for the qual to have. */
2738 
2739   Int2           choice;
2740   Int2           fromval;
2741   Int2           toval;
2742   Int2           onlythis;
2743   CharPtr        findStr;
2744   CharPtr        replaceStr;
2745 
2746   Boolean        replaceOldAsked;
2747   Boolean        doReplaceAll;
2748   Boolean        use_semicolon;
2749   ButtoN         leaveDlgUp;
2750 } SourceFormData, PNTR SourceFormPtr;
2751 
2752 Uint2 mod_widths [] = {
2753   0, 25
2754 };
2755 
2756 Uint2 mod_types [] = {
2757   TAGLIST_POPUP, TAGLIST_TEXT
2758 };
2759 
2760 static CharPtr FindNextModNameToken (CharPtr modname)
2761 {
2762   CharPtr token, other_token;
2763 
2764   if (StringHasNoText (modname))
2765   {
2766     return NULL;
2767   }
2768 
2769   token = StringChr (modname, '-');
2770   other_token = StringChr (modname, '_');
2771   if (token == NULL || (other_token != NULL && token > other_token))
2772   {
2773     token = other_token;
2774   }
2775   other_token = StringChr (modname, ' ');
2776   if (token == NULL || (other_token != NULL && token > other_token))
2777   {
2778     token = other_token;
2779   }
2780   return token;
2781 }
2782 
2783 static Boolean DoModNamesMatch (CharPtr name1, CharPtr name2)
2784 {
2785   CharPtr name1_token, name2_token;
2786   if (StringHasNoText (name1) && StringHasNoText (name2))
2787   {
2788     return TRUE;
2789   }
2790   else if (StringHasNoText (name1) || StringHasNoText (name2))
2791   {
2792     return FALSE;
2793   }
2794   else if (StringICmp (name1, name2) == 0)
2795   {
2796     return TRUE;
2797   }
2798   
2799   name1_token = FindNextModNameToken (name1);
2800   name2_token = FindNextModNameToken (name2);
2801   if (name1_token == NULL || name2_token == NULL)
2802   {
2803     return FALSE;
2804   }
2805   else if (name1_token - name1 != name2_token - name2)
2806   {
2807     return FALSE;
2808   }
2809   else if (StringNICmp (name1, name2, name1_token - name1) == 0)
2810   {
2811     return DoModNamesMatch (name1_token + 1, name2_token + 1);
2812   }
2813   else
2814   {
2815     return FALSE;
2816   }
2817 }
2818 
2819 extern Uint1 FindTypeForModNameText (CharPtr cp)
2820 {
2821   Uint1 subtype;
2822 
2823   subtype = EquivalentSubSource (cp);
2824   if (subtype == 0) {
2825     subtype = EquivalentOrgMod (cp);
2826     if (subtype > 200) {
2827       /* function that calls this expects less than 100 vals for orgmod */
2828       /* need to adjust for old-lineage and old-name */
2829       subtype -= 200;
2830     }
2831   } else {
2832     /* function that calls this uses >100 to decide if subsource */
2833     subtype += 100;
2834   }
2835   if (subtype == 0) {
2836     subtype = SUBSRC_other;
2837   }
2838   return subtype;
2839 }
2840 
2841 static CharPtr GetValueNameFromEnum (Int4 val, EnumFieldAssocPtr list)
2842 { 
2843   EnumFieldAssocPtr ap;
2844   
2845   for (ap = list; ap != NULL && ap->name != NULL; ap++)
2846   {
2847       if (ap->value == val)
2848       {
2849         return ap->name;
2850       }
2851   }
2852   return NULL;
2853 }
2854 
2855 extern void AppendOrReplaceString (
2856   CharPtr PNTR string_loc,
2857   CharPtr new_value,
2858   Boolean PNTR asked_question,
2859   Boolean PNTR do_replace,
2860   Boolean PNTR use_semicolon
2861 )
2862 {
2863   MsgAnswer ans;
2864   CharPtr   tmp_value, tmp_new_value;
2865 
2866   if (string_loc == NULL
2867     || new_value == NULL
2868     || asked_question == NULL
2869     || do_replace == NULL
2870     || use_semicolon == NULL)
2871   {
2872     return;
2873   }
2874 
2875   if (! *asked_question && !StringHasNoText (*string_loc))
2876   {
2877     *asked_question = TRUE;
2878     ArrowCursor ();
2879     ans = Message (MSG_YN, "Do you wish to overwrite existing content?");
2880     *do_replace = (Boolean) (ans == ANS_YES);
2881     if (! *use_semicolon)
2882     {
2883       if (! *do_replace)
2884       {
2885         ans = Message (MSG_YN, "Separate items with semicolon?");
2886         *use_semicolon = (Boolean) (ans == ANS_YES);
2887       }
2888     }
2889     WatchCursor ();
2890     Update ();
2891   }
2892   if (*do_replace || StringHasNoText (*string_loc))
2893   {
2894     MemFree (*string_loc);
2895     *string_loc = StringSave (new_value);
2896   }
2897   else
2898   {
2899     tmp_value = MemNew (StringLen (*string_loc) + StringLen ( new_value) + 3);
2900     if (tmp_value == NULL) return;
2901     StringCpy (tmp_value, *string_loc);
2902     TrimSpacesAroundString (tmp_value);
2903     if (*use_semicolon)
2904     {
2905       StringCat (tmp_value, "; ");
2906     }
2907     else
2908     {
2909       StringCat (tmp_value, " ");
2910     }
2911     tmp_new_value = StringSave (new_value);
2912     TrimSpacesAroundString (tmp_new_value);
2913     StringCat (tmp_value, tmp_new_value);
2914     MemFree (tmp_new_value);
2915     MemFree (*string_loc);
2916     *string_loc = tmp_value;
2917   }
2918 }
2919 
2920 static ENUM_ALIST(origin_alist)
2921 {" ",               ORG_DEFAULT    },
2922 {"Natural",         ORG_NATURAL    },
2923 {"Natural Mutant",  ORG_NATMUT     },
2924 {"Mutant",          ORG_MUT        },
2925 {"Artificial",      ORG_ARTIFICIAL },
2926 {"Synthetic",       ORG_SYNTHETIC  },
2927 {"Other",           ORG_OTHER      },
2928 END_ENUM_ALIST
2929 
2930 
2931 typedef struct setsample
2932 {
2933   GetFeatureFieldString    fieldstring_func;
2934   GetDescriptorFieldString descrstring_func;
2935   Uint2                    entityID;
2936   ValNodePtr               field_list;
2937   FreeValNodeProc          free_vn_proc;
2938   CopyValNodeDataProc      copy_vn_proc;
2939   MatchValNodeProc         match_vn_proc;
2940   NameFromValNodeProc      label_vn_proc;  
2941   
2942   FilterSetPtr             fsp;
2943 } SetSampleData, PNTR SetSamplePtr;
2944 
2945 static ValNodePtr IntValNodeCopy (ValNodePtr vnp)
2946 {
2947   ValNodePtr vnp_new;
2948   
2949   if (vnp == NULL)
2950   {
2951     return NULL;
2952   }
2953   vnp_new = ValNodeNew (NULL);
2954   if (vnp_new != NULL)
2955   {
2956     vnp_new->choice = vnp->choice;
2957     vnp_new->data.intvalue = vnp->data.intvalue;
2958   }
2959   return vnp_new;
2960 }
2961 
2962 static Boolean IntValNodeMatch (ValNodePtr vnp1, ValNodePtr vnp2)
2963 {
2964   if (vnp1 == NULL && vnp2 == NULL)
2965   {
2966     return TRUE;
2967   }
2968   else if (vnp1 == NULL || vnp2 == NULL)
2969   {
2970     return FALSE;
2971   }
2972   else if (vnp1->data.intvalue == vnp2->data.intvalue)
2973   {
2974     return TRUE;
2975   }
2976   else
2977   {
2978     return FALSE;
2979   }
2980 }
2981 
2982 static void LocationConstraintXClearText (LocationConstraintXPtr lcp)
2983 {
2984   if (lcp != NULL)
2985   {
2986     lcp->left = -1;
2987     lcp->right = -1;
2988   }
2989 }
2990 
2991 static LocationConstraintXPtr LocationConstraintXFree (LocationConstraintXPtr lcp)
2992 {
2993   lcp = MemFree (lcp);
2994   return lcp;
2995 }
2996 
2997 static LocationConstraintXPtr LocationConstraintXCopy (LocationConstraintXPtr lcp)
2998 {
2999   LocationConstraintXPtr lcp_new;
3000   if (lcp == NULL)
3001   {
3002     return NULL;
3003   }
3004   lcp_new = (LocationConstraintXPtr) MemNew (sizeof (LocationConstraintXData));
3005   if (lcp_new != NULL)
3006   {
3007     lcp_new->left = lcp->left;
3008     lcp_new->right = lcp->right;
3009     lcp_new->interval_end_choice = lcp->interval_end_choice;
3010     lcp_new->match_choice = lcp->match_choice;
3011     lcp_new->strand = lcp->strand;
3012     lcp_new->sequence_type = lcp->sequence_type;
3013   }
3014   return lcp_new;
3015 }
3016 
3017 extern StringConstraintXPtr StringConstraintXFree (StringConstraintXPtr scp)
3018 {
3019   if (scp == NULL) return NULL;
3020   scp->match_text = MemFree (scp->match_text);
3021   scp = MemFree (scp);
3022   return scp;  
3023 }
3024 
3025 static void StringConstraintClearText (StringConstraintXPtr scp)
3026 {
3027   if (scp != NULL)
3028   {
3029     scp->match_text = MemFree (scp->match_text);
3030   }
3031 }
3032 
3033 static StringConstraintXPtr StringConstraintCopy (StringConstraintXPtr scp)
3034 {
3035   StringConstraintXPtr scp_new;
3036   if (scp == NULL)
3037   {
3038     return NULL;
3039   }
3040   
3041   scp_new = (StringConstraintXPtr) MemNew (sizeof (StringConstraintData));
3042   if (scp_new != NULL)
3043   {
3044     scp_new->match_text = StringSave (scp->match_text);
3045     scp_new->match_location = scp->match_location;
3046     scp_new->insensitive = scp->insensitive;
3047     scp_new->whole_word = scp->whole_word;
3048     scp_new->not_present = scp->not_present;   
3049   }
3050   return scp_new;
3051 }
3052 
3053 extern ValNodePtr ValNodeFuncFree (ValNodePtr vnp, FreeValNodeProc free_vn_proc)
3054 {
3055   if (vnp == NULL)
3056   {
3057     return NULL;
3058   }
3059   vnp->next = ValNodeFuncFree (vnp->next, free_vn_proc);
3060   if (free_vn_proc != NULL)
3061   {
3062     free_vn_proc (vnp);
3063   }
3064   ValNodeFree (vnp);
3065   return NULL;
3066 }
3067 
3068 extern ChoiceConstraintPtr ChoiceConstraintFree (ChoiceConstraintPtr scp)
3069 {
3070   if (scp == NULL) return NULL;
3071   scp->qual_choice = ValNodeFuncFree (scp->qual_choice, scp->free_vn_proc);
3072   scp->qual_choice_match = ValNodeFuncFree (scp->qual_choice, scp->free_vn_proc);
3073   scp->string_constraint = StringConstraintXFree (scp->string_constraint);
3074   scp->pseudo_constraint = MemFree (scp->pseudo_constraint);
3075   scp = MemFree (scp);
3076   return scp;
3077 }
3078 
3079 static ValNodePtr QualChoiceCopy (ValNodePtr vnp, CopyValNodeDataProc copy_vn_proc)
3080 {
3081   ValNodePtr new_list = NULL;
3082   
3083   if (vnp == NULL || copy_vn_proc == NULL)
3084   {
3085     return NULL;
3086   }
3087   
3088   new_list = copy_vn_proc (vnp);
3089   new_list->next = QualChoiceCopy (vnp->next, copy_vn_proc);
3090   return new_list;
3091 }
3092 
3093 static ChoiceConstraintPtr ChoiceConstraintCopy (ChoiceConstraintPtr ccp)
3094 {
3095   ChoiceConstraintPtr ccp_new;
3096   if (ccp == NULL || ccp->copy_vn_proc == NULL)
3097   {
3098     return NULL;
3099   }
3100   ccp_new = (ChoiceConstraintPtr) MemNew (sizeof (ChoiceConstraintData));
3101   if (ccp_new != NULL)
3102   {
3103     ccp_new->constraint_type = ccp->constraint_type;
3104     ccp_new->qual_choice = QualChoiceCopy (ccp->qual_choice, ccp->copy_vn_proc);
3105     ccp_new->qual_choice_match = QualChoiceCopy (ccp->qual_choice_match, ccp->copy_vn_proc);
3106     ccp_new->string_constraint = StringConstraintCopy (ccp->string_constraint);
3107     ccp_new->copy_vn_proc = ccp->copy_vn_proc;
3108     ccp_new->free_vn_proc = ccp->free_vn_proc;
3109   }
3110   return ccp_new;
3111 }
3112 
3113 static void ChoiceConstraintClearText (ChoiceConstraintPtr scp)
3114 {
3115   if (scp != NULL)
3116   {
3117     StringConstraintClearText (scp->string_constraint);
3118   }
3119 }
3120 
3121 
3122 extern void FilterSetClearText (FilterSetPtr fsp)
3123 {
3124   if (fsp != NULL)
3125   {
3126     StringConstraintClearText (fsp->scp);
3127     ChoiceConstraintClearText (fsp->ccp);
3128     LocationConstraintXClearText (fsp->lcp);
3129     StringConstraintClearText (fsp->id_list);
3130   }
3131 }
3132 
3133 extern FilterSetPtr FilterSetNew (void)
3134 {
3135   FilterSetPtr fsp_new;
3136   fsp_new = (FilterSetPtr) MemNew (sizeof (FilterSetData));
3137   if (fsp_new != NULL)
3138   {
3139     fsp_new->scp = NULL;
3140     fsp_new->ccp = NULL;
3141     fsp_new->lcp = NULL;
3142     fsp_new->cgp = NULL;
3143     fsp_new->id_list = NULL;
3144   }
3145   return fsp_new;
3146 }
3147 
3148 extern FilterSetPtr FilterSetFree (FilterSetPtr fsp)
3149 {
3150   if (fsp != NULL)
3151   {
3152     fsp->scp = StringConstraintXFree (fsp->scp);
3153     fsp->ccp = ChoiceConstraintFree (fsp->ccp);
3154     fsp->lcp = LocationConstraintXFree (fsp->lcp);
3155     fsp->cgp = ChoiceConstraintFree (fsp->cgp);
3156     fsp->id_list = StringConstraintXFree (fsp->id_list);
3157     fsp = MemFree (fsp);
3158   }
3159   return fsp;
3160 }
3161 
3162 static FilterSetPtr FilterSetCopy (FilterSetPtr fsp)
3163 {
3164   FilterSetPtr fsp_new;
3165   
3166   if (fsp == NULL)
3167   {
3168     return NULL;
3169   }
3170   fsp_new = (FilterSetPtr) MemNew (sizeof (FilterSetData));
3171   if (fsp_new != NULL)
3172   {
3173     fsp_new->scp = StringConstraintCopy (fsp->scp);
3174     fsp_new->ccp = ChoiceConstraintCopy (fsp->ccp);
3175     fsp_new->lcp = LocationConstraintXCopy (fsp->lcp);
3176     fsp_new->cgp = ChoiceConstraintCopy (fsp->cgp);
3177     fsp_new->id_list = StringConstraintCopy (fsp->id_list);
3178   }
3179   return fsp_new;
3180 }
3181 
3182 
3183 static SetSamplePtr SetSampleFree (SetSamplePtr ssp)
3184 {
3185   ValNodePtr vnp;
3186   
3187   if (ssp == NULL)
3188   {
3189     return NULL;
3190   }
3191   if (ssp->free_vn_proc != NULL)
3192   {
3193     for (vnp = ssp->field_list; vnp != NULL; vnp = vnp->next)
3194     {
3195       (ssp->free_vn_proc)(vnp);
3196     }
3197   }
3198   ssp->field_list = ValNodeFree (ssp->field_list);
3199    
3200   ssp = MemFree (ssp);
3201   return ssp;
3202 }
3203 
3204 static SetSamplePtr SetSampleCopy (SetSamplePtr ssp)
3205 {
3206   SetSamplePtr ssp_new;
3207   ValNodePtr   vnp_old, vnp_new, vnp_last = NULL;
3208   
3209   if (ssp == NULL)
3210   {
3211     return NULL;
3212   }
3213   ssp_new = (SetSamplePtr) MemNew (sizeof (SetSampleData));
3214   if (ssp_new != NULL)
3215   {
3216     ssp_new->fieldstring_func = ssp->fieldstring_func;
3217     ssp_new->descrstring_func = ssp->descrstring_func;
3218     ssp_new->free_vn_proc = ssp->free_vn_proc;
3219     ssp_new->copy_vn_proc = ssp->copy_vn_proc;
3220     ssp_new->match_vn_proc = ssp->match_vn_proc;
3221     ssp_new->label_vn_proc = ssp->label_vn_proc;  
3222     
3223     ssp_new->entityID = ssp->entityID;
3224     ssp_new->field_list = NULL;
3225     for (vnp_old = ssp->field_list; vnp_old != NULL; vnp_old = vnp_old->next)
3226     {
3227       vnp_new = (ssp_new->copy_vn_proc)(vnp_old);
3228       if (vnp_last == NULL)
3229       {
3230         ssp_new->field_list = vnp_new;
3231       }
3232       else
3233       {
3234         vnp_last->next = vnp_new;
3235       }
3236       vnp_last = vnp_new;
3237     }
3238     ssp_new->fsp = FilterSetCopy (ssp->fsp);
3239   }
3240   return ssp_new;
3241 }
3242 
3243 #define PARSE_FIELD_DEFLINE       1
3244 #define PARSE_FIELD_BIOSRC_STRING 2
3245 #define PARSE_FIELD_SOURCE_QUAL   3
3246 #define PARSE_FIELD_GENE_FIELD    4
3247 #define PARSE_FIELD_RNA_FIELD    5
3248 #define PARSE_FIELD_CDS_COMMENT   6
3249 #define PARSE_FIELD_PROTEIN_FIELD 7
3250 #define PARSE_FIELD_IMPORT_QUAL   8
3251 #define PARSE_FIELD_FEATURE_NOTE  9
3252 #define PARSE_FIELD_COMMENT_DESC  10
3253 #define PARSE_FIELD_DBXREF        11
3254 
3255 #define MAX_PARSE_FIELD_TYPE   11
3256 #define SEARCH_FIELD_PUBLICATION  12
3257 
3258 #define PARSE_FIELD_FIRST_FEATURE 4
3259 #define PARSE_FIELD_LAST_FEATURE  9
3260 
3261 extern Boolean DoesLocationMatchConstraint (SeqLocPtr slp, LocationConstraintXPtr lcp);
3262 
3263 typedef struct acceptpolicy 
3264 {
3265   Boolean leave_dlg_up;
3266 } AcceptPolicyData, PNTR AcceptPolicyPtr;
3267 
3268 typedef struct acceptcanceldialog 
3269 {
3270   DIALOG_MESSAGE_BLOCK
3271   Nlm_AcceptActnProc    accept_actn;
3272   Nlm_CancelActnProc    cancel_actn;
3273   Nlm_ClearActnProc     clear_actn;
3274   Nlm_ClearTextActnProc clear_text_actn;
3275   WindoW                w;
3276   
3277   ButtoN                accept_btn;
3278   
3279   ButtoN                leave_dlg_up_btn;
3280 } AcceptCancelDialogData, PNTR AcceptCancelDialogPtr;
3281 
3282 static void AcceptCancelDialogAccept (ButtoN b)
3283 {
3284   AcceptCancelDialogPtr acdp;
3285 
3286   acdp = (AcceptCancelDialogPtr) GetObjectExtra (b);
3287   if (acdp == NULL) return;
3288   
3289   if (acdp->accept_actn != NULL)
3290   {
3291     if (!((acdp->accept_actn) (acdp->userdata)))
3292     {
3293       return;
3294     }
3295   }
3296   if (! GetStatus (acdp->leave_dlg_up_btn))
3297   {
3298     Remove (acdp->w);
3299   }
3300 }
3301 
3302 static void AcceptCancelDialogCancel (ButtoN b)
3303 {
3304   AcceptCancelDialogPtr acdp;
3305 
3306   acdp = (AcceptCancelDialogPtr) GetObjectExtra (b);
3307   if (acdp == NULL) return;
3308   
3309   if (acdp->cancel_actn != NULL)
3310   {
3311     (acdp->cancel_actn) (acdp->userdata);    
3312   }
3313   Remove (acdp->w);
3314 }
3315 
3316 static void AcceptCancelDialogClear (ButtoN b)
3317 {
3318   AcceptCancelDialogPtr acdp;
3319 
3320   acdp = (AcceptCancelDialogPtr) GetObjectExtra (b);
3321   if (acdp == NULL || acdp->clear_actn == NULL) return;
3322   
3323   (acdp->clear_actn) (acdp->userdata);
3324 }
3325 
3326 static void AcceptCancelDialogClearText (ButtoN b)
3327 {
3328   AcceptCancelDialogPtr acdp;
3329 
3330   acdp = (AcceptCancelDialogPtr) GetObjectExtra (b);
3331   if (acdp == NULL || acdp->clear_text_actn == NULL) return;
3332   
3333   (acdp->clear_text_actn) (acdp->userdata);
3334 }
3335 
3336 static void AcceptPolicyToAcceptCancelDialog (DialoG d, Pointer data)
3337 
3338 {
3339   AcceptCancelDialogPtr   acdp;
3340   AcceptPolicyPtr         app;
3341 
3342   acdp = (AcceptCancelDialogPtr) GetObjectExtra (d);
3343   app = (AcceptPolicyPtr) data;
3344   if (acdp == NULL || app == NULL)
3345   {
3346     return;
3347   }
3348 
3349   SetStatus (acdp->leave_dlg_up_btn, app->leave_dlg_up);  
3350 }
3351 
3352 static Pointer AcceptCancelDialogToAcceptPolicy (DialoG d)
3353 {
3354   AcceptCancelDialogPtr acdp;
3355   AcceptPolicyPtr       app;
3356   
3357   acdp = (AcceptCancelDialogPtr) GetObjectExtra (d);
3358   if (acdp == NULL) 
3359   {
3360     return NULL;
3361   }
3362   
3363   app = (AcceptPolicyPtr) MemNew (sizeof (AcceptPolicyData));
3364   if (app != NULL)
3365   {
3366     app->leave_dlg_up = GetStatus (acdp->leave_dlg_up_btn);
3367   }
3368   return app;
3369 }
3370 
3371 static void AcceptCancelMessage (DialoG d, Int2 mssg)
3372 
3373 {
3374   AcceptCancelDialogPtr acdp;
3375 
3376   acdp = (AcceptCancelDialogPtr) GetObjectExtra (d);
3377   if (acdp != NULL) {
3378     switch (mssg) {
3379       case VIB_MSG_INIT :
3380         /* reset accept policy */
3381         SetStatus (acdp->leave_dlg_up_btn, FALSE);
3382         break;
3383       case VIB_MSG_ENTER :
3384         Select (acdp->accept_btn);
3385         break;
3386       default :
3387         break;
3388     }
3389   }
3390 }
3391 
3392 static ValNodePtr TestAcceptCancelDialog (DialoG d)
3393 
3394 {
3395   return NULL;
3396 }
3397 
3398 extern DialoG AcceptCancelDialog 
3399 (GrouP                 parent,
3400  Nlm_AcceptActnProc    accept_actn,
3401  Nlm_CancelActnProc    cancel_actn,
3402  Nlm_ClearActnProc     clear_actn,
3403  Nlm_ClearTextActnProc clear_text_actn,
3404  Pointer               userdata,
3405  WindoW                w)
3406 {
3407   AcceptCancelDialogPtr acdp;
3408   GrouP                 grp, policy_grp = NULL, other_grp;
3409   ButtoN                b;
3410   
3411   acdp = (AcceptCancelDialogPtr) MemNew (sizeof (AcceptCancelDialogData));
3412   grp = HiddenGroup (parent, -1, 0, NULL);
3413   SetObjectExtra (grp, acdp, StdCleanupExtraProc);
3414   SetGroupSpacing (grp, 10, 10);
3415 
3416   acdp->dialog = (DialoG) grp;
3417   acdp->todialog = AcceptPolicyToAcceptCancelDialog;
3418   acdp->fromdialog = AcceptCancelDialogToAcceptPolicy;
3419   acdp->dialogmessage = AcceptCancelMessage;
3420   acdp->testdialog = TestAcceptCancelDialog;
3421 
3422   acdp->accept_actn             = accept_actn;
3423   acdp->cancel_actn             = cancel_actn;
3424   acdp->clear_actn              = clear_actn;
3425   acdp->clear_text_actn         = clear_text_actn;
3426   acdp->userdata                = userdata;
3427   acdp->w                       = w;
3428 
3429   policy_grp = HiddenGroup (grp, 3, 0, NULL);
3430   SetGroupSpacing (policy_grp, 10, 10);
3431   
3432   b = PushButton (policy_grp, "Clear", AcceptCancelDialogClear);
3433   SetObjectExtra (b, acdp, NULL);
3434  
3435   b = PushButton (policy_grp, "Clear Text", AcceptCancelDialogClearText);
3436   SetObjectExtra (b, acdp, NULL);
3437   
3438   acdp->leave_dlg_up_btn = CheckBox (policy_grp, "Leave Dialog Up", NULL);
3439   
3440   other_grp = HiddenGroup (grp, 5, 0, NULL);
3441   SetGroupSpacing (other_grp, 10, 10);
3442   acdp->accept_btn = PushButton (other_grp, "Accept", AcceptCancelDialogAccept);
3443   SetObjectExtra (acdp->accept_btn, acdp, NULL);
3444   
3445   b = PushButton (other_grp, "Cancel", AcceptCancelDialogCancel);
3446   SetObjectExtra (b, acdp, NULL);
3447   
3448   AlignObjects (ALIGN_CENTER, (HANDLE) policy_grp, (HANDLE) other_grp, NULL);
3449   
3450   return (DialoG) grp;
3451 }
3452 
3453 
3454 extern void EnableAcceptCancelDialogAccept (DialoG d)
3455 {
3456   AcceptCancelDialogPtr acdp;
3457 
3458   acdp = (AcceptCancelDialogPtr) GetObjectExtra (d);
3459 
3460   if (acdp == NULL) return;
3461   
3462   InvalObject (acdp->accept_btn);
3463   SafeEnable (acdp->accept_btn);
3464   Update ();
3465 }
3466 
3467 extern void DisableAcceptCancelDialogAccept (DialoG d)
3468 {
3469   AcceptCancelDialogPtr acdp;
3470 
3471   acdp = (AcceptCancelDialogPtr) GetObjectExtra (d);
3472 
3473   if (acdp == NULL) return;
3474   
3475   InvalObject (acdp->accept_btn);
3476   SafeDisable (acdp->accept_btn);
3477   Update ();
3478 }
3479 
3480 
3481 
3482 
3483 
3484 static ValNodePtr ValNodeAppend (ValNodePtr list, ValNodePtr second_list)
3485 {
3486   ValNodePtr last_vnp;
3487   
3488   if (list == NULL)
3489   {
3490     list = second_list;
3491   }
3492   else if (second_list != NULL)
3493   {
3494     last_vnp = list;
3495     while (last_vnp != NULL && last_vnp->next != NULL)
3496     {
3497       last_vnp = last_vnp->next;
3498     }
3499     last_vnp->next = second_list;
3500   }
3501   return list;
3502 }
3503 
3504 static void FindFeatureTypeCallback (SeqFeatPtr sfp, Pointer userdata)
3505 {
3506   BoolPtr type_list;
3507   
3508   if (sfp == NULL || userdata == NULL) return;
3509   
3510   type_list = (BoolPtr) userdata;
3511   type_list[sfp->idx.subtype] = TRUE;
3512 }
3513 
3514 
3515 static void AddFeatureToList (ValNodePtr PNTR list, FeatDefPtr curr)
3516 {
3517   Char        str [256];
3518 
3519   if (list == NULL || curr == NULL) return;
3520   
3521   if (curr->featdef_key == FEATDEF_PUB)
3522   {
3523     StringNCpy_0 (str, curr->typelabel, sizeof (str) - 15);
3524     StringCat (str, " (Publication)");
3525     ValNodeAddPointer (list, curr->featdef_key, StringSave (str));
3526   }
3527   else if (curr->featdef_key == FEATDEF_BIOSRC)
3528   {
3529     ValNodeAddPointer (list, FEATDEF_BIOSRC, StringSave ("BioSource"));
3530   }
3531   else if (curr->featdef_key == FEATDEF_otherRNA)
3532   {
3533     ValNodeAddPointer (list, FEATDEF_otherRNA, StringSave ("misc_RNA"));
3534   }
3535   else if (curr->featdef_key == FEATDEF_misc_RNA ||
3536            curr->featdef_key == FEATDEF_precursor_RNA ||
3537            curr->featdef_key == FEATDEF_mat_peptide ||
3538            curr->featdef_key == FEATDEF_sig_peptide ||
3539            curr->featdef_key == FEATDEF_transit_peptide ||
3540            curr->featdef_key == FEATDEF_Imp_CDS)
3541   {
3542     StringNCpy_0 (str, curr->typelabel, sizeof (str) - 10);
3543     StringCat (str, "_imp");
3544     ValNodeAddPointer (list, curr->featdef_key, StringSave (str));
3545   }
3546   else
3547   {
3548     ValNodeAddPointer (list, curr->featdef_key, StringSave (curr->typelabel));
3549   }
3550 }
3551 
3552 extern ValNodePtr BuildFeatureDialogList (Boolean list_most_used_first, SeqEntryPtr sep)
3553 {
3554   ValNodePtr  feature_choice_list = NULL;
3555   ValNodePtr  import_feature_list = NULL;
3556   ValNodePtr  least_liked_feature_list = NULL;
3557   ValNodePtr  most_used_feature_list = NULL;
3558   ValNodePtr  unused_list = NULL;
3559   FeatDefPtr  curr;
3560   Uint1       key;
3561   CharPtr     label = NULL;
3562   Boolean     feature_type_list[256];
3563   Boolean     only_most_used = TRUE;
3564   Int4        i;
3565 
3566   if (sep == NULL) {
3567       for (i = 0; i < 255; i++) {
3568           feature_type_list[i] = TRUE;
3569       }
3570   } else {
3571       for (i = 0; i < 255; i++) {
3572           feature_type_list[i] = FALSE;
3573       }
3574       VisitFeaturesInSep (sep, feature_type_list, FindFeatureTypeCallback);
3575   }
3576 
3577   curr = FeatDefFindNext (NULL, &key, &label, FEATDEF_ANY, TRUE);
3578   while (curr != NULL) {
3579     if (key == FEATDEF_BAD
3580         || key == FEATDEF_Imp_CDS
3581         || key == FEATDEF_source
3582         || key == FEATDEF_ORG
3583         || IsUnwantedFeatureType (key))
3584     {
3585       curr = FeatDefFindNext (curr, &key, &label, FEATDEF_ANY, TRUE);
3586       continue;
3587     }
3588     else if (!feature_type_list[key]) 
3589     {
3590       AddFeatureToList (&unused_list, curr);
3591       curr = FeatDefFindNext (curr, &key, &label, FEATDEF_ANY, TRUE);
3592       continue;
3593     }
3594     
3595     if (curr->featdef_key == FEATDEF_otherRNA) {
3596       AddFeatureToList (&feature_choice_list, curr);
3597       if (list_most_used_first) {
3598         AddFeatureToList (&most_used_feature_list, curr);
3599       }
3600     }
3601     else if (curr->featdef_key == FEATDEF_misc_RNA ||
3602             curr->featdef_key == FEATDEF_precursor_RNA ||
3603             curr->featdef_key == FEATDEF_mat_peptide ||
3604             curr->featdef_key == FEATDEF_sig_peptide ||
3605             curr->featdef_key == FEATDEF_transit_peptide ||
3606             curr->featdef_key == FEATDEF_Imp_CDS)
3607     {
3608       AddFeatureToList (&import_feature_list, curr);
3609     }
3610     else if (curr->featdef_key == FEATDEF_TXINIT)
3611     {
3612       AddFeatureToList (&least_liked_feature_list, curr);
3613     }
3614     else
3615     {
3616       ValNodeAddPointer (&feature_choice_list, curr->featdef_key, StringSave (curr->typelabel));
3617     }
3618     
3619     if (list_most_used_first)
3620     {
3621       /* also build most used list */
3622       if (curr->featdef_key == FEATDEF_CDS
3623           || curr->featdef_key == FEATDEF_exon
3624           || curr->featdef_key == FEATDEF_GENE
3625           || curr->featdef_key == FEATDEF_intron
3626           || curr->featdef_key == FEATDEF_mRNA
3627           || curr->featdef_key == FEATDEF_rRNA
3628           || curr->featdef_key == FEATDEF_PROT)
3629       {
3630         ValNodeAddPointer (&most_used_feature_list, curr->featdef_key, 
3631                            StringSave (curr->typelabel));
3632       }
3633       else
3634       {
3635         only_most_used = FALSE;
3636       }
3637     }
3638     
3639     curr = FeatDefFindNext (curr, &key, &label, FEATDEF_ANY, TRUE);
3640   }
3641 
3642   most_used_feature_list = SortValNode (most_used_feature_list,
3643                                         CompareFeatureValNodeStrings);
3644   feature_choice_list = SortValNode (feature_choice_list,
3645                                      CompareFeatureValNodeStrings);
3646   import_feature_list = SortValNode (import_feature_list,
3647                                      CompareFeatureValNodeStrings);
3648   least_liked_feature_list = SortValNode (least_liked_feature_list,
3649                                           CompareFeatureValNodeStrings);
3650   unused_list = SortValNode (unused_list, CompareFeatureValNodeStrings);       
3651 
3652   if (most_used_feature_list != NULL && only_most_used) {
3653     feature_choice_list = ValNodeFreeData (feature_choice_list);
3654     feature_choice_list = most_used_feature_list;
3655     least_liked_feature_list = ValNodeFreeData(least_liked_feature_list);
3656     import_feature_list = ValNodeFreeData(least_liked_feature_list);
3657   } else {
3658     feature_choice_list = ValNodeAppend (most_used_feature_list, feature_choice_list);
3659     feature_choice_list = ValNodeAppend (feature_choice_list, least_liked_feature_list);
3660     feature_choice_list = ValNodeAppend (feature_choice_list, import_feature_list);
3661   }
3662   feature_choice_list = ValNodeAppend (feature_choice_list, unused_list);
3663   
3664   return feature_choice_list;
3665 }
3666 
3667 static ValNodePtr BuildImportList (void)
3668 {
3669   ValNodePtr  import_feature_list = NULL;
3670   FeatDefPtr  curr;
3671   Uint1       key;
3672   CharPtr     label = NULL;
3673   Char        str [256];
3674 
3675   curr = FeatDefFindNext (NULL, &key, &label, FEATDEF_ANY, TRUE);
3676   while (curr != NULL) {
3677     if (FindFeatFromFeatDefType (key) == SEQFEAT_IMP && !IsUnwantedFeatureType(key))
3678     {
3679       ValNodeAddPointer (&import_feature_list, curr->featdef_key, StringSave (str));
3680     }
3681     
3682     curr = FeatDefFindNext (curr, &key, &label, FEATDEF_ANY, TRUE);
3683   } 
3684   return import_feature_list; 
3685 }
3686 
3687 static void RemoveFeatureSelectionDuplicates (ValNodePtr orig_list)
3688 {
3689   ValNodePtr vnp1, vnp2, prev_vnp, next_vnp;
3690   
3691   if (orig_list == NULL || orig_list->next == NULL)
3692   {
3693     return;
3694   }
3695   
3696   vnp1 = orig_list;
3697   while (vnp1 != NULL && vnp1->next != NULL)
3698   {
3699     vnp2 = vnp1->next;
3700     prev_vnp = vnp1;
3701     while (vnp2 != NULL)
3702     {
3703       next_vnp = vnp2->next;
3704       if (vnp2->choice == vnp1->choice)
3705       {
3706         prev_vnp->next = next_vnp;
3707         vnp2->next = NULL;
3708         vnp2 = ValNodeFreeData (vnp2);
3709       }
3710       else
3711       {
3712         prev_vnp = vnp2;
3713       }
3714       vnp2 = next_vnp;
3715     }
3716     vnp1 = vnp1->next;
3717   }
3718 }
3719 
3720 static ValNodePtr FeatureSelectionRemap (ValNodePtr orig_list)
3721 {
3722   ValNodePtr vnp, vnp_next, prev_vnp, repl_vnp = NULL;
3723   
3724   if (orig_list == NULL)
3725   {
3726     return NULL;
3727   }
3728   
3729   vnp = orig_list;
3730   prev_vnp = NULL;
3731   while (vnp != NULL && repl_vnp == NULL)
3732   {
3733     vnp_next = vnp->next;
3734     /* replace FEATDEF_IMP with list of import features */
3735     if (vnp->choice == FEATDEF_IMP)
3736     {
3737       /* build replacement list */
3738       repl_vnp = BuildImportList ();
3739       
3740       ValNodeLink (&repl_vnp, vnp->next);
3741       
3742       if (prev_vnp == NULL)
3743       {
3744         orig_list = repl_vnp;
3745       }
3746       else
3747       {
3748         prev_vnp->next = repl_vnp;
3749       }
3750 
3751       vnp->next = NULL;
3752       ValNodeFreeData (vnp);
3753     }
3754     else
3755     {
3756       prev_vnp = vnp;
3757     }
3758     vnp = vnp_next;
3759   }
3760   
3761   RemoveFeatureSelectionDuplicates (orig_list);
3762   
3763   return orig_list; 
3764 }
3765 
3766 extern DialoG 
3767 FeatureSelectionDialogEx 
3768 (GrouP                    h,
3769  Boolean                  allow_multi,
3770  SeqEntryPtr              sep,
3771  Nlm_ChangeNotifyProc     change_notify,
3772  Pointer                  change_userdata)
3773 {
3774   DialoG      dlg;
3775   ValNodePtr  feature_choice_list, vnp, vnp_next, vnp_prev;
3776   Boolean     found_import = FALSE;
3777 
3778   feature_choice_list = BuildFeatureDialogList (TRUE, sep);
3779   
3780   if (!allow_multi)
3781   {
3782     /* remove Import option */
3783     vnp_prev = NULL;
3784     for (vnp = feature_choice_list; vnp != NULL && !found_import; vnp = vnp_next)
3785     {
3786       vnp_next = vnp->next;
3787       if (vnp->choice == FEATDEF_IMP)
3788       {
3789         if (vnp_prev == NULL)
3790         {
3791           feature_choice_list = vnp_next;
3792         }
3793         else
3794         {
3795           vnp_prev->next = vnp_next;
3796         }
3797         vnp->next = NULL;
3798         vnp = ValNodeFreeData (vnp);
3799         found_import = TRUE;
3800       }
3801       else
3802       {
3803         vnp_prev = vnp;
3804       }
3805     }
3806   }
3807   
3808   /* note - the ValNodeSelectionDialog will free the feature_choice_list when done */
3809   
3810   dlg = ValNodeSelectionDialogEx (h, feature_choice_list, TALL_SELECTION_LIST, 
3811                                 ValNodeStringName,
3812                                 ValNodeSimpleDataFree, ValNodeStringCopy,
3813                                 ValNodeChoiceMatch, "feature list", 
3814                                 change_notify, change_userdata, allow_multi, FALSE,
3815                                 allow_multi ? FeatureSelectionRemap : NULL);
3816   return dlg;
3817 }
3818 
3819 extern DialoG 
3820 FeatureSelectionDialog 
3821 (GrouP                    h,
3822  Boolean                  allow_multi,
3823  Nlm_ChangeNotifyProc     change_notify,
3824  Pointer                  change_userdata)
3825 {
3826   return FeatureSelectionDialogEx(h, allow_multi, NULL, change_notify, change_userdata);
3827 }
3828 
3829 extern DialoG
3830 DescriptorSelectionDialog
3831 (GrouP                    h,
3832  Boolean                  allow_multi,
3833  Nlm_ChangeNotifyProc     change_notify,
3834  Pointer                  change_userdata)
3835 {
3836   ValNodePtr descriptor_list = BuildDescriptorValNodeList ();
3837   return ValNodeSelectionDialogEx (h, descriptor_list, TALL_SELECTION_LIST,
3838                                 ValNodeStringName,
3839                                 ValNodeSimpleDataFree, ValNodeStringCopy,
3840                                 ValNodeChoiceMatch, "descriptor list", 
3841                                 change_notify, change_userdata, allow_multi, FALSE,
3842                                 NULL);
3843 }
3844 
3845 
3846 extern CharPtr SourceQualValNodeName (ValNodePtr vnp)
3847 {
3848   SourceQualDescPtr           sqdp;
3849   
3850   if (vnp == NULL || vnp->data.ptrvalue == NULL)
3851   {
3852     return NULL;
3853   }
3854   else if (vnp->choice == 0)
3855   {
3856     sqdp = (SourceQualDescPtr) vnp->data.ptrvalue;
3857     return StringSave (sqdp->name);
3858   }
3859   else
3860   {
3861     return StringSave (vnp->data.ptrvalue);
3862   }
3863 }
3864 
3865 extern ValNodePtr SourceQualValNodeDataCopy (ValNodePtr vnp)
3866 {
3867   SourceQualDescPtr           sqdp, new_sqdp = NULL;
3868   ValNodePtr                  vnp_copy = NULL;
3869   
3870   if (vnp != NULL && vnp->data.ptrvalue != NULL)
3871   {
3872     if (vnp->choice == 0)
3873     {
3874       sqdp = (SourceQualDescPtr) vnp->data.ptrvalue;
3875       new_sqdp = (SourceQualDescPtr) MemNew (sizeof (SourceQualDescData));
3876       if (new_sqdp != NULL)
3877       {
3878         MemCpy (new_sqdp, sqdp, sizeof (SourceQualDescData));
3879       }
3880       ValNodeAddPointer (&vnp_copy, vnp->choice, new_sqdp);
3881     }
3882     else
3883     {
3884       ValNodeAddPointer (&vnp_copy, vnp->choice, StringSave (vnp->data.ptrvalue));
3885     }
3886   }
3887   return vnp_copy;
3888 }
3889 
3890 extern Boolean SourceQualValNodeMatch (ValNodePtr vnp1, ValNodePtr vnp2)
3891 {
3892   SourceQualDescPtr  sqdp1, sqdp2;
3893   Boolean            rval = FALSE;
3894   
3895   if (vnp1 == NULL || vnp2 == NULL
3896       || vnp1->data.ptrvalue == NULL || vnp2->data.ptrvalue == NULL)
3897   {
3898     rval = FALSE;
3899   }
3900   else if (vnp1->choice != vnp2->choice)
3901   {
3902     rval = FALSE;
3903   }
3904   else if (vnp1->choice == 0)
3905   {
3906     sqdp1 = (SourceQualDescPtr) vnp1->data.ptrvalue;
3907     sqdp2 = (SourceQualDescPtr) vnp2->data.ptrvalue;
3908   
3909     if (sqdp1->subtype == sqdp2->subtype
3910         && ((sqdp1->isOrgMod && sqdp2->isOrgMod)
3911             || (!sqdp1->isOrgMod && ! sqdp2->isOrgMod)))
3912     {
3913       rval = TRUE;
3914     }
3915     else
3916     {
3917       rval = FALSE;
3918     }
3919   }
3920   else
3921   {
3922     if (StringCmp (vnp1->data.ptrvalue, vnp2->data.ptrvalue) == 0)
3923     {
3924       rval = TRUE;
3925     }
3926     else
3927     {
3928       rval = FALSE;
3929     }
3930   }
3931   return rval;
3932 }
3933 
3934 static DialoG SourceQualTypeSelectionDialogEx
3935 (GrouP h,
3936  Boolean                  allow_multi,
3937  Nlm_ChangeNotifyProc     change_notify,
3938  Pointer                  change_userdata,
3939  Int2                     list_height,
3940  Boolean                  show_discouraged,
3941  Boolean                  show_discontinued)
3942 
3943 {
3944   DialoG     dlg;
3945   ValNodePtr qual_choice_list;
3946 
3947   if (allow_multi)
3948   {
3949     qual_choice_list = ValNodeNew (NULL);
3950     qual_choice_list->choice = 1;
3951     qual_choice_list->data.ptrvalue = StringSave ("All Notes");
3952     qual_choice_list->next = GetSourceQualDescList (TRUE, TRUE, show_discouraged, show_discontinued);
3953   }
3954   else
3955   {
3956     qual_choice_list = GetSourceQualDescList (TRUE, TRUE, show_discouraged, show_discontinued);
3957   }
3958   /* note - the ValNodeSelectionDialog will free the qual_choice_list when done */                                            
3959   dlg = ValNodeSelectionDialog (h, qual_choice_list, list_height, SourceQualValNodeName,
3960                                 ValNodeSimpleDataFree, SourceQualValNodeDataCopy,
3961                                 SourceQualValNodeMatch, "feature list", 
3962                                 change_notify, change_userdata, allow_multi);
3963 
3964   return dlg;
3965 }
3966 
3967 extern DialoG SourceQualTypeSelectionDialog 
3968 (GrouP h,
3969  Boolean                  allow_multi,
3970  Nlm_ChangeNotifyProc     change_notify,
3971  Pointer                  change_userdata)
3972  
3973 {
3974   return SourceQualTypeSelectionDialogEx (h, allow_multi, change_notify,
3975                                           change_userdata, 6, FALSE, FALSE);
3976 }
3977 
3978 static DialoG SourceQualTypeDiscSelectionDialog 
3979 (GrouP h,
3980  Boolean                  allow_multi,
3981  Nlm_ChangeNotifyProc     change_notify,
3982  Pointer                  change_userdata)
3983  
3984 {
3985   return SourceQualTypeSelectionDialogEx (h, allow_multi, change_notify,
3986                                           change_userdata, 6, TRUE, TRUE);
3987 }
3988 
3989 static DialoG SourceQualTypeConstraintSelectionDialog
3990 (GrouP h,
3991  Boolean                  allow_multi,
3992  Nlm_ChangeNotifyProc     change_notify,
3993  Pointer                  change_userdata)
3994 
3995 {
3996   return SourceQualTypeSelectionDialogEx (h, allow_multi, change_notify,
3997                                           change_userdata, 4, TRUE, FALSE);
3998 }
3999 
4000 static DialoG SourceStringConstraintSelectionDialog
4001 (GrouP h,
4002  Boolean                  allow_multi,
4003  Nlm_ChangeNotifyProc     change_notify,
4004  Pointer                  change_userdata)
4005 
4006 {
4007   DialoG     dlg;
4008   ValNodePtr qual_choice_list = NULL;
4009 
4010   /* ignore allow_multi */
4011   
4012   ValNodeAddPointer (&qual_choice_list, 1, StringSave ("Organism or Any Qual"));
4013   ValNodeAddPointer (&qual_choice_list, 1, StringSave ("Organism"));
4014   qual_choice_list->next->next = GetSourceQualDescList (TRUE, TRUE, TRUE, FALSE);
4015   ValNodeAddPointer (&qual_choice_list, 1, StringSave ("Lineage"));
4016   ValNodeAddPointer (&qual_choice_list, 1, StringSave ("Location"));
4017 
4018   /* note - the ValNodeSelectionDialog will free the qual_choice_list when done */                                            
4019   dlg = ValNodeSelectionDialog (h, qual_choice_list, 4, SourceQualValNodeName,
4020                                 ValNodeSimpleDataFree, SourceQualValNodeDataCopy,
4021                                 SourceQualValNodeMatch, "feature list", 
4022                                 change_notify, change_userdata, FALSE);
4023 
4024   return dlg;
4025 }
4026 
4027 static Boolean OrgModSpecialMatch (OrgModPtr mod, FilterSetPtr fsp)
4028 {
4029   SourceQualDescPtr sqdp;
4030   
4031   if (mod == NULL)
4032   {
4033     return FALSE;
4034   }
4035   if (fsp == NULL
4036       || fsp->ccp == NULL 
4037       || fsp->ccp->constraint_type != CHOICE_CONSTRAINT_STRING
4038       || fsp->ccp->string_constraint == NULL
4039       || fsp->ccp->qual_choice == NULL
4040       || fsp->ccp->qual_choice->data.ptrvalue == NULL)
4041   {
4042     return TRUE;
4043   }
4044   
4045   sqdp = (SourceQualDescPtr) fsp->ccp->qual_choice->data.ptrvalue;
4046   if (sqdp->subtype != mod->subtype)
4047   {
4048     return TRUE;
4049   }
4050   
4051   if (DoesStringMatchConstraintX (mod->subname, fsp->ccp->string_constraint))
4052   {
4053     if (fsp->ccp->string_constraint->not_present)
4054     {
4055       return FALSE;
4056     }
4057     else
4058     {
4059       return TRUE;
4060     }
4061   }
4062   else
4063   {
4064     if (fsp->ccp->string_constraint->not_present)
4065     {
4066       return TRUE;
4067     }
4068     else
4069     {
4070       return FALSE;
4071     }
4072   }
4073 }
4074 
4075 static Boolean SubSrcSpecialMatch (SubSourcePtr ssp, FilterSetPtr fsp)
4076 {
4077   SourceQualDescPtr sqdp;
4078   
4079   if (ssp == NULL)
4080   {
4081     return FALSE;
4082   }
4083   if (fsp == NULL
4084       || fsp->ccp == NULL 
4085       || fsp->ccp->constraint_type != CHOICE_CONSTRAINT_STRING
4086       || fsp->ccp->string_constraint == NULL
4087       || fsp->ccp->qual_choice == NULL
4088       || fsp->ccp->qual_choice->data.ptrvalue == NULL)
4089   {
4090     return TRUE;
4091   }
4092   
4093   sqdp = (SourceQualDescPtr) fsp->ccp->qual_choice->data.ptrvalue;
4094   if (sqdp->subtype != ssp->subtype)
4095   {
4096     return TRUE;
4097   }
4098   if (DoesStringMatchConstraintX (ssp->name, fsp->ccp->string_constraint))
4099   {
4100     if (fsp->ccp->string_constraint->not_present)
4101     {
4102       return FALSE;
4103     }
4104     else
4105     {
4106       return TRUE;
4107     }
4108   }
4109   else
4110   {
4111     if (fsp->ccp->string_constraint->not_present)
4112     {
4113       return TRUE;
4114     }
4115     else
4116     {
4117       return FALSE;
4118     }
4119   }
4120 }
4121 
4122 
4123 static CharPtr GetSubfield (CharPtr str, Uint1 subfield)
4124 {
4125   CharPtr cp, cp2;
4126   Int4    num_colons = 0;
4127   CharPtr new_val = NULL;
4128 
4129   if (StringHasNoText (str)) {
4130     return NULL;
4131   }
4132 
4133   cp = StringChr (str, ':');
4134   while (cp != NULL) {
4135     num_colons ++;
4136     cp = StringChr (cp + 1, ':');
4137   }
4138 
4139   if (subfield == 0) {
4140     new_val = StringSave (str);
4141   } else if (subfield == 1) {
4142     if (num_colons == 0) {
4143       return NULL;
4144     } else {
4145       cp = StringChr (str, ':');
4146       new_val = (CharPtr) MemNew (sizeof (Char) * (cp - str + 1));
4147       StringNCpy (new_val, str, cp - str);
4148       new_val[cp - str] = 0;
4149     }
4150   } else if (subfield == 2) {
4151     if (num_colons == 0 || num_colons == 1) {
4152       return NULL;
4153     } else {
4154       cp = StringChr (str, ':');
4155       cp2 = StringChr (cp + 1, ':');
4156       new_val = (CharPtr) MemNew (sizeof (Char) * (cp2 - cp));
4157       StringNCpy (new_val, cp + 1, cp2 - cp - 1);
4158       new_val[cp2 - cp - 1] = 0;
4159     }
4160   } else {
4161     if (num_colons == 0) {
4162       new_val = StringSave (str);
4163     } else {
4164       cp = StringRChr (str, ':');
4165       new_val = StringSave (cp + 1);
4166     }
4167   }
4168   return new_val;
4169 }
4170 
4171 
4172 static CharPtr 
4173 GetSourceQualQualValueFromBiop 
4174 (BioSourcePtr      biop,
4175  SourceQualDescPtr sqdp,
4176  FilterSetPtr      fsp)
4177 {
4178   CharPtr            str = NULL, field, tmp_str;
4179   OrgModPtr          mod;
4180   SubSourcePtr       ssp;
4181   
4182   if (biop == NULL || sqdp == NULL)
4183   {
4184     return NULL;
4185   }
4186 
4187   if (sqdp->isOrgMod)
4188   {
4189     if (biop->org != NULL && biop->org->orgname != NULL)
4190     {
4191       mod = biop->org->orgname->mod;
4192       while (mod != NULL)
4193       {
4194         if (mod->subtype == sqdp->subtype
4195             && !StringHasNoText (mod->subname)
4196             && OrgModSpecialMatch (mod, fsp))
4197         {
4198           field = GetSubfield (mod->subname, sqdp->subfield);
4199           if (!StringHasNoText (field)) {
4200             if (str == NULL) {
4201               str = field;
4202             } else {
4203               tmp_str = (CharPtr) MemNew ((StringLen (str) + StringLen (field) + 3) * sizeof (Char));
4204               StringCpy (tmp_str, str);
4205               StringCat (tmp_str, "; ");
4206               StringCat (tmp_str, field);
4207               field = MemFree (field);
4208               str = MemFree (str);
4209               str = tmp_str;
4210             }
4211           } else {
4212             field = MemFree (field);
4213           }
4214         }
4215         mod = mod->next;
4216       }
4217     }
4218   }
4219   else
4220   {
4221     ssp = biop->subtype;
4222     while (ssp != NULL)
4223     {
4224       if (ssp->subtype == sqdp->subtype
4225           && !StringHasNoText (ssp->name)
4226           && SubSrcSpecialMatch (ssp, fsp))
4227       {
4228         field = GetSubfield (ssp->name, sqdp->subfield);
4229         if (!StringHasNoText (field)) {
4230           if (str == NULL) {
4231             str = field;
4232           } else {
4233             tmp_str = (CharPtr) MemNew ((StringLen (str) + StringLen (field) + 3) * sizeof (Char));
4234             StringCpy (tmp_str, str);
4235             StringCat (tmp_str, "; ");
4236             StringCat (tmp_str, field);
4237             field = MemFree (field);
4238             str = MemFree (str);
4239             str = tmp_str;
4240           }
4241         } else {
4242           field = MemFree (field);
4243         }
4244       }
4245       ssp = ssp->next;
4246     }
4247   }
4248   return str;  
4249 }
4250 
4251 static CharPtr GetLocationFromSource (BioSourcePtr biop, ValNodePtr vnp)
4252 {
4253   Nlm_EnumFieldAssocPtr eap;
4254   
4255   if (biop == NULL)
4256   {
4257     return NULL;
4258   }
4259   
4260   for (eap = biosource_genome_alistX;
4261        eap->name != NULL && eap->value != biop->genome;
4262        eap++)
4263   {
4264   }
4265   
4266   if (eap != NULL && eap->name != NULL && !StringHasNoText (eap->name))
4267   {
4268     return StringSave (eap->name);
4269   }
4270   else
4271   {
4272     return NULL;
4273   }  
4274 }
4275 
4276 static CharPtr GetLocationFromSourceFeature (SeqFeatPtr sfp, ValNodePtr vnp, FilterSetPtr fsp)
4277 {
4278   if (sfp != NULL && sfp->data.choice == SEQFEAT_BIOSRC)
4279   {
4280     return GetLocationFromSource (sfp->data.value.ptrvalue, vnp);
4281   }
4282   else
4283   {
4284     return NULL;
4285   }
4286 }
4287 
4288 static CharPtr 
4289 GetLocationFromSourceDescriptor 
4290 (SeqDescrPtr  sdp,
4291  ValNodePtr   vnp, 
4292  FilterSetPtr fsp)
4293 {
4294   if (sdp != NULL && sdp->choice == Seq_descr_source)
4295   {
4296     return GetLocationFromSource (sdp->data.ptrvalue, vnp);
4297   }
4298   else
4299   {
4300     return NULL;
4301   }
4302 }
4303 
4304 static CharPtr GetOriginFromSource (BioSourcePtr biop, ValNodePtr vnp)
4305 {
4306   Nlm_EnumFieldAssocPtr eap;
4307   
4308   if (biop == NULL)
4309   {
4310     return NULL;
4311   }
4312   
4313   for (eap = origin_alist;
4314        eap->name != NULL && eap->value != biop->origin;
4315        eap++)
4316   {
4317   }
4318   
4319   if (eap != NULL && eap->name != NULL && !StringHasNoText (eap->name))
4320   {
4321     return StringSave (eap->name);
4322   }
4323   else
4324   {
4325     return NULL;
4326   }  
4327 }
4328 
4329 static CharPtr 
4330 GetOriginFromSourceFeature 
4331 (SeqFeatPtr   sfp,
4332  ValNodePtr   vnp,
4333  FilterSetPtr fsp)
4334 {
4335   if (sfp != NULL && sfp->data.choice == SEQFEAT_BIOSRC)
4336   {
4337     return GetOriginFromSource (sfp->data.value.ptrvalue, vnp);
4338   }
4339   else
4340   {
4341     return NULL;
4342   }
4343 }
4344 
4345 static CharPtr 
4346 GetOriginFromSourceDescriptor 
4347 (SeqDescrPtr  sdp,
4348  ValNodePtr   vnp,
4349  FilterSetPtr fsp)
4350 {
4351   if (sdp != NULL && sdp->choice == Seq_descr_source)
4352   {
4353     return GetOriginFromSource (sdp->data.ptrvalue, vnp);
4354   }
4355   else
4356   {
4357     return NULL;
4358   }
4359 }
4360 
4361 static CharPtr GetStringFromSource (BioSourcePtr biop, ValNodePtr vnp)
4362 {
4363   Nlm_EnumFieldAssocPtr eap;
4364   
4365   if (biop == NULL)
4366   {
4367     return NULL;
4368   }
4369   
4370   for (eap = orgref_textfield_alist;
4371        eap->name != NULL && StringCmp (vnp->data.ptrvalue, eap->name) != 0;
4372        eap++)
4373   {
4374   }
4375   
4376   if (eap != NULL && eap->name != NULL)
4377   {
4378     switch (eap->value)
4379     {
4380       case 1:
4381         if (biop->org != NULL && !StringHasNoText (biop->org->taxname))
4382         {
4383           return StringSave (biop->org->taxname);
4384         }
4385         break;
4386       case 2:
4387         if (biop->org != NULL && !StringHasNoText (biop->org->common))
4388         {
4389           return StringSave (biop->org->common);
4390         }
4391         break;
4392       case 3:
4393         if (biop->org != NULL && biop->org->orgname != NULL
4394             && !StringHasNoText (biop->org->orgname->lineage))
4395         {
4396           return StringSave (biop->org->orgname->lineage);
4397         }
4398         break;
4399       case 4:
4400         if (biop->org != NULL && biop->org->orgname != NULL
4401             && !StringHasNoText (biop->org->orgname->div))
4402         {
4403           return StringSave (biop->org->orgname->div);
4404         }
4405         break;
4406     }
4407   }
4408   return NULL;  
4409 }
4410 
4411 static CharPtr GetStringFromSourceFeature (SeqFeatPtr sfp, ValNodePtr vnp, FilterSetPtr fsp)
4412 {
4413   if (sfp != NULL && sfp->data.choice == SEQFEAT_BIOSRC)
4414   {
4415     return GetStringFromSource (sfp->data.value.ptrvalue, vnp);
4416   }
4417   else
4418   {
4419     return NULL;
4420   }
4421 }
4422 
4423 static CharPtr StringAppend (CharPtr str1, CharPtr str2)
4424 {
4425   CharPtr new_str;
4426   
4427   if (str1 == NULL && str2 == NULL)
4428   {
4429     return NULL;
4430   }
4431   else if (str1 == NULL)
4432   {
4433     return StringSave (str2);
4434   }
4435   else if (str2 == NULL)
4436   {
4437     return StringSave (str1);
4438   }
4439   else
4440   {
4441     new_str = (CharPtr) MemNew ((StringLen (str1) + StringLen (str2) + 3) * sizeof (Char));
4442     if (new_str != NULL)
4443     {
4444       sprintf (new_str, "%s; %s", str1, str2);  
4445     }
4446     return new_str;
4447   }
4448 }
4449 
4450 static CharPtr GetStringFromSourceDescriptor (SeqDescrPtr sdp, ValNodePtr vnp, FilterSetPtr fsp)
4451 {
4452   if (sdp != NULL && sdp->choice == Seq_descr_source)
4453   {
4454     return GetStringFromSource (sdp->data.ptrvalue, vnp);
4455   }
4456   else
4457   {
4458     return NULL;
4459   }
4460 }
4461 
4462 static CharPtr 
4463 GetSourceQualStringFromBioSource 
4464 (BioSourcePtr biop,
4465  ValNodePtr   vnp,
4466  FilterSetPtr fsp)
4467 {
4468   CharPtr            str = NULL, str1 = NULL, str2 = NULL;
4469   SourceQualDescData sqdd;
4470   
4471   if (biop == NULL || vnp == NULL)
4472   {
4473     return NULL;
4474   }
4475   
4476   while (vnp != NULL && str == NULL)
4477   {
4478     if (vnp->choice == 0)
4479     {
4480       str = GetSourceQualQualValueFromBiop (biop, vnp->data.ptrvalue, fsp);   
4481     }
4482     else if (vnp->choice == 1)
4483     {
4484       if (StringCmp (vnp->data.ptrvalue, "Location") == 0)
4485       {
4486         str = GetLocationFromSource (biop, vnp);
4487       }
4488       else if (StringCmp (vnp->data.ptrvalue, "Origin") == 0)
4489       {
4490         str = GetOriginFromSource (biop, vnp);
4491       }
4492       else if (StringCmp (vnp->data.ptrvalue, "All Notes") == 0)
4493       {
4494         sqdd.name = "note";
4495         sqdd.isOrgMod = TRUE;
4496         sqdd.subtype = 255;
4497         str1 = GetSourceQualQualValueFromBiop (biop, &sqdd, fsp);
4498         sqdd.isOrgMod = FALSE;
4499         str2 = GetSourceQualQualValueFromBiop (biop, &sqdd, fsp);
4500         str = StringAppend (str1, str2);
4501         str1 = MemFree (str1);
4502         str2 = MemFree (str2);
4503       }
4504       else
4505       {
4506         str = GetStringFromSource (biop, vnp);
4507       }
4508     }
4509     vnp = vnp->next;
4510   }
4511   return str;
4512 }
4513 
4514 static CharPtr 
4515 GetSourceQualDescrString 
4516 (SeqDescrPtr  sdp,
4517  ValNodePtr   vnp,
4518  FilterSetPtr fsp)
4519 {
4520   if (sdp == NULL || sdp->choice != Seq_descr_source || vnp == NULL)
4521   {
4522     return NULL;
4523   }
4524   return GetSourceQualStringFromBioSource (sdp->data.ptrvalue, vnp, fsp);
4525 }
4526 
4527 static CharPtr 
4528 GetSourceQualFeatureString 
4529 (SeqFeatPtr   sfp,
4530  ValNodePtr   vnp,
4531  FilterSetPtr fsp)
4532 {
4533   if (sfp == NULL || sfp->data.choice != SEQFEAT_BIOSRC || vnp == NULL)
4534   {
4535     return NULL;
4536   }
4537   
4538   return GetSourceQualStringFromBioSource (sfp->data.value.ptrvalue, vnp, fsp);
4539 }
4540 
4541 static void ApplyLocationToBiop (BioSourcePtr biop, ApplyValuePtr avp)
4542 {
4543   if (biop == NULL || avp == NULL || avp->field_list == NULL)
4544   {
4545     return;
4546   }
4547   
4548   if (avp->etp == NULL 
4549       || avp->etp->existing_text_choice == eExistingTextChoiceReplaceOld
4550       || biop->genome == 0)
4551   {
4552     biop->genome = avp->field_list->choice;
4553   }
4554 }
4555 
4556 static void ApplyLocationToSourceFeature (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
4557 {
4558   if (sfp != NULL && sfp->data.choice == SEQFEAT_BIOSRC)
4559   {
4560     ApplyLocationToBiop (sfp->data.value.ptrvalue, userdata);
4561   }
4562 }
4563 
4564 static void ApplyLocationToSourceDescriptor (SeqDescrPtr sdp, Pointer userdata, FilterSetPtr fsp)
4565 {
4566   if (sdp != NULL && sdp->choice == Seq_descr_source)
4567   {
4568     ApplyLocationToBiop (sdp->data.ptrvalue, userdata);
4569   }
4570 }
4571 
4572 static void RemoveLocationFromBiop (BioSourcePtr biop, ApplyValuePtr avp)
4573 {
4574   if (biop == NULL || avp == NULL || avp->field_list == NULL)
4575   {
4576     return;
4577   }
4578   
4579   if (biop->genome == avp->field_list->choice)
4580   {
4581     biop->genome = 0;
4582   }
4583 }
4584 
4585 static void RemoveLocationFromSourceFeature (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
4586 {
4587   if (sfp != NULL && sfp->data.choice == SEQFEAT_BIOSRC)
4588   {
4589     RemoveLocationFromBiop (sfp->data.value.ptrvalue, userdata);
4590   }
4591 }
4592 
4593 static void RemoveLocationFromSourceDescriptor (SeqDescrPtr sdp, Pointer userdata, FilterSetPtr fsp)
4594 {
4595   if (sdp != NULL && sdp->choice == Seq_descr_source)
4596   {
4597     RemoveLocationFromBiop (sdp->data.ptrvalue, userdata);
4598   }
4599 }
4600 
4601 static void ApplyOriginToBiop (BioSourcePtr biop, ApplyValuePtr avp)
4602 {
4603   if (biop == NULL || avp == NULL || avp->field_list == NULL)
4604   {
4605     return;
4606   }
4607   
4608   if (avp->etp == NULL 
4609       || avp->etp->existing_text_choice == eExistingTextChoiceReplaceOld
4610       || biop->origin == 0)
4611   {
4612     biop->origin = avp->field_list->choice;
4613   }
4614 }
4615 
4616 static void ApplyOriginToSourceFeature (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
4617 {
4618   if (sfp != NULL && sfp->data.choice == SEQFEAT_BIOSRC)
4619   {
4620     ApplyOriginToBiop (sfp->data.value.ptrvalue, userdata);
4621   }
4622 }
4623 
4624 static void ApplyOriginToSourceDescriptor (SeqDescrPtr sdp, Pointer userdata, FilterSetPtr fsp)
4625 {
4626   if (sdp != NULL && sdp->choice == Seq_descr_source)
4627   {
4628     ApplyOriginToBiop (sdp->data.ptrvalue, userdata);
4629   }
4630 }
4631 
4632 static void RemoveOriginFromBiop (BioSourcePtr biop, ApplyValuePtr avp)
4633 {
4634   if (biop == NULL || avp == NULL || avp->field_list == NULL)
4635   {
4636     return;
4637   }
4638   
4639   if (biop->origin == avp->field_list->choice)
4640   {
4641     biop->origin = 0;
4642   }
4643 }
4644 
4645 static void RemoveOriginFromSourceFeature (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
4646 {
4647   if (sfp != NULL && sfp->data.choice == SEQFEAT_BIOSRC)
4648   {
4649     RemoveOriginFromBiop (sfp->data.value.ptrvalue, userdata);
4650   }
4651 }
4652 
4653 static void RemoveOriginFromSourceDescriptor (SeqDescrPtr sdp, Pointer userdata, FilterSetPtr fsp)
4654 {
4655   if (sdp != NULL && sdp->choice == Seq_descr_source)
4656   {
4657     RemoveOriginFromBiop (sdp->data.ptrvalue, userdata);
4658   }
4659 }
4660 
4661 static void ApplyStringToSource (BioSourcePtr biop, Pointer userdata)
4662 {
4663   ApplyValuePtr         avp;
4664 
4665   if (biop == NULL || userdata == NULL)
4666   {
4667     return;
4668   }
4669   
4670   avp = (ApplyValuePtr) userdata;
4671   if (avp == NULL || avp->field_list == NULL)
4672   {
4673     return;
4674   }
4675 
4676   if (StringHasNoText (avp->text_to_replace))
4677   {
4678     if (biop->org == NULL)
4679     {
4680       biop->org = OrgRefNew();
4681     }
4682     if (biop->org->orgname == NULL 
4683         && (avp->field_list->choice == 3
4684             || avp->field_list->choice == 4))
4685     {
4686       biop->org->orgname = OrgNameNew ();
4687     }
4688   }
4689   
4690   switch (avp->field_list->choice)
4691   {
4692     case 1:
4693       biop->org->taxname = HandleApplyValue (biop->org->taxname, avp);
4694       break;
4695     case 2:
4696       biop->org->common = HandleApplyValue (biop->org->common, avp);
4697       break;
4698     case 3:
4699       biop->org->orgname->lineage = HandleApplyValue (biop->org->orgname->lineage, avp);
4700       break;
4701     case 4:
4702       biop->org->orgname->div = HandleApplyValue (biop->org->orgname->div, avp);
4703       break;
4704   }  
4705 }
4706 
4707 static void ApplyStringToSourceFeature (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
4708 {
4709   if (sfp != NULL && sfp->data.choice == SEQFEAT_BIOSRC)
4710   {
4711     ApplyStringToSource (sfp->data.value.ptrvalue, userdata);
4712   }
4713 }
4714 
4715 static void ApplyStringToSourceDescriptor (SeqDescrPtr sdp, Pointer userdata, FilterSetPtr fsp)
4716 {
4717   if (sdp != NULL && sdp->choice == Seq_descr_source)
4718   {
4719     ApplyStringToSource (sdp->data.ptrvalue, userdata);
4720   }
4721 }
4722 
4723 static void RemoveStringFromSource (BioSourcePtr biop, Pointer userdata)
4724 {
4725   ApplyValuePtr avp;
4726   
4727   if (biop == NULL || biop->org == NULL || userdata == NULL)
4728   {
4729     return;
4730   }
4731   
4732   avp = (ApplyValuePtr) userdata;
4733   if (avp == NULL || avp->field_list == NULL)
4734   {
4735     return;
4736   }
4737   
4738   switch (avp->field_list->choice)
4739   {
4740     case 1:
4741       biop->org->taxname = MemFree (biop->org->taxname);
4742       break;
4743     case 2:
4744       biop->org->common = MemFree (biop->org->common);
4745       break;
4746     case 3:
4747       if (biop->org->orgname != NULL)
4748       {
4749         biop->org->orgname->lineage = MemFree (biop->org->orgname->lineage);
4750       }
4751       break;
4752     case 4:
4753       if (biop->org->orgname != NULL)
4754       {
4755         biop->org->orgname->div = MemFree (biop->org->orgname->div);
4756       }
4757       break;
4758   }   
4759 }
4760 
4761 static void RemoveStringFromSourceFeature (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
4762 {
4763   if (sfp != NULL && sfp->data.choice == SEQFEAT_BIOSRC)
4764   {
4765     RemoveStringFromSource (sfp->data.value.ptrvalue, userdata);
4766   }
4767 }
4768 
4769 static void RemoveStringFromSourceDescriptor (SeqDescrPtr sdp, Pointer userdata, FilterSetPtr fsp)
4770 {
4771   if (sdp != NULL && sdp->choice == Seq_descr_source)
4772   {
4773     RemoveStringFromSource (sdp->data.ptrvalue, userdata);
4774   }
4775 }
4776 
4777 static void RemoveSourceQualFromBioSource (BioSourcePtr biop, Pointer userdata, FilterSetPtr fsp);
4778 
4779 static CharPtr RemoveSubfield (CharPtr orig, Uint1 subfield)
4780 {
4781   CharPtr cp, cp2;
4782   Int4    num_colons = 0;
4783   CharPtr new_val;
4784 
4785   cp = StringChr (orig, ':');
4786   while (cp != NULL) {
4787     num_colons ++;
4788     cp = StringChr (cp + 1, ':');
4789   }
4790   new_val = orig;
4791 
4792   if (subfield == 0) {
4793     new_val = MemFree (new_val);
4794   } else if (subfield == 1) {
4795     if (num_colons == 0) {
4796       /* no INST, just specID, nothing to remove */
4797     } else if (num_colons == 1) {
4798       cp = StringChr (orig, ':');
4799       new_val = StringSave (cp + 1);
4800       orig = MemFree (orig);
4801     } else {
4802       cp = StringChr (orig, ':');
4803       new_val = StringSave (cp);
4804       orig = MemFree (orig);
4805     }
4806   } else if (subfield == 2) {
4807     if (num_colons == 0 || num_colons == 1) {
4808       /* no COLL, nothing to remove */
4809     } else {
4810       cp = StringChr (orig, ':');
4811       cp2 = StringChr (cp + 1, ':');
4812       new_val = (CharPtr) MemNew (sizeof (Char) * (cp - orig + StringLen (cp2) + 1));
4813       StringNCpy (new_val, orig, cp - orig);
4814       StringCat (new_val, cp2);
4815       orig = MemFree (orig);
4816       if (StringCmp (new_val, ":") == 0) {
4817         new_val = MemFree (new_val);
4818       }
4819     }
4820   } else {
4821     /* specid */
4822     if (num_colons == 0) {
4823       new_val = MemFree (new_val);
4824     } else {
4825       cp = StringRChr (new_val, ':');
4826       *(cp + 1) = 0;
4827     }
4828   }
4829   return new_val;
4830 }
4831 
4832 
4833 static CharPtr ApplyToSubfield (CharPtr orig, ApplyValuePtr avp, Uint1 subfield)
4834 {
4835   CharPtr cp, cp2;
4836   Int4    num_colons = 0, len;
4837   CharPtr new_field, new_val;
4838 
4839   cp = StringChr (orig, ':');
4840   while (cp != NULL) {
4841     num_colons ++;
4842     cp = StringChr (cp + 1, ':');
4843   }
4844 
4845   new_val = orig;
4846   if (subfield == 0) {
4847     /* whole field */
4848     new_val = HandleApplyValue (orig, avp);
4849   } else if (subfield == 1) {
4850     /* INST */
4851     if (num_colons == 0) {
4852       /* all we have is the specID, we are adding INST */
4853       new_field = HandleApplyValue (NULL, avp);
4854       if (!StringHasNoText (new_field)) {
4855         new_val = (CharPtr) MemNew (sizeof (Char) * (StringLen (new_field) + StringLen (orig) + 2));
4856         sprintf (new_val, "%s:%s", new_field, orig == NULL ? "" : orig);
4857         orig = MemFree (orig);
4858       } else {
4859         new_val = orig;
4860       }
4861       new_field = MemFree (new_field);
4862     } else {
4863       cp = StringChr (orig, ':');
4864       len = cp - orig + 1;
4865       new_field = (CharPtr) MemNew (sizeof (Char) * len);
4866       StringNCpy (new_field, orig, len - 1);
4867       new_field[len - 1] = 0;
4868       new_field = HandleApplyValue (new_field, avp);
4869       new_val = (CharPtr) MemNew (sizeof (Char) * (StringLen (new_field) + StringLen (cp) + 1));
4870       sprintf (new_val, "%s%s", new_field == NULL ? "" : new_field, cp);
4871       orig = MemFree (orig);
4872       new_field = MemFree (new_field);
4873     }
4874   } else if (subfield == 2) {
4875     /* COLL */
4876     if (num_colons == 0) {
4877       /* add blank INST, then COLL, then existing specID */
4878       new_field = HandleApplyValue (NULL, avp);
4879       if (!StringHasNoText (new_field)) {
4880         new_val = (CharPtr) MemNew (sizeof (Char) * (3 + StringLen (new_field) +  StringLen (orig)));
4881         sprintf (new_val, ":%s:%s", new_field, orig == NULL ? "" : orig);
4882         orig = MemFree (orig);
4883       } else {
4884         new_val = orig;
4885       }
4886       new_field = MemFree (new_field);
4887     } else if (num_colons == 1) {
4888       /* have INST and specID */
4889       new_field = HandleApplyValue (NULL, avp);
4890       if (!StringHasNoText (new_field)) {
4891         new_val = (CharPtr) MemNew (sizeof (Char) * (3 + StringLen (new_field) +  StringLen (orig)));
4892         cp = StringChr (orig, ':');
4893         len = cp - orig;
4894         StringNCpy (new_val, orig, len);
4895         StringCat (new_val, ":");
4896         StringCat (new_val, new_field);
4897         StringCat (new_val, cp);
4898         orig = MemFree (orig);
4899       } else {
4900         new_val = orig;
4901       }
4902       new_field = MemFree (new_field);
4903     } else {
4904       cp = StringChr (orig, ':');
4905       cp2 = StringChr (cp + 1, ':');
4906       len = cp2 - cp;
4907       new_field = (CharPtr) MemNew (sizeof (Char) * len);
4908       StringNCpy (new_field, cp + 1, len - 1);
4909       new_field[len - 1] = 0;
4910       new_field = HandleApplyValue (new_field, avp);
4911       new_val = (CharPtr) MemNew (sizeof (Char) * (cp - orig + 1 + StringLen (new_field) + StringLen (cp2) + 1));
4912       StringNCpy (new_val, orig, cp - orig + 1);
4913       StringCat (new_val, new_field);
4914       StringCat (new_val, cp2);
4915       orig = MemFree (orig);
4916       new_field = MemFree (new_field);
4917     }
4918   } else {
4919     /* specid */
4920     if (num_colons == 0) {
4921       new_val = HandleApplyValue (orig, avp);
4922     } else {
4923       cp = StringRChr (orig, ':');
4924       new_field = StringSave (cp + 1);
4925       new_field = HandleApplyValue (new_field, avp);
4926       new_val = (CharPtr) MemNew (sizeof (Char) + (cp - orig + 1 + StringLen (new_field) + 1));
4927       StringNCpy (new_val, orig, cp - orig + 1);
4928       StringCat (new_val, new_field);
4929       orig = MemFree (orig);
4930       new_field = MemFree (new_field);
4931     }
4932   }
4933   return new_val;
4934 }
4935 
4936 
4937 static void ApplySourceQualBioSourceCallback (BioSourcePtr biop, Pointer userdata, FilterSetPtr fsp)
4938 {
4939   ApplyValuePtr         avp;
4940   SourceQualDescPtr     sqdp;
4941   OrgModPtr             mod = NULL, last_mod = NULL;
4942   SubSourcePtr          ssp = NULL, last_ssp = NULL;
4943   Boolean               found = FALSE;
4944   Boolean               is_nontext;
4945   
4946   if (biop == NULL || userdata == NULL)
4947   {
4948     return;
4949   }
4950   
4951   avp = (ApplyValuePtr) userdata;
4952   if (avp->field_list == NULL || avp->field_list->data.ptrvalue == NULL)
4953   {
4954     return;
4955   }
4956   
4957   /* don't apply to All Notes */
4958   if (avp->field_list->choice != 0)
4959   {
4960     return;
4961   }
4962   
4963   sqdp = (SourceQualDescPtr) avp->field_list->data.ptrvalue;
4964   
4965   is_nontext = IsNonTextModifier (sqdp->name);
4966   if (is_nontext && StringHasNoText (avp->new_text))
4967   {
4968     RemoveSourceQualFromBioSource (biop, avp, fsp);
4969     return;
4970   }
4971   
4972   if (!StringHasNoText (avp->text_to_replace))
4973   {
4974     found = TRUE;
4975   }
4976   
4977   if (sqdp->isOrgMod)
4978   {
4979     if (biop->org == NULL)
4980     {
4981       biop->org = OrgRefNew ();
4982     }
4983     if (biop->org != NULL && biop->org->orgname == NULL)
4984     {
4985       biop->org->orgname = OrgNameNew ();
4986     }
4987     if (biop->org != NULL && biop->org->orgname != NULL)
4988     {
4989       mod = biop->org->orgname->mod;
4990       while (mod != NULL)
4991       {
4992         if (mod->subtype == sqdp->subtype)
4993         {
4994           if (!is_nontext)
4995           {
4996             mod->subname = ApplyToSubfield (mod->subname, avp, sqdp->subfield);
4997           }
4998           found = TRUE;
4999         }
5000         last_mod = mod;
5001         mod = mod->next;
5002       }
5003       if (!found)
5004       {
5005         mod = OrgModNew ();
5006         mod->subtype = sqdp->subtype;
5007         if (is_nontext)
5008         {
5009           mod->subname = StringSave ("");
5010         }
5011         else
5012         {
5013           mod->subname = ApplyToSubfield (mod->subname, avp, sqdp->subfield);
5014         }
5015         if (last_mod == NULL)
5016         {
5017           biop->org->orgname->mod = mod;
5018         }
5019         else
5020         {
5021           last_mod->next = mod;
5022         }
5023       }
5024     }
5025   }
5026   else
5027   {
5028     ssp = biop->subtype;
5029     while (ssp != NULL)
5030     {
5031       if (ssp->subtype == sqdp->subtype)
5032       {
5033         if (! is_nontext)
5034         {
5035           ssp->name = ApplyToSubfield (ssp->name, avp, sqdp->subfield);
5036         }
5037         found = TRUE;
5038       }
5039       last_ssp = ssp;
5040       ssp = ssp->next;
5041     }
5042     if (!found)
5043     {
5044       ssp = SubSourceNew ();
5045       ssp->subtype = sqdp->subtype;
5046       if (is_nontext)
5047       {
5048         ssp->name = StringSave ("");
5049       }
5050       else
5051       {
5052         ssp->name = ApplyToSubfield (ssp->name, avp, sqdp->subfield);
5053       }
5054       if (last_ssp == NULL)
5055       {
5056         biop->subtype = ssp;
5057       }
5058       else
5059       {
5060         last_ssp->next = ssp;
5061       }
5062     }
5063   }
5064 }
5065 
5066 static void ApplySourceQualFeatureCallback (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
5067 {
5068   if (sfp == NULL || sfp->data.choice != SEQFEAT_BIOSRC || userdata == NULL)
5069   {
5070     return;
5071   }
5072   ApplySourceQualBioSourceCallback (sfp->data.value.ptrvalue, userdata, fsp);
5073 }
5074 
5075 static void ApplySourceQualDescriptorCallback (SeqDescrPtr sdp, Pointer userdata, FilterSetPtr fsp)
5076 {
5077   if (sdp == NULL || sdp->choice != Seq_descr_source || userdata == NULL)
5078   {
5079     return;
5080   }
5081   ApplySourceQualBioSourceCallback (sdp->data.ptrvalue, userdata, fsp);
5082 }
5083 
5084 static void RemoveOrgModFromBioSource (BioSourcePtr biop, Uint1 subtype, Uint1 subfield, FilterSetPtr fsp)
5085 {
5086   OrgModPtr mod = NULL, prev_mod = NULL, next_mod;
5087   
5088   if (biop != NULL && biop->org != NULL && biop->org->orgname != NULL)
5089   {
5090     mod = biop->org->orgname->mod;
5091     while (mod != NULL)
5092     {
5093       next_mod = mod->next;
5094       if (mod->subtype == subtype
5095           && OrgModSpecialMatch (mod, fsp))
5096       {
5097         mod->subname = RemoveSubfield (mod->subname, subfield);
5098         if (StringHasNoText (mod->subname)) {
5099           if (prev_mod == NULL)
5100           {
5101             biop->org->orgname->mod = mod->next;
5102           }
5103           else
5104           {
5105             prev_mod->next = mod->next;
5106           }
5107           mod->next = NULL;
5108           OrgModFree (mod);
5109         } else {
5110           prev_mod = mod;
5111         }
5112       }
5113       else
5114       {
5115         prev_mod = mod;
5116       }
5117       mod = next_mod;
5118     }
5119   }
5120 }
5121 
5122 static void RemoveSubSourceFromBioSource (BioSourcePtr biop, Uint2 subtype, Uint1 subfield, FilterSetPtr fsp)
5123 {
5124   SubSourcePtr ssp = NULL, prev_ssp = NULL, next_ssp;
5125 
5126   if (biop != NULL)
5127   {
5128     ssp = biop->subtype;
5129     while (ssp != NULL)
5130     { 
5131       next_ssp = ssp->next;
5132       if (ssp->subtype == subtype
5133           && SubSrcSpecialMatch (ssp, fsp))
5134       {
5135         ssp->name = RemoveSubfield (ssp->name, subfield);
5136         if (StringHasNoText (ssp->name)) {
5137           if (prev_ssp == NULL)
5138           {
5139             biop->subtype = ssp->next;
5140           }
5141           else
5142           {
5143             prev_ssp->next = ssp->next;
5144           }
5145           ssp->next = NULL;
5146           SubSourceFree (ssp);
5147         } else {
5148           prev_ssp = ssp;
5149         }
5150       }
5151       else
5152       {
5153         prev_ssp = ssp;
5154       }
5155       ssp = next_ssp;
5156     }
5157   }
5158 }
5159 
5160 static void RemoveSourceQualFromBioSource (BioSourcePtr biop, Pointer userdata, FilterSetPtr fsp)
5161 {
5162   ApplyValuePtr         avp;
5163   SourceQualDescPtr     sqdp;
5164   
5165   if (biop == NULL || userdata == NULL)
5166   {
5167     return;
5168   }
5169   
5170   avp = (ApplyValuePtr) userdata;
5171   if (avp->field_list == NULL || avp->field_list->data.ptrvalue == NULL)
5172   {
5173     return;
5174   }
5175   if (avp->field_list->choice == 0)
5176   {
5177     sqdp = (SourceQualDescPtr) avp->field_list->data.ptrvalue;
5178     if (sqdp->isOrgMod)
5179     {
5180       RemoveOrgModFromBioSource (biop, sqdp->subtype, sqdp->subfield, fsp);
5181     }
5182     else
5183     {
5184       RemoveSubSourceFromBioSource (biop, sqdp->subtype, sqdp->subfield, fsp);
5185     }
5186   }
5187   else if (avp->field_list->choice == 1 
5188            && StringCmp (avp->field_list->data.ptrvalue, "All Notes") == 0)
5189   {
5190     RemoveOrgModFromBioSource (biop, 255, 0, fsp);
5191     RemoveSubSourceFromBioSource (biop, 255, 0, fsp);
5192   }
5193 }
5194 
5195 static void RemoveSourceQualFromSourceFeature (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
5196 {
5197   if (sfp == NULL || sfp->data.choice != SEQFEAT_BIOSRC || userdata == NULL)
5198   {
5199     return;
5200   }
5201   RemoveSourceQualFromBioSource (sfp->data.value.ptrvalue, userdata, fsp);
5202 }
5203 
5204 static void RemoveSourceQualFromSourceDescriptor (SeqDescrPtr sdp, Pointer userdata, FilterSetPtr fsp)
5205 {
5206   if (sdp == NULL || sdp->choice != Seq_descr_source || userdata == NULL)
5207   {
5208     return;
5209   }
5210   RemoveSourceQualFromBioSource (sdp->data.ptrvalue, userdata, fsp);
5211 }
5212 
5213 static DialoG SourceLocationSelectionDialogEx 
5214 (GrouP h,
5215  Boolean                  allow_multi,
5216  Boolean                  allow_discontinued,
5217  Nlm_ChangeNotifyProc     change_notify,
5218  Pointer                  change_userdata)
5219 
5220 {
5221   DialoG     dlg;
5222   ValNodePtr choice_list = NULL;
5223   Nlm_EnumFieldAssocPtr eap = biosource_genome_alistX;
5224   
5225   if (eap == NULL)
5226   {
5227     return NULL;
5228   }
5229 
5230   while (eap->name != NULL)
5231   {
5232     if (!StringHasNoText (eap->name) 
5233         && (allow_discontinued ||
5234             (StringCmp (eap->name, "Insertion Sequence") != 0
5235              && StringCmp (eap->name, "Transposon") != 0)))
5236     {
5237       ValNodeAddPointer (&choice_list, eap->value, StringSave (eap->name));
5238     }
5239     eap++;
5240   }
5241   
5242   /* note - the ValNodeSelectionDialog will free the qual_choice_list
5243    * when done */                                            
5244   dlg = ValNodeSelectionDialog (h, choice_list, TALL_SELECTION_LIST,
5245                                 ValNodeStringName,
5246                                 ValNodeSimpleDataFree, ValNodeStringCopy,
5247                                 ValNodeChoiceMatch, "Location",
5248                                 change_notify, change_userdata, allow_multi);
5249 
5250   return dlg;
5251 }
5252 
5253 
5254 static DialoG SourceLocationSelectionDialog
5255 (GrouP h,
5256  Boolean                  allow_multi,
5257  Nlm_ChangeNotifyProc     change_notify,
5258  Pointer                  change_userdata)
5259 {
5260   return SourceLocationSelectionDialogEx (h, allow_multi, FALSE,
5261                                           change_notify, change_userdata);
5262 }
5263 
5264 
5265 static DialoG SourceLocationDiscSelectionDialog
5266 (GrouP h,
5267  Boolean                  allow_multi,
5268  Nlm_ChangeNotifyProc     change_notify,
5269  Pointer                  change_userdata)
5270 {
5271   return SourceLocationSelectionDialogEx (h, allow_multi, TRUE,
5272                                           change_notify, change_userdata);
5273 }
5274 
5275 
5276 static DialoG SourceOriginSelectionDialog
5277 (GrouP h,
5278  Boolean                  allow_multi,
5279  Nlm_ChangeNotifyProc     change_notify,
5280  Pointer                  change_userdata)
5281 
5282 {
5283   return EnumAssocSelectionDialog (h, origin_alist, "Origin",
5284                                    allow_multi, change_notify, change_userdata);
5285 }
5286 
5287 static DialoG SourceStringSelectionDialog
5288 (GrouP h,
5289  Boolean                  allow_multi,
5290  Nlm_ChangeNotifyProc     change_notify,
5291  Pointer                  change_userdata)
5292 
5293 {
5294   return EnumAssocSelectionDialog (h, orgref_textfield_alist, "string",
5295                                    allow_multi, change_notify, change_userdata);
5296 }
5297 
5298 
5299 static CharPtr 
5300 GetStringFromStringDescriptor 
5301 (SeqDescrPtr  sdp,
5302  ValNodePtr   vnp,
5303  FilterSetPtr fsp)
5304 {
5305   if (sdp == NULL || vnp == NULL || sdp->choice != vnp->data.intvalue)
5306   {
5307     return NULL;
5308   }
5309   return StringSave (sdp->data.ptrvalue);
5310 }
5311 
5312 static void SetStringInStringDescriptor (SeqDescrPtr sdp, ValNodePtr vnp, ApplyValuePtr avp)
5313 {
5314   if (sdp == NULL || vnp == NULL || sdp->choice != vnp->data.intvalue)
5315   {
5316     return;
5317   }
5318   sdp->data.ptrvalue = HandleApplyValue (sdp->data.ptrvalue, avp);
5319 }
5320 
5321 static void ApplyTitleDescriptorCallback (SeqDescrPtr sdp, Pointer userdata, FilterSetPtr fsp)
5322 {
5323   ApplyValuePtr avp;
5324   ValNode       vn;
5325   
5326   if (sdp == NULL || sdp->choice != Seq_descr_title || userdata == NULL)
5327   {
5328     return;
5329   }
5330   
5331   avp = (ApplyValuePtr) userdata;
5332   
5333   vn.data.intvalue = Seq_descr_title;
5334   vn.next = NULL;
5335   
5336   SetStringInStringDescriptor (sdp, &vn, avp);
5337   
5338 }
5339 
5340 static DialoG GBQualSelectionDialog 
5341 (GrouP                    h,
5342  Boolean                  allow_multi,
5343  Nlm_ChangeNotifyProc     change_notify,
5344  Pointer                  change_userdata)
5345 
5346 {
5347   DialoG                    dlg;
5348   ValNodePtr            choice_name_list = NULL;
5349   Int4                      i;
5350      
5351   for (i = 0; i < NumEditQualifiers; i++)
5352   {
5353     ValNodeAddPointer (&choice_name_list, 0, EditQualifierList[i].name);
5354   }
5355 
5356   dlg = SelectionDialog (h, change_notify, change_userdata, 
5357                          allow_multi, "genbank qualifier",
5358                          choice_name_list, TALL_SELECTION_LIST);
5359   ValNodeFree (choice_name_list); 
5360   return dlg;
5361 }
5362 
5363 static Int4 GetDbtagStringLen (DbtagPtr db_tag)
5364 {
5365   Int4 len;
5366   
5367   if (db_tag == NULL)
5368   {
5369     return 0;
5370   }
5371   
5372   len = StringLen (db_tag->db) + 2;
5373   if (db_tag->tag != NULL)
5374   {
5375     if (db_tag->tag->str != NULL)
5376     {
5377       len += StringLen (db_tag->tag->str);
5378     }
5379     else
5380     {
5381       len += 10;
5382     }
5383   }
5384   return len;
5385 }
5386 
5387 static CharPtr GetDbtagString (DbtagPtr db_tag)
5388 {
5389   Int4    len;
5390   CharPtr str;
5391   
5392   if (db_tag == NULL)
5393   {
5394     return NULL;
5395   }
5396   
5397   len = GetDbtagStringLen (db_tag);
5398   if (len == 0)
5399   {
5400     return NULL;
5401   }
5402   
5403   str = (CharPtr) MemNew (len * sizeof (Char));
5404   if (str != NULL)
5405   {
5406     StringCpy (str, db_tag->db);
5407     StringCat (str, ":");
5408     if (db_tag->tag != NULL)
5409     {
5410       if (db_tag->tag->str != NULL)
5411       {
5412         StringCat (str, db_tag->tag->str);
5413       }
5414       else
5415       {
5416         sprintf (str + StringLen (str), "%d", db_tag->tag->id);
5417       }
5418     }
5419   }
5420   return str;
5421 }
5422 
5423 static CharPtr GetDbxrefString (SeqFeatPtr sfp)
5424 {
5425   ValNodePtr vnp;
5426   Int4       len = 0;
5427   CharPtr    str = NULL, cp;
5428   
5429   if (sfp == NULL || sfp->dbxref == NULL)
5430   {
5431     return NULL;
5432   }
5433   
5434   for (vnp = sfp->dbxref; vnp != NULL; vnp = vnp->next)
5435   {
5436     len += GetDbtagStringLen (vnp->data.ptrvalue) + 1;
5437   }
5438   
5439   if (len == 0)
5440   {
5441     return NULL;
5442   }
5443   
5444   str = (CharPtr) MemNew ((len + 1) * sizeof (Char));
5445   if (str != NULL)
5446   {
5447     for (vnp = sfp->dbxref; vnp != NULL; vnp = vnp->next)
5448     {
5449       cp = GetDbtagString (vnp->data.ptrvalue);
5450       if (cp != NULL)
5451       {
5452         StringCat (str, cp);
5453         StringCat (str, ";");
5454       }
5455     }
5456   }
5457   if (StringLen (str) >1)
5458   {
5459     /* remove final semicolon */
5460     str [StringLen (str) - 2] = 0;
5461   }
5462   return str;
5463 }
5464 
5465 static CharPtr GetGBQualString (SeqFeatPtr sfp, ValNodePtr vnp, FilterSetPtr fsp)
5466 {
5467   GBQualPtr  gbqual;
5468   CharPtr    str = NULL;
5469   Int4       field_choice;
5470   RnaRefPtr  rrp;
5471   GeneRefPtr grp;
5472   
5473   if (sfp == NULL)
5474   {
5475     return NULL;
5476   }
5477   while (vnp != NULL && str == NULL)
5478   {
5479     field_choice = vnp->data.intvalue;
5480     if (StringICmp (EditQualifierList[field_choice - 1].name, "note") == 0)
5481     {
5482       if (!StringHasNoText (sfp->comment))
5483       {
5484         str = StringSave (sfp->comment);
5485       }
5486     }
5487     else if (StringICmp (EditQualifierList[field_choice - 1].name, "exception") == 0)
5488     {
5489       if (!StringHasNoText (sfp->except_text))
5490       {
5491         str = StringSave (sfp->except_text);
5492       }
5493     }
5494     else if (StringICmp (EditQualifierList[field_choice - 1].name, "product") == 0
5495              && sfp->data.choice == SEQFEAT_RNA)
5496     {
5497       rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
5498       if (rrp != NULL && rrp->ext.choice == 1
5499           && !StringHasNoText (rrp->ext.value.ptrvalue))
5500       {
5501         str = StringSave (rrp->ext.value.ptrvalue);        
5502       }
5503     }
5504     else if (StringICmp (EditQualifierList [field_choice - 1].name, "map") == 0
5505              && sfp->data.choice == SEQFEAT_GENE)
5506     {
5507       grp = (GeneRefPtr) sfp->data.value.ptrvalue;
5508       if (grp != NULL && !StringHasNoText (grp->maploc))
5509       {
5510         str = StringSave (grp->maploc);
5511       }
5512     }
5513     else if (StringICmp (EditQualifierList [field_choice - 1].name, "db_xref") == 0)
5514     {
5515         str = GetDbxrefString (sfp);
5516     }
5517     else if (StringICmp (EditQualifierList [field_choice - 1].name, "evidence") == 0)
5518     {
5519       if (sfp->exp_ev == 1)
5520       {
5521         str = StringSave ("experimental");
5522       }
5523       else if (sfp->exp_ev == 2)
5524       {
5525         str = StringSave ("non-experimental");
5526       }
5527     }
5528     else
5529     {
5530       gbqual = sfp->qual;
5531       while (gbqual != NULL && str == NULL)
5532       {
5533         if (field_choice > 0 && field_choice < NumEditQualifiers + 1
5534             && StringCmp (gbqual->qual, EditQualifierList[field_choice - 1].name) == 0
5535             && !StringHasNoText (gbqual->val))
5536         {
5537           str = StringSave (gbqual->val);
5538         }
5539         gbqual = gbqual->next;
5540       }
5541     }
5542     vnp = vnp->next;
5543   }
5544   return str;
5545 }
5546 
5547 static DbtagPtr DbtagFromString (CharPtr str)
5548 {
5549   DbtagPtr db_tag;
5550   CharPtr  cp, idp;
5551   Boolean  use_id = TRUE;
5552   
5553   if (StringHasNoText (str))
5554   {
5555     return NULL;
5556   }
5557   
5558   cp = StringChr (str, ':');
5559   if (cp == NULL)
5560   {
5561     return NULL;
5562   }
5563   
5564   db_tag = DbtagNew ();
5565   if (db_tag != NULL)
5566   {
5567     db_tag->db = (CharPtr) MemNew ((cp - str + 1) * sizeof (Char));
5568     StringNCpy (db_tag->db, str, cp - str);
5569     db_tag->db [cp - str] = 0;
5570     
5571     idp = cp + 1;
5572     while (*idp != 0 && use_id)
5573     {
5574       if (!isdigit (*idp))
5575       {
5576         use_id = FALSE;
5577       }
5578       idp++;
5579     }
5580     db_tag->tag = ObjectIdNew ();
5581     if (use_id)
5582     {
5583       db_tag->tag->id = atoi (cp + 1);
5584       db_tag->tag->str = NULL;
5585     }
5586     else
5587     {
5588       db_tag->tag->id = 0;
5589       db_tag->tag->str = StringSave (cp + 1);
5590     }
5591   }
5592   return db_tag;
5593 }
5594 
5595 static void HandleApplyValueForObjectID (ObjectIdPtr oip, ApplyValuePtr avp)
5596 {
5597   CharPtr tmp_str = NULL;
5598   CharPtr cp;
5599   Boolean is_num = TRUE;
5600   
5601   if (oip == NULL || avp == NULL)
5602   {
5603     return;
5604   }
5605   
5606   if (oip->str == NULL)
5607   {
5608     tmp_str = (CharPtr) MemNew (10 * sizeof (Char));
5609     sprintf (tmp_str, "%d", oip->id);
5610     
5611   }
5612   else
5613   {
5614     tmp_str = oip->str;
5615     oip->str = NULL;
5616   }
5617   tmp_str = HandleApplyValue (tmp_str, avp);
5618   
5619   for (cp = tmp_str; cp != NULL && *cp != 0 && is_num; cp++)
5620   {
5621     if (!isdigit (*cp))
5622     {
5623       is_num = FALSE;
5624     }
5625   }
5626   if (is_num)
5627   {
5628     oip->id = atoi (tmp_str);
5629     tmp_str = MemFree (tmp_str);
5630   }
5631   else
5632   {
5633     oip->str = tmp_str;
5634   }
5635 }
5636 
5637 static void EditDbxref (SeqFeatPtr sfp, ApplyValuePtr avp, FilterSetPtr fsp)
5638 {
5639   ValNodePtr vnp;
5640   DbtagPtr   db_tag_new, db_tag_to_replace, db_tag;
5641   CharPtr    cp;
5642   
5643   if (sfp == NULL || avp == NULL)
5644   {
5645     return;
5646   }
5647   
5648   db_tag_new = DbtagFromString (avp->new_text);
5649   db_tag_to_replace = DbtagFromString (avp->text_to_replace);
5650   
5651   if (db_tag_new == NULL && db_tag_to_replace == NULL)
5652   {
5653     for (vnp = sfp->dbxref; vnp != NULL; vnp = vnp->next)
5654     {
5655       db_tag = (DbtagPtr) vnp->data.ptrvalue;
5656       if (db_tag != NULL)
5657       {
5658         db_tag->db = HandleApplyValue (db_tag->db, avp);
5659         HandleApplyValueForObjectID (db_tag->tag, avp);
5660       }
5661     }
5662   }
5663   else if (db_tag_new != NULL && db_tag_to_replace != NULL)
5664   {
5665     for (vnp = sfp->dbxref; vnp != NULL; vnp = vnp->next)
5666     {
5667       db_tag = (DbtagPtr) vnp->data.ptrvalue;
5668       if (db_tag != NULL)
5669       {
5670         cp = GetDbtagString (db_tag);
5671         cp = HandleApplyValue (cp, avp);
5672         db_tag = DbtagFree (db_tag);
5673         db_tag = DbtagFromString (cp);
5674         vnp->data.ptrvalue = db_tag;
5675         cp = MemFree (cp);
5676       }
5677     }
5678   }  
5679 }
5680 
5681 static ValNodePtr RemoveDbxrefList (ValNodePtr vnp)
5682 
5683 {
5684   ValNodePtr  next;
5685 
5686   while (vnp != NULL) {
5687     next = vnp->next;
5688     DbtagFree ((DbtagPtr) vnp->data.ptrvalue);
5689     MemFree (vnp);
5690     vnp = next;
5691   }
5692   return NULL;
5693 }
5694 
5695 static void SetDbxrefFromString (SeqFeatPtr sfp, ApplyValuePtr avp, FilterSetPtr fsp)
5696 {
5697   DbtagPtr new_tag;
5698   
5699   if (sfp == NULL || avp == NULL)
5700   {
5701     return;
5702   }
5703   
5704   if (StringHasNoText (avp->text_to_replace))
5705   {
5706     /* this is an apply */
5707     if (avp->etp != NULL)
5708     {
5709       if (avp->etp->existing_text_choice == eExistingTextChoiceLeaveOld
5710           && sfp->dbxref != NULL)
5711       {
5712         return;
5713       }
5714       else if (avp->etp->existing_text_choice == eExistingTextChoiceReplaceOld)
5715       {
5716         sfp->dbxref = RemoveDbxrefList (sfp->dbxref);
5717       }
5718     }
5719     
5720     new_tag = DbtagFromString (avp->new_text);
5721     if (new_tag != NULL)
5722     {
5723       ValNodeAddPointer (&(sfp->dbxref), 0, new_tag);
5724     }
5725   }
5726   else
5727   {
5728     EditDbxref (sfp, avp, fsp);
5729   }
5730   
5731 }
5732 
5733 static void SetRNAProduct (SeqFeatPtr sfp, ApplyValuePtr avp);
5734 
5735 static void SetGBQualString (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
5736 {
5737   GBQualPtr     gbqual, gbqual_last = NULL;
5738   ApplyValuePtr avp;
5739   Boolean       found = FALSE;
5740   GeneRefPtr    grp;
5741   
5742   if (sfp == NULL || userdata == NULL)
5743   {
5744     return;
5745   }
5746   avp = (ApplyValuePtr) userdata;
5747   if (avp->field_list == NULL 
5748       || avp->field_list->data.intvalue < 1 
5749       || avp->field_list->data.intvalue >= NumEditQualifiers + 1)
5750   {
5751     return;
5752   }
5753 
5754   if (StringICmp (EditQualifierList[avp->field_list->data.intvalue - 1].name, "note") == 0)
5755   {
5756     sfp->comment = HandleApplyValue (sfp->comment, avp);
5757     return;
5758   }
5759   else if (StringICmp (EditQualifierList[avp->field_list->data.intvalue - 1].name, "exception") == 0)
5760   {
5761     sfp->except_text = HandleApplyValue (sfp->except_text, avp);
5762     return;
5763   }
5764   else if (StringICmp (EditQualifierList[avp->field_list->data.intvalue - 1].name, "product") == 0
5765            && sfp->data.choice == SEQFEAT_RNA)
5766   {
5767     SetRNAProduct (sfp, avp);
5768     return;
5769   }
5770   else if (StringICmp (EditQualifierList [avp->field_list->data.intvalue - 1].name, "map") == 0
5771            && sfp->data.choice == SEQFEAT_GENE)
5772   {
5773     grp = (GeneRefPtr) sfp->data.value.ptrvalue;
5774     if (grp != NULL)
5775     {
5776       grp->maploc = HandleApplyValue (grp->maploc, avp);
5777       return;
5778     }
5779   }
5780   else if (StringICmp (EditQualifierList [avp->field_list->data.intvalue - 1].name, "db_xref") == 0)
5781   {
5782     SetDbxrefFromString (sfp, avp, fsp);
5783     return;
5784   }
5785 
5786 
5787   if (!StringHasNoText (avp->text_to_replace))
5788   {
5789     found = TRUE;
5790   }
5791     
5792   gbqual = sfp->qual;
5793   while (gbqual != NULL)
5794   {
5795     gbqual_last = gbqual;
5796     if (StringCmp (gbqual->qual, EditQualifierList[avp->field_list->data.intvalue - 1].name) == 0)
5797     {
5798       gbqual->val = HandleApplyValue (gbqual->val, avp);
5799       found = TRUE;
5800     }
5801     gbqual = gbqual->next;
5802   }
5803   if (!found)
5804   {
5805     gbqual = GBQualNew ();
5806     if (gbqual != NULL)
5807     {
5808       gbqual->qual = StringSave (EditQualifierList[avp->field_list->data.intvalue - 1].name);
5809       gbqual->val = StringSave (avp->new_text);
5810       if (gbqual_last == NULL)
5811       {
5812         sfp->qual = gbqual;
5813       }
5814       else
5815       {
5816         gbqual_last->next = gbqual;
5817       }
5818     }
5819   }
5820 }
5821 
5822 static void RemoveInference (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
5823 {
5824   GBQualPtr     gbqual, gbqual_last = NULL, gbqual_next;
5825   ApplyValuePtr avp;
5826   
5827   if (sfp == NULL || userdata == NULL)
5828   {
5829     return;
5830   }
5831   avp = (ApplyValuePtr) userdata;
5832 
5833   gbqual = sfp->qual;
5834   while (gbqual != NULL)
5835   {
5836     gbqual_next = gbqual->next;
5837     if (StringCmp (gbqual->qual, "inference") == 0)
5838     {
5839       if (gbqual_last == NULL)
5840       {
5841         sfp->qual = gbqual->next;
5842       }
5843       else
5844       {
5845         gbqual_last->next = gbqual->next;
5846       }
5847       gbqual->next = NULL;
5848       GBQualFree (gbqual);
5849     }
5850     else
5851     {
5852       gbqual_last = gbqual;
5853     }
5854     gbqual = gbqual_next;
5855   }
5856 }
5857 
5858 static void RemoveGBQualField (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
5859 {
5860   GBQualPtr     gbqual, gbqual_last = NULL, gbqual_next;
5861   ApplyValuePtr avp;
5862   RnaRefPtr     rrp;
5863   GeneRefPtr    grp;
5864   
5865   if (sfp == NULL || userdata == NULL)
5866   {
5867     return;
5868   }
5869   avp = (ApplyValuePtr) userdata;
5870   if (avp->field_list == NULL 
5871       || avp->field_list->data.intvalue < 1 
5872       || avp->field_list->data.intvalue >= NumEditQualifiers + 1)
5873   {
5874     return;
5875   }
5876   
5877   if (StringICmp (EditQualifierList[avp->field_list->data.intvalue - 1].name, "note") == 0)
5878   {
5879     sfp->comment = MemFree (sfp->comment);
5880     return;
5881   }
5882   else if (StringICmp (EditQualifierList[avp->field_list->data.intvalue - 1].name, "exception") == 0)
5883   {
5884     sfp->except_text = MemFree (sfp->except_text);
5885     return;
5886   }
5887   else if (StringICmp (EditQualifierList[avp->field_list->data.intvalue - 1].name, "product") == 0
5888            && sfp->data.choice == SEQFEAT_RNA)
5889   {
5890     rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
5891     if (rrp != NULL && rrp->ext.choice == 1)
5892     {
5893       rrp->ext.choice = 0;
5894       rrp->ext.value.ptrvalue = MemFree (rrp->ext.value.ptrvalue);
5895     }
5896     return;
5897   }
5898   else if (StringICmp (EditQualifierList [avp->field_list->data.intvalue - 1].name, "map") == 0
5899            && sfp->data.choice == SEQFEAT_GENE)
5900   {
5901     grp = (GeneRefPtr) sfp->data.value.ptrvalue;
5902     if (grp != NULL)
5903     {
5904       grp->maploc = MemFree (grp->maploc);
5905     }
5906   }
5907   else if (StringICmp (EditQualifierList [avp->field_list->data.intvalue - 1].name, "db_xref") == 0)
5908   {
5909     sfp->dbxref = RemoveDbxrefList (sfp->dbxref);
5910   }
5911 
5912 
5913   gbqual = sfp->qual;
5914   while (gbqual != NULL)
5915   {
5916     gbqual_next = gbqual->next;
5917     if (StringCmp (gbqual->qual, EditQualifierList[avp->field_list->data.intvalue - 1].name) == 0)
5918     {
5919       if (gbqual_last == NULL)
5920       {
5921         sfp->qual = gbqual->next;
5922       }
5923       else
5924       {
5925         gbqual_last->next = gbqual->next;
5926       }
5927       gbqual->next = NULL;
5928       GBQualFree (gbqual);
5929     }
5930     else
5931     {
5932       gbqual_last = gbqual;
5933     }
5934     gbqual = gbqual_next;
5935   }
5936 }
5937 
5938 
5939 static void RemoveGoTerm (SeqFeatPtr sfp, CharPtr term_name)
5940 {
5941   UserObjectPtr       uop;
5942   ObjectIdPtr         oip;
5943   UserFieldPtr  curr, curr_next, prev = NULL;
5944   
5945   if (sfp == NULL || sfp->ext == NULL || StringHasNoText (term_name))
5946   {
5947     return;
5948   }
5949 
5950   uop = (UserObjectPtr) sfp->ext;
5951   oip = uop->type;
5952   if (oip == NULL || StringICmp (oip->str, "GeneOntology") != 0) return;
5953   
5954   for (curr = uop->data; curr != NULL; curr = curr_next)
5955   {
5956     curr_next = curr->next;
5957     oip = curr->label;
5958     if (oip != NULL && StringICmp (oip->str, term_name) == 0)
5959     {
5960       if (prev == NULL)
5961       {
5962         uop->data = curr->next;
5963       }
5964       else
5965       {
5966         prev->next = curr->next;
5967       }
5968       curr->next = NULL;
5969       UserFieldFree (curr);
5970     }
5971     else
5972     {
5973       prev = curr;
5974     }
5975   }
5976  
5977   if (uop->data == NULL)
5978   {
5979     sfp->ext = UserObjectFree (sfp->ext);
5980   }
5981  
5982 }
5983 
5984 
5985 static void RemoveGBQualByNameConstraint (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
5986 {
5987   GBQualPtr           gbqual, gbqual_last = NULL, gbqual_next;
5988   RnaRefPtr           rrp;
5989   GeneRefPtr          grp;
5990   StringConstraintXPtr scp;
5991   
5992   if (sfp == NULL || userdata == NULL)
5993   {
5994     return;
5995   }
5996   scp = (StringConstraintXPtr) userdata;
5997   if (scp == NULL)
5998   {
5999     return;
6000   }
6001   
6002   if (DoesStringMatchConstraintX ("note", scp))
6003   {
6004     sfp->comment = MemFree (sfp->comment);
6005   }
6006   
6007   if (DoesStringMatchConstraintX ("exception", scp))
6008   {
6009     sfp->except_text = MemFree (sfp->except_text);
6010   }
6011 
6012   if (DoesStringMatchConstraintX ("product", scp) && sfp->data.choice == SEQFEAT_RNA)
6013   {
6014     rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
6015     if (rrp != NULL && rrp->ext.choice == 1)
6016     {
6017       rrp->ext.choice = 0;
6018       rrp->ext.value.ptrvalue = MemFree (rrp->ext.value.ptrvalue);
6019     }
6020   }
6021   
6022   if (DoesStringMatchConstraintX ("map", scp) && sfp->data.choice == SEQFEAT_GENE)
6023   {
6024     grp = (GeneRefPtr) sfp->data.value.ptrvalue;
6025     if (grp != NULL)
6026     {
6027       grp->maploc = MemFree (grp->maploc);
6028     }
6029   }
6030   
6031   if (DoesStringMatchConstraintX ("db_xref", scp))
6032   {
6033     sfp->dbxref = RemoveDbxrefList (sfp->dbxref);
6034   }
6035   
6036   if (DoesStringMatchConstraintX ("go_process", scp))
6037   {
6038     RemoveGoTerm (sfp, "process");
6039   }
6040   
6041   if (DoesStringMatchConstraintX ("go_function", scp))
6042   {
6043     RemoveGoTerm (sfp, "function");
6044   }
6045 
6046   if (DoesStringMatchConstraintX ("go_component", scp))
6047   {
6048     RemoveGoTerm (sfp, "component");
6049   }
6050 
6051   gbqual = sfp->qual;
6052   while (gbqual != NULL)
6053   {
6054     gbqual_next = gbqual->next;
6055     if (DoesStringMatchConstraintX (gbqual->qual, scp))
6056     {
6057       if (gbqual_last == NULL)
6058       {
6059         sfp->qual = gbqual->next;
6060       }
6061       else
6062       {
6063         gbqual_last->next = gbqual->next;
6064       }
6065       gbqual->next = NULL;
6066       GBQualFree (gbqual);
6067     }
6068     else
6069     {
6070       gbqual_last = gbqual;
6071     }
6072     gbqual = gbqual_next;
6073   }
6074 }
6075 
6076 static void SetFeatureNote (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
6077 {
6078   ApplyValuePtr avp;
6079   
6080   if (sfp == NULL || userdata == NULL)
6081   {
6082     return;
6083   }
6084   avp = (ApplyValuePtr) userdata;
6085   sfp->comment = HandleApplyValue (sfp->comment, avp);
6086 }
6087 
6088 static CharPtr GetFeatureNote (SeqFeatPtr sfp, ValNodePtr vnp, FilterSetPtr fsp)
6089 {
6090   if (sfp == NULL || StringHasNoText (sfp->comment))
6091   {
6092     return NULL;
6093   }
6094   else
6095   {
6096     return StringSave (sfp->comment);
6097   }
6098 }
6099 
6100 static void RemoveFeatureNote (SeqFeatPtr sfp, Pointer userdata)
6101 {
6102   if (sfp == NULL)
6103   {
6104     return;
6105   }
6106   sfp->comment = MemFree (sfp->comment);
6107 }
6108 
6109 
6110 static void StripFieldNameFromText(CharPtr text,
6111                                    NameFromValNodeProc field_name_func, 
6112                                    ValNodePtr          field_vnp)
6113 {
6114   CharPtr src, dst;
6115   CharPtr field_name = NULL;
6116   Uint4    field_name_len;
6117   
6118   if (StringHasNoText (text) || field_name_func == NULL)
6119   {
6120     return;
6121   }
6122   
6123   field_name = field_name_func(field_vnp);
6124   field_name_len = StringLen (field_name);
6125     
6126   if (!StringHasNoText (field_name) && StringNICmp(text, field_name, field_name_len) == 0
6127         && StringLen (text) > field_name_len 
6128         && text[field_name_len] == ' ')
6129   {
6130     src = text + field_name_len + 1;
6131     while (*src == ' ')
6132     {
6133       src++;
6134     }
6135     dst = text;
6136     while (*src != 0)
6137     {
6138       *dst = *src;
6139       dst++;
6140       src++;
6141     }
6142     *dst = 0;
6143   }
6144   field_name = MemFree (field_name);
6145 }
6146 
6147 
6148 static CharPtr ReplaceStringForParse(CharPtr src_text, TextPortionXPtr text_portion)
6149 {
6150   CharPtr         found_loc;
6151   Int4            found_len;
6152   CharPtr         dst_txt = NULL, cp;
6153   
6154   if (src_text == NULL || text_portion == NULL) {
6155     return NULL;
6156   }
6157   /* for parse, replace the source text with the portion we want */
6158   found_loc = NULL;
6159   found_len = 0;
6160   FindTextPortionXInString (src_text, text_portion, &found_loc, &found_len);
6161   if (found_loc != NULL) 
6162   {
6163     dst_txt = (CharPtr)MemNew (found_len + 1);
6164     StringNCpy (dst_txt, found_loc, found_len);
6165     dst_txt[found_len] = 0;
6166     cp = found_loc + found_len;
6167     while (*cp != 0) {
6168       *found_loc = *cp;
6169       found_loc++;
6170       cp++;
6171     }
6172     *found_loc = 0;
6173   }
6174   return dst_txt;
6175 }
6176 
6177 
6178 static void ConvertFeatureFieldCallback (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
6179 {
6180   ConvertFieldPtr cfp;
6181   CharPtr         src_text;
6182   CharPtr         dst_text = NULL;
6183   ApplyValueData  avd;
6184   
6185   if (sfp == NULL || userdata == NULL)
6186   {
6187     return;
6188   }
6189   
6190   cfp = (ConvertFieldPtr) userdata;
6191   
6192   if (cfp->src_field_list == NULL || cfp->dst_field_list == NULL
6193       || cfp->get_str_func == NULL || cfp->set_str_func == NULL
6194       || cfp->remove_str_func == NULL)
6195   {
6196     return;
6197   }
6198   
6199   avd.text_to_replace = NULL;
6200   avd.where_to_replace = EditApplyFindLocation_anywhere;
6201   src_text = (cfp->get_str_func)(sfp, cfp->src_field_list, cfp->fsp);
6202   
6203   if (cfp->strip_name_from_text)
6204   {
6205     StripFieldNameFromText(src_text, cfp->name_field_func, cfp->dst_field_list);
6206   }
6207   
6208   if (StringHasNoText (src_text))
6209   {
6210     src_text = MemFree (src_text);
6211     return;
6212   }
6213   
6214   if (cfp->convert_type == CONVERT_TYPE_SWAP)
6215   {
6216     /* for swap, we already know what we're doing with existing text - 
6217      * we're putting it where the new text used to be. */
6218     avd.etp = NULL;
6219     /* and we need to get the destination text before it's replaced */
6220     dst_text = (cfp->get_str_func)(sfp, cfp->dst_field_list, cfp->fsp); 
6221     if (cfp->strip_name_from_text)
6222     {
6223       StripFieldNameFromText(dst_text, cfp->name_field_func, cfp->src_field_list);
6224     }
6225   }
6226   else if (cfp->convert_type == CONVERT_TYPE_PARSE)
6227   {
6228     /* for parse, replace the source text with the portion we want */
6229     dst_text = src_text;
6230     src_text = ReplaceStringForParse(src_text, cfp->text_portion);
6231     if (src_text == NULL) 
6232     {
6233       dst_text = MemFree (dst_text);
6234       return;
6235     }
6236     if (!cfp->remove_parsed) {
6237       dst_text = MemFree (dst_text);
6238     }
6239     avd.etp = cfp->etp;
6240   }
6241   else
6242   {
6243     avd.etp = cfp->etp;
6244   }
6245   
6246     
6247   /* put src_text in the dst_field */
6248   avd.field_list = cfp->dst_field_list;
6249   avd.new_text = src_text;
6250   (cfp->set_str_func) (sfp, &avd, cfp->fsp);
6251   
6252   if (cfp->convert_type == CONVERT_TYPE_SWAP
6253       || (cfp->convert_type == CONVERT_TYPE_PARSE && cfp->remove_parsed))
6254   {
6255     /* put dst_text in the src_field */
6256     avd.field_list = cfp->src_field_list;
6257     avd.new_text = dst_text;
6258     (cfp->set_str_func) (sfp, &avd, cfp->fsp);
6259   }
6260   else if (cfp->convert_type == CONVERT_TYPE_MOVE)
6261   {
6262     /* remove old src_field */
6263     avd.etp = NULL;
6264     avd.field_list = cfp->src_field_list;
6265     avd.new_text = NULL;
6266     (cfp->remove_str_func) (sfp, &avd, cfp->fsp);
6267   }
6268 }
6269 
6270 static void ConvertDescriptorFieldCallback (SeqDescrPtr sdp, Pointer userdata, FilterSetPtr fsp)
6271 {
6272   ConvertFieldPtr cfp;
6273   CharPtr         src_text;
6274   CharPtr         dst_text;
6275   ApplyValueData  avd;
6276   
6277   if (sdp == NULL || userdata == NULL)
6278   {
6279     return;
6280   }
6281   
6282   cfp = (ConvertFieldPtr) userdata;
6283   
6284   if (cfp->src_field_list == NULL || cfp->dst_field_list == NULL
6285       || cfp->get_d_str_func == NULL || cfp->set_d_str_func == NULL
6286       || cfp->remove_d_str_func == NULL)
6287   {
6288     return;
6289   }
6290   
6291   avd.text_to_replace = NULL;
6292   avd.where_to_replace = EditApplyFindLocation_anywhere;
6293   src_text = (cfp->get_d_str_func)(sdp, cfp->src_field_list, cfp->fsp);
6294   if (cfp->strip_name_from_text)
6295   {
6296     StripFieldNameFromText(src_text, cfp->name_field_func, cfp->dst_field_list);
6297   }
6298 
6299   if (StringHasNoText (src_text))
6300   {
6301     src_text = MemFree (src_text);
6302     return;
6303   }
6304   
6305   if (cfp->convert_type == CONVERT_TYPE_SWAP)
6306   {
6307     /* for swap, we already know what we're doing with existing text - 
6308      * we're putting it where the new text used to be. */
6309     avd.etp = NULL;
6310     /* and we need to get the destination text before it's replaced */
6311     dst_text = (cfp->get_d_str_func)(sdp, cfp->dst_field_list, cfp->fsp);    
6312     if (cfp->strip_name_from_text)
6313     {
6314       StripFieldNameFromText(dst_text, cfp->name_field_func, cfp->src_field_list);
6315     }
6316     
6317   }
6318   else if (cfp->convert_type == CONVERT_TYPE_PARSE)
6319   {
6320     /* for parse, replace the source text with the portion we want */
6321     dst_text = src_text;
6322     src_text = ReplaceStringForParse(src_text, cfp->text_portion);
6323     if (src_text == NULL) 
6324     {
6325       dst_text = MemFree (dst_text);
6326       return;
6327     }
6328     if (!cfp->remove_parsed) {
6329       dst_text = MemFree (dst_text);
6330     }
6331     avd.etp = cfp->etp;
6332   }
6333   else
6334   {
6335     avd.etp = cfp->etp;
6336   }
6337     
6338   /* put src_text in the dst_field */
6339   avd.field_list = cfp->dst_field_list;
6340   avd.new_text = src_text;
6341   (cfp->set_d_str_func) (sdp, &avd, cfp->fsp);
6342   
6343   if (cfp->convert_type == CONVERT_TYPE_SWAP
6344       || (cfp->convert_type == CONVERT_TYPE_PARSE && cfp->remove_parsed))
6345   {
6346     /* put dst_text in the src_field */
6347     avd.etp = NULL;
6348     avd.field_list = cfp->src_field_list;
6349     avd.new_text = dst_text;
6350     (cfp->set_d_str_func) (sdp, &avd, cfp->fsp);
6351   }
6352   else if (cfp->convert_type == CONVERT_TYPE_MOVE)
6353   {
6354     /* remove old src_field */
6355     avd.etp = NULL;
6356     avd.field_list = cfp->src_field_list;
6357     avd.new_text = NULL;
6358     (cfp->remove_d_str_func) (sdp, &avd, cfp->fsp);
6359   }
6360 }
6361 
6362 static void ConvertNonTextFeatureFieldCallback (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
6363 {
6364   ConvertFieldPtr cfp;
6365   CharPtr         curr_val = NULL;
6366   CharPtr         src_val;
6367   ApplyValueData  avd;
6368   
6369   if (sfp == NULL || userdata == NULL)
6370   {
6371     return;
6372   }
6373   
6374   cfp = (ConvertFieldPtr) userdata;
6375   
6376   if (cfp->src_field_list == NULL || cfp->dst_field_list == NULL
6377       || cfp->get_str_func == NULL || cfp->set_str_func == NULL
6378       || cfp->name_field_func == NULL)
6379   {
6380     return;
6381   }
6382   
6383   curr_val = (cfp->get_str_func)(sfp, NULL, NULL);
6384   src_val = (cfp->name_field_func)(cfp->src_field_list);
6385   if (StringCmp (curr_val, src_val) == 0)
6386   {
6387     avd.where_to_replace = EditApplyFindLocation_anywhere;
6388     avd.field_list = cfp->dst_field_list;
6389     avd.etp = NULL;
6390     (cfp->set_str_func) (sfp, &avd, cfp->fsp);
6391   }
6392   curr_val = MemFree (curr_val);
6393   src_val = MemFree (src_val);
6394 }
6395 
6396 static void ConvertNonTextDescriptorFieldCallback (SeqDescrPtr sdp, Pointer userdata, FilterSetPtr fsp)
6397 {
6398   ConvertFieldPtr cfp;
6399   CharPtr         curr_val = NULL;
6400   CharPtr         src_val;
6401   ApplyValueData  avd;
6402   
6403   if (sdp == NULL || userdata == NULL)
6404   {
6405     return;
6406   }
6407   
6408   cfp = (ConvertFieldPtr) userdata;
6409   
6410   if (cfp->src_field_list == NULL || cfp->dst_field_list == NULL
6411       || cfp->get_d_str_func == NULL || cfp->set_d_str_func == NULL
6412       || cfp->name_field_func == NULL)
6413   {
6414     return;
6415   }
6416   
6417   curr_val = (cfp->get_d_str_func)(sdp, NULL, NULL);
6418   src_val = (cfp->name_field_func)(cfp->src_field_list);
6419   if (StringCmp (curr_val, src_val) == 0)
6420   {
6421     avd.where_to_replace = EditApplyFindLocation_anywhere;
6422     avd.field_list = cfp->dst_field_list;
6423     avd.etp = NULL;
6424     (cfp->set_d_str_func) (sdp, &avd, cfp->fsp);
6425   }
6426   curr_val = MemFree (curr_val);
6427   src_val = MemFree (src_val);
6428 }
6429 
6430 #define FEATUREFIELD_NONE        0
6431 
6432 typedef struct featurefieldselection 
6433 {
6434   DIALOG_MESSAGE_BLOCK
6435   PopuP                    feature_field;
6436 
6437   Boolean                  allow_none;
6438   Int4                     num_fields;
6439   Nlm_ChangeNotifyProc     change_notify;
6440   Pointer                  change_userdata;
6441 } FeatureFieldSelectionData, PNTR FeatureFieldSelectionPtr;
6442 
6443 
6444 static void FeatureFieldSelectionChange (PopuP p)
6445 {
6446   FeatureFieldSelectionPtr  dlg;
6447 
6448   dlg = (FeatureFieldSelectionPtr) GetObjectExtra (p);
6449   if (dlg == NULL)
6450   {
6451     return;
6452   }
6453   if (dlg->change_notify != NULL)
6454   {
6455     (dlg->change_notify) (dlg->change_userdata);
6456   }
6457 }
6458 
6459 static void ResetFeatureFieldSelection (FeatureFieldSelectionPtr dlg)
6460 {
6461   if (dlg == NULL)
6462   {
6463     return;
6464   }
6465   SetValue (dlg->feature_field, 1);
6466   FeatureFieldSelectionChange (dlg->feature_field);
6467 }
6468 
6469 static void FeatureFieldToDialog (DialoG d, Pointer data)
6470 {
6471   FeatureFieldSelectionPtr  dlg;
6472   ValNodePtr             vnp;
6473   Int4                   feature_field;
6474 
6475   dlg = (FeatureFieldSelectionPtr) GetObjectExtra (d);
6476   if (dlg == NULL)
6477   {
6478     return;
6479   }
6480   
6481   vnp = (ValNodePtr) data;
6482   if (vnp == NULL)
6483   {
6484     ResetFeatureFieldSelection (dlg);
6485   }
6486   else
6487   {
6488     feature_field = vnp->data.intvalue;
6489     if (feature_field < FEATUREFIELD_NONE || feature_field > dlg->num_fields + 1)
6490     {
6491       feature_field = FEATUREFIELD_NONE;
6492     }
6493     if (dlg->allow_none)
6494     {
6495       feature_field ++;
6496     }
6497     SetValue (dlg->feature_field, feature_field);
6498   }  
6499 }
6500 
6501 static Pointer DialogToFeatureField (DialoG d)
6502 {
6503   FeatureFieldSelectionPtr  dlg;
6504   ValNodePtr             vnp = NULL;
6505   Int4                   feature_field;
6506 
6507   dlg = (FeatureFieldSelectionPtr) GetObjectExtra (d);
6508   if (dlg == NULL)
6509   {
6510     return NULL;
6511   }
6512   
6513   feature_field = GetValue (dlg->feature_field);
6514   if (dlg->allow_none)
6515   {
6516     feature_field --;
6517   }
6518   if (feature_field > FEATUREFIELD_NONE)
6519   {
6520     vnp = ValNodeNew (NULL);
6521     if (vnp != NULL)
6522     {
6523       vnp->data.intvalue = feature_field;
6524     }
6525   }
6526   return vnp;
6527 }
6528 
6529 static void FeatureFieldMessage (DialoG d, Int2 mssg)
6530 
6531 {
6532   FeatureFieldSelectionPtr  dlg;
6533 
6534   dlg = (FeatureFieldSelectionPtr) GetObjectExtra (d);
6535   if (dlg != NULL) {
6536     switch (mssg) {
6537       case VIB_MSG_INIT :
6538         /* reset list */
6539         ResetFeatureFieldSelection (dlg);
6540         break;
6541       case VIB_MSG_ENTER :
6542         Select (dlg->feature_field);
6543         break;
6544       default :
6545         break;
6546     }
6547   }
6548 }
6549 
6550 static ValNodePtr TestFeatureFieldDialog (DialoG d)
6551 
6552 {
6553   return NULL;
6554 }
6555 
6556 static DialoG FeatureFieldSelectionDialogEx 
6557 (GrouP                    h,
6558  Boolean                  allow_none,
6559  CharPtr                  none_txt,
6560  Int4                     num_fields,
6561  CharPtr PNTR             field_names,
6562  Nlm_ChangeNotifyProc     change_notify,
6563  Pointer                  change_userdata)
6564 {
6565   FeatureFieldSelectionPtr  dlg;
6566   GrouP                     p;
6567   Int4                      k;
6568   
6569   dlg = (FeatureFieldSelectionPtr) MemNew (sizeof (FeatureFieldSelectionData));
6570   if (dlg == NULL)
6571   {
6572     return NULL;
6573   }
6574 
6575   p = HiddenGroup (h, 1, 0, NULL);
6576   SetObjectExtra (p, dlg, StdCleanupExtraProc);
6577 
6578   dlg->dialog = (DialoG) p;
6579   dlg->todialog = FeatureFieldToDialog;
6580   dlg->fromdialog = DialogToFeatureField;
6581   dlg->dialogmessage = FeatureFieldMessage;
6582   dlg->testdialog = TestFeatureFieldDialog;
6583   dlg->allow_none = allow_none;
6584   dlg->num_fields = num_fields;
6585   dlg->change_notify = change_notify;
6586   dlg->change_userdata = change_userdata;
6587 
6588   dlg->feature_field = PopupList (p, TRUE, FeatureFieldSelectionChange);
6589   if (dlg->allow_none)
6590   {
6591     PopupItem (dlg->feature_field, none_txt);
6592   }
6593   for (k = 0; k < dlg->num_fields; k++)
6594   {
6595     PopupItem (dlg->feature_field, field_names[k]);
6596   }
6597   SetValue (dlg->feature_field, 1);
6598   SetObjectExtra (dlg->feature_field, dlg, NULL);
6599   return (DialoG) p;  
6600 }
6601 
6602 extern DialoG 
6603 FeatureFieldSelectionDialog
6604 (GrouP                    h,
6605  Boolean                  allow_none,
6606  Int4                     num_fields,
6607  CharPtr PNTR             field_names,
6608  Nlm_ChangeNotifyProc     change_notify,
6609  Pointer                  change_userdata)
6610 {
6611   return FeatureFieldSelectionDialogEx (h, allow_none, "None", 
6612                                         num_fields, field_names, 
6613                                         change_notify, change_userdata);
6614 }
6615 
6616 static DialoG FeatureFieldSelectionDialogAny
6617 (GrouP                    h,
6618  Boolean                  allow_none,
6619  Int4                     num_fields,
6620  CharPtr PNTR             field_names,
6621  Nlm_ChangeNotifyProc     change_notify,
6622  Pointer                  change_userdata)
6623 {
6624   return FeatureFieldSelectionDialogEx (h, allow_none, "Any Field", 
6625                                         num_fields, field_names, 
6626                                         change_notify, change_userdata);
6627 }
6628 
6629 
6630 static CharPtr gene_field_list [] = 
6631 {
6632   "locus", "description", "comment", "allele", "maploc", "locus_tag", "synonym", "old_locus_tag"  
6633 };
6634 
6635 #define GENEFIELD_LOCUS         1
6636 #define GENEFIELD_DESCRIPTION   2
6637 #define GENEFIELD_COMMENT       3
6638 #define GENEFIELD_ALLELE        4
6639 #define GENEFIELD_MAPLOC        5
6640 #define GENEFIELD_LOCUS_TAG     6
6641 #define GENEFIELD_SYNONYM       7
6642 #define GENEFIELD_OLD_LOCUS_TAG 8
6643 
6644 static int num_gene_fields = sizeof (gene_field_list) / sizeof (CharPtr);
6645 
6646 extern DialoG 
6647 GeneFieldSelectionDialog
6648 (GrouP                    h,
6649  Boolean                  allow_none,
6650  Nlm_ChangeNotifyProc     change_notify,
6651  Pointer                  change_userdata)
6652 {
6653   return FeatureFieldSelectionDialog (h, allow_none,
6654                                       num_gene_fields, gene_field_list, 
6655                                       change_notify, change_userdata);
6656 }
6657 
6658 extern CharPtr 
6659 GetGeneFieldString 
6660 (SeqFeatPtr   sfp,
6661  ValNodePtr   gene_field,
6662  FilterSetPtr fsp)
6663 {
6664   ValNodePtr vnp;
6665   CharPtr    str = NULL;
6666   GeneRefPtr grp;
6667   GBQualPtr  qual;
6668   
6669   if (sfp == NULL || gene_field == NULL)
6670   {
6671     return NULL;
6672   }
6673   
6674   if (sfp->data.choice == SEQFEAT_GENE)
6675   {
6676     grp = (GeneRefPtr) sfp->data.value.ptrvalue;
6677   }
6678   else
6679   {
6680     grp = SeqMgrGetGeneXref (sfp);
6681   }
6682   
6683   if (sfp->data.choice != SEQFEAT_GENE && grp != NULL)
6684   {
6685     vnp = NULL;
6686   }
6687   
6688   vnp = gene_field;
6689   while (vnp != NULL && vnp->data.intvalue != FEATUREFIELD_NONE && StringHasNoText (str))
6690   {
6691     str = NULL;
6692     switch (vnp->data.intvalue)
6693     {
6694       case GENEFIELD_LOCUS:
6695         if (grp != NULL)
6696         {
6697           str = grp->locus;
6698         }
6699         break;
6700       case GENEFIELD_DESCRIPTION:
6701         if (grp != NULL)
6702         {
6703           str = grp->desc;
6704         }
6705         break;
6706       case GENEFIELD_COMMENT:
6707         if (sfp->data.choice == SEQFEAT_GENE)
6708         {
6709           str = sfp->comment;
6710         }
6711         break;
6712       case GENEFIELD_ALLELE:
6713         if (grp != NULL)
6714         {
6715           str = grp->allele;
6716         }
6717         break;
6718       case GENEFIELD_MAPLOC:
6719         if (grp != NULL)
6720         {
6721           str = grp->maploc;
6722         }
6723         break;
6724       case GENEFIELD_SYNONYM:
6725         if (grp != NULL && grp->syn != NULL)
6726         {
6727           str = grp->syn->data.ptrvalue;
6728         }
6729         break;
6730       case GENEFIELD_LOCUS_TAG:
6731         if (grp != NULL)
6732         {
6733           str = grp->locus_tag;
6734         }
6735         break;
6736       case GENEFIELD_OLD_LOCUS_TAG:
6737         qual = sfp->qual;
6738         while (qual != NULL && StringICmp (qual->qual, "old_locus_tag") != 0)
6739         {
6740           qual = qual->next;
6741         }
6742         if (qual != NULL)
6743         {
6744           str = qual->val;
6745         }
6746         break;
6747     }
6748     vnp = vnp->next;
6749   }
6750   if (StringHasNoText (str))
6751   {
6752     str = NULL;
6753   }
6754   else
6755   {
6756     str = StringSave (str);
6757   }
6758   return str;
6759 }
6760 
6761 extern void RemoveGeneFieldString (SeqFeatPtr sfp, ValNodePtr gene_field)
6762 {
6763   ValNodePtr vnp;
6764   Boolean    found_nonempty = FALSE;
6765   GeneRefPtr grp;
6766   ValNodePtr syn_remove;
6767   GBQualPtr  qual, prevqual;
6768   
6769   if (sfp == NULL || gene_field == NULL)
6770   {
6771     return;
6772   }
6773   
6774   if (sfp->data.choice == SEQFEAT_GENE)
6775   {
6776     grp = (GeneRefPtr) sfp->data.value.ptrvalue;
6777   }
6778   else
6779   {
6780     grp = SeqMgrGetGeneXref (sfp);
6781   }
6782   
6783   if (grp == NULL)
6784   {
6785     return;
6786   }
6787   
6788   vnp = gene_field;
6789   while (vnp != NULL && vnp->data.intvalue != FEATUREFIELD_NONE && !found_nonempty)
6790   {
6791     switch (vnp->data.intvalue)
6792     {
6793       case GENEFIELD_LOCUS:
6794         if (grp != NULL && !StringHasNoText (grp->locus))
6795         {
6796           found_nonempty = TRUE;
6797           if (vnp->choice != 0)
6798           {
6799             grp->locus = MemFree (grp->locus);
6800           }
6801         }
6802         break;
6803       case GENEFIELD_DESCRIPTION:
6804         if (grp != NULL && !StringHasNoText (grp->desc))
6805         {
6806           found_nonempty = TRUE;
6807           if (vnp->choice != 0)
6808           {
6809             grp->desc = MemFree (grp->desc);
6810           }
6811         }
6812         break;
6813       case GENEFIELD_COMMENT:
6814         if (!StringHasNoText (sfp->comment))
6815         {
6816           found_nonempty = TRUE;
6817           if (vnp->choice != 0)
6818           {
6819             sfp->comment = MemFree (sfp->comment);
6820           }
6821         }
6822         break;
6823       case GENEFIELD_ALLELE:
6824         if (grp != NULL && !StringHasNoText (grp->allele))
6825         {
6826           found_nonempty = TRUE;
6827           if (vnp->choice != 0)
6828           {
6829             grp->allele = MemFree (grp->allele);  
6830           }
6831         }
6832         break;
6833       case GENEFIELD_MAPLOC:
6834         if (grp != NULL && !StringHasNoText (grp->maploc))
6835         {
6836           found_nonempty = TRUE;
6837           if (vnp->choice != 0)
6838           {
6839             grp->maploc = MemFree (grp->maploc);            
6840           }
6841         }
6842         break;
6843       case GENEFIELD_SYNONYM:
6844         if (grp != NULL && grp->syn != NULL && !StringHasNoText (grp->syn->data.ptrvalue))
6845         {
6846           found_nonempty = TRUE;
6847           if (vnp->choice != 0)
6848           {
6849             syn_remove = grp->syn;
6850             grp->syn = grp->syn->next;
6851             syn_remove->next = NULL;
6852             ValNodeFreeData (syn_remove);
6853           }
6854         }
6855         break;
6856       case GENEFIELD_LOCUS_TAG:
6857         if (grp != NULL && !StringHasNoText (grp->locus_tag))
6858         {
6859           found_nonempty = TRUE;
6860           if (vnp->choice != 0)
6861           {
6862             grp->locus_tag = MemFree (grp->locus_tag);
6863           }
6864         }
6865         break;
6866       case GENEFIELD_OLD_LOCUS_TAG:
6867         prevqual = NULL;
6868         qual = sfp->qual;
6869         while (qual != NULL)
6870         {
6871           if (StringICmp (qual->qual, "old_locus_tag") == 0)
6872           {
6873             if (prevqual == NULL)
6874             {
6875               sfp->qual = qual->next;
6876               qual->next = NULL;
6877               qual = GBQualFree (qual);
6878               qual = sfp->qual;
6879             }
6880             else
6881             {
6882               prevqual->next = qual->next;
6883               qual->next = NULL;
6884               qual = GBQualFree (qual);
6885               qual = prevqual->next;
6886             }
6887           }
6888           else
6889           {
6890             prevqual = qual;
6891             qual = qual->next;
6892           }
6893         }
6894         break;
6895     }
6896     vnp = vnp->next;
6897   }
6898 }
6899 
6900 static void SetGeneFieldString (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
6901 {
6902   GeneRefPtr    grp;
6903   ApplyValuePtr avp;
6904   Boolean       found;
6905   GBQualPtr     qual, qual_last;
6906   
6907   if (sfp == NULL || userdata == NULL)
6908   {
6909     return;
6910   }
6911   avp = (ApplyValuePtr) userdata;
6912   if (avp->field_list == NULL)
6913   {
6914     return;
6915   }
6916   
6917   if (sfp->data.choice == SEQFEAT_GENE)
6918   {
6919     grp = (GeneRefPtr) sfp->data.value.ptrvalue;
6920   }
6921   else
6922   {
6923     grp = SeqMgrGetGeneXref (sfp);
6924   }
6925   
6926   if (grp == NULL && sfp->data.choice == SEQFEAT_GENE)
6927   {
6928     grp = GeneRefNew ();
6929     sfp->data.value.ptrvalue = grp;
6930   }
6931   
6932   if (grp == NULL)
6933   {
6934     return;
6935   }
6936   
6937   switch (avp->field_list->data.intvalue)
6938   {
6939     case GENEFIELD_LOCUS:
6940       grp->locus = HandleApplyValue (grp->locus, avp);
6941       break;
6942     case GENEFIELD_DESCRIPTION:
6943       grp->desc = HandleApplyValue (grp->desc, avp);
6944       break;
6945     case GENEFIELD_COMMENT:
6946       sfp->comment = HandleApplyValue (sfp->comment, avp);
6947       break;
6948     case GENEFIELD_ALLELE:
6949       grp->allele = HandleApplyValue (grp->allele, avp);  
6950       break;
6951     case GENEFIELD_MAPLOC:
6952       grp->maploc = HandleApplyValue (grp->maploc, avp);            
6953       break;
6954     case GENEFIELD_SYNONYM:
6955       if (grp->syn == NULL || !StringHasNoText (avp->text_to_replace)) {
6956         grp->syn = ApplyValueToValNodeStringList (grp->syn, 0, avp);
6957       } else {
6958         grp->syn->data.ptrvalue = HandleApplyValue (grp->syn->data.ptrvalue, avp);
6959       }
6960       break;
6961     case GENEFIELD_LOCUS_TAG:
6962       grp->locus_tag = HandleApplyValue (grp->locus_tag, avp);
6963       break;
6964     case GENEFIELD_OLD_LOCUS_TAG:
6965       qual = sfp->qual;
6966       qual_last = NULL;
6967       found = FALSE;
6968       while (qual != NULL && !found)
6969       {
6970         qual_last = qual;
6971         if (StringCmp (qual->qual, "old_locus_tag") == 0)
6972         {
6973           qual->val = HandleApplyValue (qual->val, avp);
6974           found = TRUE;
6975         }
6976         qual = qual->next;
6977       }
6978       if (!found)
6979       {
6980         qual = GBQualNew ();
6981         if (qual != NULL)
6982         {
6983           qual->qual = StringSave ("old_locus_tag");
6984           qual->val = StringSave (avp->new_text);
6985           if (qual_last == NULL)
6986           {
6987             sfp->qual = qual;
6988           }
6989           else
6990           {
6991             qual_last->next = qual;
6992           }
6993         }
6994       }    
6995       break;
6996   }
6997 }
6998 
6999 static CharPtr mrna_field_list [] = 
7000 {
7001   "product", "comment"  
7002 };
7003 
7004 #define MRNAFIELD_PRODUCT     1
7005 #define MRNAFIELD_COMMENT     2
7006 
7007 static int num_mrna_fields = sizeof (mrna_field_list) / sizeof (CharPtr);
7008 
7009 extern DialoG 
7010 MRNAFieldSelectionDialog
7011 (GrouP                    h,
7012  Boolean                  allow_none,
7013  Nlm_ChangeNotifyProc     change_notify,
7014  Pointer                  change_userdata)
7015 {
7016   return FeatureFieldSelectionDialog (h, allow_none,
7017                                       num_mrna_fields, mrna_field_list, 
7018                                       change_notify, change_userdata);
7019 }
7020 
7021 extern CharPtr 
7022 GetmRNAFieldString 
7023 (SeqFeatPtr   sfp,
7024  ValNodePtr   mrna_field,
7025  FilterSetPtr fsp)
7026 {
7027   ValNodePtr vnp;
7028   CharPtr    str = NULL;
7029   RnaRefPtr  rrp;
7030   
7031   if (sfp == NULL || mrna_field == NULL || sfp->idx.subtype != FEATDEF_mRNA)
7032   {
7033     return NULL;
7034   }
7035   
7036   vnp = mrna_field;
7037   rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
7038 
7039   while (vnp != NULL && vnp->data.intvalue != FEATUREFIELD_NONE && StringHasNoText (str))
7040   {
7041     str = NULL;
7042     switch (vnp->data.intvalue)
7043     {
7044       case MRNAFIELD_PRODUCT:
7045         if (rrp != NULL)
7046         {
7047           str = rrp->ext.value.ptrvalue;
7048         }
7049         break;
7050       case MRNAFIELD_COMMENT:
7051         str = sfp->comment;
7052         break;
7053     }
7054     vnp = vnp->next;
7055   }
7056   if (StringHasNoText (str))
7057   {
7058     str = NULL;
7059   }
7060   else
7061   {
7062     str = StringSave (str);
7063   }
7064   return str;
7065 }
7066 
7067 extern void RemovemRNAFieldString (SeqFeatPtr sfp, ValNodePtr mrna_field)
7068 {
7069   ValNodePtr vnp;
7070   Boolean    found_nonempty = FALSE;
7071   RnaRefPtr  rrp;
7072   
7073   if (sfp == NULL || mrna_field == NULL || sfp->idx.subtype != FEATDEF_mRNA)
7074   {
7075     return;
7076   }
7077   
7078   vnp = mrna_field;
7079   rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
7080   while (vnp != NULL && vnp->data.intvalue != FEATUREFIELD_NONE && !found_nonempty)
7081   {
7082     switch (vnp->data.intvalue)
7083     {
7084       case MRNAFIELD_PRODUCT:
7085         if (rrp != NULL && !StringHasNoText (rrp->ext.value.ptrvalue))
7086         {
7087           found_nonempty = TRUE;
7088           if (vnp->choice != 0)
7089           {
7090             rrp->ext.value.ptrvalue = MemFree (rrp->ext.value.ptrvalue);
7091           }
7092         }
7093         break;
7094       case MRNAFIELD_COMMENT:
7095         if (!StringHasNoText (sfp->comment))
7096         {
7097           found_nonempty = TRUE;
7098           if (vnp->choice != 0)
7099           {
7100             sfp->comment = MemFree (sfp->comment);
7101           }
7102         }
7103         break;
7104     }
7105     vnp = vnp->next;
7106   }
7107 }
7108 
7109 static void SetmRNAFieldString (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
7110 {
7111   RnaRefPtr     rrp;
7112   ApplyValuePtr avp;
7113   Int4          field_choice;
7114   
7115   if (sfp == NULL || userdata == NULL || sfp->idx.subtype != FEATDEF_mRNA)
7116   {
7117     return;
7118   }
7119   
7120   avp = (ApplyValuePtr) userdata;
7121   if (avp->field_list == NULL)
7122   {
7123     return;
7124   }
7125   
7126   rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
7127   if (rrp == NULL)
7128   {
7129     rrp = RnaRefNew ();
7130     if (rrp == NULL)
7131     {
7132       return;
7133     }
7134     sfp->data.value.ptrvalue = rrp;
7135   }
7136   field_choice = avp->field_list->data.intvalue;
7137   switch (avp->field_list->data.intvalue)
7138   {
7139     case MRNAFIELD_PRODUCT:
7140       if (rrp->ext.choice == 0)
7141       {
7142         rrp->ext.choice = 1;
7143         rrp->ext.value.ptrvalue = NULL;
7144       }    
7145       rrp->ext.value.ptrvalue = HandleApplyValue (rrp->ext.value.ptrvalue, avp);
7146       break;
7147     case MRNAFIELD_COMMENT:
7148       sfp->comment = HandleApplyValue (sfp->comment,avp);
7149       break;
7150   }
7151 }
7152 
7153 static CharPtr GetCDSComment (SeqFeatPtr sfp, ValNodePtr vnp, FilterSetPtr fsp)
7154 {
7155   if (sfp == NULL || sfp->data.choice != SEQFEAT_CDREGION || StringHasNoText (sfp->comment))
7156   {
7157     return NULL;
7158   }
7159   else
7160   {
7161     return StringSave (sfp->comment);
7162   }
7163 }
7164 
7165 static void SetCDSComment (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
7166 {
7167   ApplyValuePtr avp;
7168 
7169   if (sfp == NULL || userdata == NULL || sfp->data.choice != SEQFEAT_CDREGION)
7170   {
7171     return;
7172   }
7173   
7174   avp = (ApplyValuePtr) userdata;
7175 
7176   sfp->comment = HandleApplyValue (sfp->comment, avp);  
7177 }
7178 
7179 static void RemoveCDSComment (SeqFeatPtr sfp, ValNodePtr vnp)
7180 {
7181   if (sfp == NULL || sfp->data.choice != SEQFEAT_CDREGION)
7182   {
7183     return;
7184   }
7185   sfp->comment = MemFree (sfp->comment);
7186 }
7187 
7188 extern CharPtr 
7189 GetCDSFieldString 
7190 (SeqFeatPtr   sfp,
7191  ValNodePtr   cds_field,
7192  FilterSetPtr fsp)
7193 {
7194   ValNodePtr vnp;
7195   CharPtr    str = NULL;
7196   BioseqPtr  prot_bsp;
7197   SeqFeatPtr prot_sfp;
7198   SeqMgrFeatContext prot_context;
7199   ProtRefPtr        prp;
7200   
7201   if (sfp == NULL || cds_field == NULL || sfp->idx.subtype != FEATDEF_CDS)
7202   {
7203     return NULL;
7204   }
7205   
7206   vnp = cds_field;
7207 
7208   while (vnp != NULL && vnp->data.intvalue != FEATUREFIELD_NONE && StringHasNoText (str))
7209   {
7210     str = NULL;
7211     switch (vnp->data.intvalue)
7212     {
7213       case MRNAFIELD_PRODUCT:
7214         prot_bsp = BioseqFind (SeqLocId (sfp->product));
7215         prot_sfp = SeqMgrGetNextFeature (prot_bsp, NULL, SEQFEAT_PROT, 0, &prot_context);
7216         if (prot_sfp != NULL && prot_sfp->data.value.ptrvalue != NULL) {
7217           prp = (ProtRefPtr) prot_sfp->data.value.ptrvalue;
7218           if (prp->name != NULL && !StringHasNoText (prp->name->data.ptrvalue)) {
7219             str = prp->name->data.ptrvalue;
7220           }
7221         }
7222         break;
7223       case MRNAFIELD_COMMENT:
7224         str = sfp->comment;
7225         break;
7226     }
7227     vnp = vnp->next;
7228   }
7229   if (StringHasNoText (str))
7230   {
7231     str = NULL;
7232   }
7233   else
7234   {
7235     str = StringSave (str);
7236   }
7237   return str;
7238 }
7239 
7240 extern void RemoveCDSFieldString (SeqFeatPtr sfp, ValNodePtr cds_field)
7241 {
7242   ValNodePtr vnp;
7243   Boolean    found_nonempty = FALSE;
7244   BioseqPtr  prot_bsp;
7245   SeqFeatPtr prot_sfp;
7246   SeqMgrFeatContext prot_context;
7247   ProtRefPtr        prp;
7248   
7249   if (sfp == NULL || cds_field == NULL || sfp->idx.subtype != FEATDEF_CDS)
7250   {
7251     return;
7252   }
7253   
7254   vnp = cds_field;
7255   while (vnp != NULL && vnp->data.intvalue != FEATUREFIELD_NONE && !found_nonempty)
7256   {
7257     switch (vnp->data.intvalue)
7258     {
7259       case MRNAFIELD_PRODUCT:
7260         prot_bsp = BioseqFind (SeqLocId (sfp->product));
7261         prot_sfp = SeqMgrGetNextFeature (prot_bsp, NULL, SEQFEAT_PROT, 0, &prot_context);
7262         if (prot_sfp != NULL && prot_sfp->data.value.ptrvalue != NULL) {
7263           prp = (ProtRefPtr) prot_sfp->data.value.ptrvalue;
7264           if (prp->name != NULL && !StringHasNoText (prp->name->data.ptrvalue)) {
7265             found_nonempty = TRUE;
7266             if (vnp->choice != 0) {
7267               prp->name = ValNodeFreeData (prp->name);
7268             }
7269           }
7270         }
7271         break;
7272       case MRNAFIELD_COMMENT:
7273         if (!StringHasNoText (sfp->comment))
7274         {
7275           found_nonempty = TRUE;
7276           if (vnp->choice != 0)
7277           {
7278             sfp->comment = MemFree (sfp->comment);
7279           }
7280         }
7281         break;
7282     }
7283     vnp = vnp->next;
7284   }
7285 }
7286 
7287 #define PROTEINFIELD_NAME               1
7288 #define PROTEINFIELD_DESC               2
7289 #define PROTEINFIELD_EC_NUM             3
7290 #define PROTEINFIELD_ACTIVITY           4
7291 #define PROTEINFIELD_COMMENT            5
7292 #define PROTEINFIELD_MATPEPTIDE_NAME    6
7293 #define PROTEINFIELD_MATPEPTIDE_DESC    7
7294 #define PROTEINFIELD_MATPEPTIDE_COMMENT 8
7295 
7296 static CharPtr protein_field_list [] =
7297 {
7298   "name", "description", "E.C. number", "activity", "comment", "mat_peptide name", "mat_peptide description", "mat_peptide comment"
7299 };
7300 
7301 static int num_protein_fields = sizeof (protein_field_list) / sizeof (CharPtr);
7302 
7303 extern DialoG 
7304 ProteinFieldSelectionDialog
7305 (GrouP                    h,
7306  Boolean                  allow_none,
7307  Nlm_ChangeNotifyProc     change_notify,
7308  Pointer                  change_userdata)
7309 {
7310   return FeatureFieldSelectionDialog (h, allow_none,
7311                                       num_protein_fields, protein_field_list, 
7312                                       change_notify, change_userdata);
7313 }
7314 
7315 extern CharPtr GetProteinFieldString (SeqFeatPtr sfp, ValNodePtr protein_field, FilterSetPtr fsp)
7316 {
7317   ValNodePtr     vnp, val_vnp;
7318   CharPtr        str = NULL;
7319   ProtRefPtr     prp = NULL;
7320   Int4           field_choice;
7321   SeqFeatXrefPtr xref;
7322   
7323   if (sfp == NULL || protein_field == NULL || (sfp->data.choice != SEQFEAT_PROT && sfp->data.choice != SEQFEAT_CDREGION))
7324   {
7325     return NULL;
7326   }
7327   
7328   vnp = protein_field;
7329   if (sfp->data.choice == SEQFEAT_PROT) {
7330       prp = (ProtRefPtr) sfp->data.value.ptrvalue;
7331   } else if (sfp->data.choice == SEQFEAT_CDREGION) {
7332       xref = sfp->xref;
7333       while (xref != NULL && xref->data.choice != SEQFEAT_PROT) {
7334           xref = xref->next;
7335       }
7336       if (xref != NULL) {
7337           prp = xref->data.value.ptrvalue;
7338       }
7339   }
7340 
7341 
7342   while (vnp != NULL && vnp->data.intvalue != FEATUREFIELD_NONE && StringHasNoText (str))
7343   {
7344     str = NULL;
7345     field_choice = vnp->data.intvalue;
7346     switch (field_choice)
7347     {
7348       case PROTEINFIELD_NAME:
7349         if (prp != NULL && prp->name != NULL && (sfp->idx.subtype == FEATDEF_PROT || sfp->idx.subtype == FEATDEF_CDS))
7350         {
7351           val_vnp = prp->name;
7352           str = val_vnp->data.ptrvalue;
7353         }
7354         break;
7355       case PROTEINFIELD_DESC:
7356         if (prp != NULL && sfp->idx.subtype == FEATDEF_PROT)
7357         {
7358           str = prp->desc;
7359         }
7360         break;
7361       case PROTEINFIELD_EC_NUM:
7362         if (prp != NULL && prp->ec != NULL && sfp->idx.subtype == FEATDEF_PROT)
7363         {
7364           val_vnp = prp->ec;
7365           str = val_vnp->data.ptrvalue;
7366         }
7367         break;
7368       case PROTEINFIELD_ACTIVITY:
7369         if (prp != NULL && prp->activity != NULL && sfp->idx.subtype == FEATDEF_PROT)
7370         {
7371           val_vnp = prp->activity;
7372           str = val_vnp->data.ptrvalue;
7373         }
7374         break;
7375       case PROTEINFIELD_COMMENT:
7376         if (sfp->idx.subtype == FEATDEF_PROT)
7377         {
7378           str = sfp->comment;
7379         }
7380         break;
7381       case PROTEINFIELD_MATPEPTIDE_NAME:
7382         if (prp != NULL && prp->name != NULL && sfp->idx.subtype == FEATDEF_mat_peptide_aa)
7383         {
7384           val_vnp = prp->name;
7385           str = val_vnp->data.ptrvalue;
7386         }
7387         break;
7388       case PROTEINFIELD_MATPEPTIDE_DESC:
7389         if (sfp->idx.subtype == FEATDEF_mat_peptide_aa && prp != NULL)
7390         {
7391            str = prp->desc;
7392         }
7393         break;
7394       case PROTEINFIELD_MATPEPTIDE_COMMENT:
7395         if (sfp->idx.subtype == FEATDEF_mat_peptide_aa)
7396         {
7397           str = sfp->comment;
7398         }
7399         break;
7400     }
7401     vnp = vnp->next;
7402   }
7403   if (StringHasNoText (str))
7404   {
7405     str = NULL;
7406   }
7407   else
7408   {
7409     str = StringSave (str);
7410   }
7411   return str;
7412 }
7413 
7414 static void RemoveProteinFieldString (SeqFeatPtr sfp, ValNodePtr protein_field)
7415 {
7416   ValNodePtr vnp;
7417   ProtRefPtr prp = NULL;
7418   Int4       field_choice;
7419   SeqFeatXrefPtr xref = NULL, prev;
7420   
7421   if (sfp == NULL || protein_field == NULL)
7422   {
7423     return;
7424   }
7425   
7426   vnp = protein_field;
7427   if (sfp->idx.subtype == FEATDEF_PROT
7428       || sfp->idx.subtype == FEATDEF_mat_peptide_aa) {
7429       prp = (ProtRefPtr) sfp->data.value.ptrvalue;
7430   } else if (sfp->idx.subtype == FEATDEF_CDS) {
7431       xref = sfp->xref;
7432       while (xref != NULL && xref->data.choice != SEQFEAT_PROT) {
7433           xref = xref->next;
7434       }
7435       if (xref != NULL) {
7436           prp = xref->data.value.ptrvalue;
7437       }
7438   }      
7439 
7440   while (vnp != NULL && vnp->data.intvalue != FEATUREFIELD_NONE)
7441   {
7442     field_choice = vnp->data.intvalue;
7443     switch (field_choice)
7444     {
7445       case PROTEINFIELD_NAME:
7446         if (prp != NULL && prp->name != NULL && sfp->idx.subtype == FEATDEF_PROT)
7447         {
7448           prp->name = ValNodeFreeData (prp->name);
7449         }
7450         break;
7451       case PROTEINFIELD_DESC:
7452         if (prp != NULL && sfp->idx.subtype == FEATDEF_PROT)
7453         {
7454           prp->desc = MemFree (prp->desc);
7455         }
7456         break;
7457       case PROTEINFIELD_EC_NUM:
7458         if (prp != NULL && prp->ec != NULL && sfp->idx.subtype == FEATDEF_PROT)
7459         {
7460           prp->ec = ValNodeFreeData (prp->ec);
7461         }
7462         break;
7463       case PROTEINFIELD_ACTIVITY:
7464         if (prp != NULL && prp->activity != NULL && sfp->idx.subtype == FEATDEF_PROT)
7465         {
7466           prp->activity = ValNodeFreeData (prp->activity);
7467         }
7468         break;
7469       case PROTEINFIELD_COMMENT:
7470         if (sfp->idx.subtype == FEATDEF_PROT)
7471         {
7472           sfp->comment = MemFree (sfp->comment);
7473         }
7474         break;
7475       case PROTEINFIELD_MATPEPTIDE_NAME:
7476         if (prp != NULL && prp->name != NULL && sfp->idx.subtype == FEATDEF_mat_peptide_aa)
7477         {
7478           prp->name = ValNodeFreeData (prp->name);
7479         }
7480         break;
7481       case PROTEINFIELD_MATPEPTIDE_DESC:
7482         if (prp != NULL && sfp->idx.subtype == FEATDEF_mat_peptide_aa)
7483         {
7484           prp->desc = MemFree (prp->desc);
7485         }
7486         break;
7487       case PROTEINFIELD_MATPEPTIDE_COMMENT:
7488         if (sfp->idx.subtype == FEATDEF_mat_peptide_aa)
7489         {
7490           sfp->comment = MemFree (sfp->comment);
7491         }
7492         break;
7493     }
7494     vnp = vnp->next;
7495   }
7496   
7497   /* remove protein xref if empty */
7498   if (prp != NULL && xref != NULL
7499       && prp->name == NULL
7500       && StringHasNoText (prp->desc)
7501       && prp->ec == NULL
7502       && prp->activity == NULL
7503       && prp->db == NULL) {
7504     prp = ProtRefFree(prp);
7505     xref->data.value.ptrvalue = NULL;
7506     if (sfp->xref == xref) {
7507         sfp->xref = xref->next;
7508     } else {
7509         prev = sfp->xref;
7510         while (prev != NULL && prev->next != xref) {
7511             prev = prev->next;
7512         }
7513         if (prev != NULL) {
7514             prev->next = xref->next;
7515         }
7516     }
7517     xref = SeqFeatXrefFree(xref);
7518   }      
7519 }
7520 
7521 extern ValNodePtr ApplyValueToValNodeStringListAsText (ValNodePtr list, Int2 choice, ApplyValuePtr avp);
7522 
7523 static void SetProteinFieldString (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
7524 {
7525   ProtRefPtr    prp;
7526   ApplyValuePtr avp;
7527   
7528   if (sfp == NULL || userdata == NULL)
7529   {
7530     return;
7531   }
7532   if (sfp->idx.subtype != FEATDEF_PROT && sfp->idx.subtype != FEATDEF_mat_peptide_aa)
7533   {
7534     return;
7535   }
7536   
7537   avp = (ApplyValuePtr) userdata;
7538   if (avp->field_list == NULL)
7539   {
7540     return;
7541   }
7542 
7543   if (sfp->idx.subtype == FEATDEF_PROT)
7544   {
7545     if (avp->field_list->data.intvalue == PROTEINFIELD_MATPEPTIDE_NAME
7546         || avp->field_list->data.intvalue == PROTEINFIELD_MATPEPTIDE_DESC
7547         || avp->field_list->data.intvalue == PROTEINFIELD_MATPEPTIDE_COMMENT)
7548     {
7549       return;
7550     }
7551   }
7552   else if (sfp->idx.subtype == FEATDEF_mat_peptide_aa)
7553   {
7554     if (avp->field_list->data.intvalue != PROTEINFIELD_MATPEPTIDE_NAME
7555         && avp->field_list->data.intvalue != PROTEINFIELD_MATPEPTIDE_DESC
7556         && avp->field_list->data.intvalue != PROTEINFIELD_MATPEPTIDE_COMMENT)
7557     {
7558       return;
7559     }
7560   }
7561   else    
7562   {
7563     return; 
7564   }
7565   
7566   prp = (ProtRefPtr) sfp->data.value.ptrvalue;
7567   if (prp == NULL)
7568   {
7569     prp = ProtRefNew ();
7570     if (prp == NULL)
7571     {
7572       return;
7573     }
7574     sfp->data.value.ptrvalue = prp;
7575   }
7576   
7577   switch (avp->field_list->data.intvalue)
7578   {
7579     case PROTEINFIELD_NAME:
7580     case PROTEINFIELD_MATPEPTIDE_NAME:
7581       if (prp->name == NULL || !StringHasNoText(avp->text_to_replace))
7582       {
7583         prp->name = ApplyValueToValNodeStringList (prp->name, 0, avp);
7584       }
7585       else
7586       {
7587         prp->name->data.ptrvalue = HandleApplyValue (prp->name->data.ptrvalue, avp);
7588       }
7589       break;
7590     case PROTEINFIELD_DESC:
7591     case PROTEINFIELD_MATPEPTIDE_DESC:
7592       prp->desc = HandleApplyValue (prp->desc, avp);
7593       break;
7594     case PROTEINFIELD_EC_NUM:
7595       prp->ec = ApplyValueToValNodeStringListAsText (prp->ec, 0, avp);
7596       break;
7597     case PROTEINFIELD_ACTIVITY:
7598       if (prp->activity == NULL || !StringHasNoText(avp->text_to_replace))
7599       {
7600         prp->activity = ApplyValueToValNodeStringList (prp->activity, 0, avp);
7601       }
7602       else
7603       {
7604         prp->activity->data.ptrvalue = HandleApplyValue (prp->activity->data.ptrvalue, avp);
7605       }
7606       break;
7607     case PROTEINFIELD_COMMENT:
7608     case PROTEINFIELD_MATPEPTIDE_COMMENT:
7609       sfp->comment = HandleApplyValue (sfp->comment, avp);
7610       break;
7611   }
7612 }
7613 
7614 static CharPtr PNTR BuildCDSGeneFieldList (Int4Ptr num_fields)
7615 {
7616   CharPtr PNTR field_name_list;
7617   Int4         i, k;
7618   Char         tmp[100];
7619 
7620   if (num_fields == NULL) 
7621   {
7622     return NULL;
7623   }
7624   *num_fields = 1 + num_gene_fields + num_mrna_fields + num_protein_fields;
7625   field_name_list = (CharPtr PNTR) MemNew (*num_fields * sizeof (CharPtr));
7626   if (field_name_list == NULL)
7627   {
7628     return NULL;
7629   }
7630   
7631   field_name_list [0] = StringSave ("CDS comment");
7632   k = 1;
7633   for (i = 0; i < num_gene_fields; i++)
7634   {
7635     sprintf (tmp, "Gene %s", gene_field_list [i]);
7636     field_name_list [k++] = StringSave (tmp);
7637   }
7638   for (i = 0; i < num_mrna_fields; i++)
7639   {
7640     sprintf (tmp, "mRNA %s", mrna_field_list [i]);
7641     field_name_list [k++] = StringSave (tmp);
7642   }
7643   for (i = 0; i < num_protein_fields; i++)
7644   {
7645     if (StringNCmp (protein_field_list [i], "mat_peptide", 11) == 0)
7646     {
7647       sprintf (tmp, "%s", protein_field_list [i]);
7648       tmp [0] = toupper (tmp [0]);
7649     }
7650     else
7651     {
7652       sprintf (tmp, "Protein %s", protein_field_list [i]);
7653     }
7654     field_name_list [k++] = StringSave (tmp);
7655   }
7656   return field_name_list;  
7657 }
7658 
7659 static void FreeCDSGeneFieldList (CharPtr PNTR field_name_list, Int4 num_fields)
7660 {
7661   Int4 i;
7662   
7663   if (field_name_list == NULL || num_fields == 0)
7664   {
7665     return;
7666   }
7667   
7668   for (i = 0; i < num_fields; i++)
7669   {
7670     field_name_list [i] = MemFree (field_name_list [i]);
7671   }
7672   field_name_list = MemFree (field_name_list);
7673 }
7674 
7675 extern DialoG 
7676 CDSGeneProtFieldSelectionDialog
7677 (GrouP                    h,
7678  Boolean                  allow_none,
7679  Nlm_ChangeNotifyProc     change_notify,
7680  Pointer                  change_userdata)
7681 {
7682   CharPtr PNTR field_name_list;
7683   Int4         num_fields = 0;
7684   DialoG       d;
7685 
7686   field_name_list = BuildCDSGeneFieldList (&num_fields);
7687   
7688   d = FeatureFieldSelectionDialog (h, allow_none,
7689                                       num_fields, field_name_list, 
7690                                       change_notify, change_userdata);
7691   FreeCDSGeneFieldList (field_name_list, num_fields);
7692   return d;
7693 }
7694 
7695 static DialoG
7696 CDSGeneProtFieldConstraintSelectionDialog
7697 (GrouP                    h,
7698  Boolean                  allow_none,
7699  Nlm_ChangeNotifyProc     change_notify,
7700  Pointer                  change_userdata)
7701 {
7702   CharPtr PNTR field_name_list;
7703   Int4         num_fields = 0;
7704   DialoG       d;
7705 
7706   field_name_list = BuildCDSGeneFieldList (&num_fields);
7707   
7708   d = FeatureFieldSelectionDialogAny (h, allow_none,
7709                                       num_fields, field_name_list, 
7710                                       change_notify, change_userdata);
7711   FreeCDSGeneFieldList (field_name_list, num_fields);
7712   return d; 
7713 }
7714 
7715 
7716 extern Boolean IsCDSetProteinProductChoice (ValNodePtr vnp)
7717 {
7718   if (vnp != NULL && vnp->data.intvalue == 2 + num_gene_fields + num_mrna_fields) {
7719     return TRUE;
7720   } else {
7721     return FALSE;
7722   }
7723 }
7724 
7725 
7726 static Boolean IsCDSetProteinQualChoice (ValNodePtr vnp)
7727 {
7728   if (vnp != NULL 
7729       && vnp->data.intvalue > 1 + num_gene_fields + num_mrna_fields
7730       && vnp->data.intvalue <= 1 + num_gene_fields + num_mrna_fields + num_protein_fields) 
7731   {
7732     return TRUE;
7733   } 
7734   else 
7735   {
7736     return FALSE;
7737   }
7738 }
7739 
7740 static Boolean IsCDSetMatPeptideQualChoice (ValNodePtr vnp)
7741 {
7742   if (IsCDSetProteinQualChoice (vnp)
7743       && StringNICmp (protein_field_list[vnp->data.intvalue - num_gene_fields - num_mrna_fields - 2],
7744                       "mat_peptide", 11) == 0) 
7745   {
7746     return TRUE;
7747   }
7748   else
7749   {
7750     return FALSE;
7751   } 
7752 }
7753 
7754 static Boolean IsCDSetMRNAQualChoice (ValNodePtr vnp)
7755 {
7756   if (vnp != NULL 
7757       && vnp->data.intvalue > 1 + num_gene_fields
7758       && vnp->data.intvalue <= 1 + num_gene_fields + num_mrna_fields) 
7759   {
7760     return TRUE;
7761   }
7762   else
7763   {
7764     return FALSE;
7765   }
7766 }
7767 
7768 static Boolean IsCDSetGeneQualChoice (ValNodePtr vnp)
7769 {
7770   if (vnp != NULL 
7771       && vnp->data.intvalue > 1
7772       && vnp->data.intvalue <= 1 + num_gene_fields)
7773   {
7774     return TRUE;
7775   }
7776   else
7777   {
7778     return FALSE;
7779   }
7780 }
7781 
7782 static Boolean IsCDSetCDSQualChoice (ValNodePtr vnp)
7783 {
7784   if (vnp != NULL && vnp->data.intvalue == 1) 
7785   {
7786     return TRUE;
7787   }
7788   else
7789   {
7790     return FALSE;
7791   }
7792 }
7793 
7794 extern CharPtr GetCDSGeneProtField (SeqFeatPtr sfp, ValNodePtr vnp, FilterSetPtr fsp)
7795 {
7796   CharPtr str = NULL;
7797   ValNode vn;
7798   Int4    field_choice;
7799   
7800   if (sfp == NULL || vnp == NULL)
7801   {
7802     return NULL;
7803   }
7804   
7805   while (vnp != NULL && str == NULL)
7806   {
7807     vn.choice = vnp->choice;
7808     vn.next = NULL;
7809     
7810     field_choice = vnp->data.intvalue;
7811   
7812     if (IsCDSetCDSQualChoice(vnp))
7813     {
7814       /* CDS Comment */
7815       str = GetCDSComment (sfp, NULL, NULL);
7816     }
7817     else if (IsCDSetGeneQualChoice (vnp))
7818     {
7819       vn.data.intvalue = vnp->data.intvalue - 1;
7820       str = GetGeneFieldString (sfp, &vn, NULL);
7821     }
7822     else if (IsCDSetMRNAQualChoice (vnp))
7823     {
7824       vn.data.intvalue = vnp->data.intvalue - num_gene_fields - 1;
7825       str = GetmRNAFieldString (sfp, &vn, NULL);
7826     }
7827     else if (IsCDSetProteinQualChoice (vnp))
7828     {
7829       vn.data.intvalue = vnp->data.intvalue - num_gene_fields - num_mrna_fields - 1;
7830       str = GetProteinFieldString (sfp, &vn, NULL);
7831     }
7832     vnp = vnp->next;
7833   }
7834   return str;
7835 }
7836 
7837 /* we could have multiple mat_peptides in a CDSset, some that match the constraint and some that do not */
7838 static Boolean DoesConstraintDisqualifyFeature (SeqFeatPtr sfp, ChoiceConstraintPtr ccp)
7839 {
7840   Boolean is_disqualified = FALSE;
7841   Boolean does_match = FALSE;
7842   CharPtr str;
7843 
7844   if (sfp == NULL || ccp == NULL 
7845       || ccp->constraint_type == CHOICE_CONSTRAINT_ANY
7846       || sfp->idx.subtype != FEATDEF_mat_peptide_aa 
7847       || !IsCDSetMatPeptideQualChoice(ccp->qual_choice))
7848   {
7849     is_disqualified = FALSE;
7850   }
7851   else if (ccp->constraint_type == CHOICE_CONSTRAINT_QUAL_PRESENT && ccp->qual_choice != NULL)
7852   {
7853     str = GetCDSGeneProtField (sfp, ccp->qual_choice, NULL);
7854     if (str == NULL)
7855     {
7856       is_disqualified = TRUE;
7857     }
7858     MemFree (str);
7859   }
7860   else if (ccp->constraint_type == CHOICE_CONSTRAINT_STRING)
7861   {
7862     str = GetCDSGeneProtField (sfp, ccp->qual_choice, NULL);
7863     does_match = DoesStringMatchConstraintX (str, ccp->string_constraint);
7864     MemFree (str);
7865     if (ccp->string_constraint != NULL && ccp->string_constraint->not_present)
7866     {
7867       does_match = ! does_match;
7868     }
7869     if (!does_match)
7870     {
7871       is_disqualified = TRUE;
7872     }
7873   }
7874   return is_disqualified;
7875 
7876 }
7877 
7878 extern void RemoveCDSGeneProtField (SeqFeatPtr sfp, ValNodePtr vnp, FilterSetPtr fsp)
7879 {
7880   ValNode vn;
7881   
7882   if (sfp == NULL || vnp == NULL)
7883   {
7884     return;
7885   }
7886 
7887   if (fsp != NULL && fsp->cgp != NULL && DoesConstraintDisqualifyFeature (sfp, fsp->cgp)) 
7888   {
7889     return;
7890   }
7891   
7892   while (vnp != NULL)
7893   {
7894     vn.choice = vnp->choice;
7895     vn.next = NULL;
7896   
7897     if (vnp->data.intvalue == 1)
7898     {
7899       /* CDS Comment */
7900       RemoveCDSComment (sfp, NULL);
7901     }
7902     else if (vnp->data.intvalue <= 1 + num_gene_fields)
7903     {
7904       vn.data.intvalue = vnp->data.intvalue - 1;
7905       RemoveGeneFieldString (sfp, &vn);
7906     }
7907     else if (vnp->data.intvalue <= 1 + num_gene_fields + num_mrna_fields)
7908     {
7909       vn.data.intvalue = vnp->data.intvalue - num_gene_fields - 1;
7910       RemovemRNAFieldString (sfp, &vn);
7911     }
7912     else if (vnp->data.intvalue <= 1 + num_gene_fields + num_mrna_fields + num_protein_fields)
7913     {
7914       vn.data.intvalue = vnp->data.intvalue - num_gene_fields - num_mrna_fields - 1;
7915       RemoveProteinFieldString (sfp, &vn);
7916     }
7917     vnp = vnp->next;
7918   }
7919 }
7920 
7921 
7922 extern Uint2 FeatDefTypeFromFieldList (ValNodePtr vnp)
7923 {
7924   if (vnp == NULL) 
7925   {
7926     return 0;
7927   }
7928   else if (IsCDSetCDSQualChoice(vnp))
7929   {
7930     return FEATDEF_CDS;
7931   }
7932   else if (IsCDSetGeneQualChoice (vnp))
7933   {
7934     return FEATDEF_GENE;
7935   }
7936   else if (IsCDSetMRNAQualChoice(vnp))
7937   {
7938     return FEATDEF_mRNA;
7939   }
7940   else if (IsCDSetProteinQualChoice (vnp))
7941   {
7942     if (IsCDSetMatPeptideQualChoice (vnp))
7943     {
7944       return FEATDEF_mat_peptide_aa;
7945     }
7946     else
7947     {
7948       return FEATDEF_PROT;
7949     }
7950   }
7951   else
7952   {
7953     return 0;
7954   }
7955 }
7956 
7957 
7958 /* return TRUE if actually set field, FALSE otherwise */
7959 extern Boolean 
7960 SetCDSGeneProtField 
7961 (SeqFeatPtr      sfp,
7962  ValNodePtr      vnp, 
7963  ApplyValuePtr   avp,
7964  FilterSetPtr    fsp)
7965 {
7966   ValNode        vn;
7967   ApplyValueData local_avd;
7968   Uint2          choice;
7969   
7970   if (sfp == NULL || vnp == NULL || avp == NULL)
7971   {
7972     return FALSE;
7973   }
7974 
7975   choice = FeatDefTypeFromFieldList (vnp);
7976   if (FindFeatFromFeatDefType(choice) != sfp->data.choice)
7977   {
7978     return FALSE;
7979   }
7980 
7981   if (fsp != NULL && fsp->cgp != NULL && DoesConstraintDisqualifyFeature (sfp, fsp->cgp)) 
7982   {
7983     return FALSE;
7984   }
7985   
7986   vn.choice = vnp->choice;
7987   vn.next = NULL;
7988   local_avd.field_list = &vn;
7989   local_avd.new_text = avp->new_text;
7990   local_avd.etp = avp->etp;
7991   local_avd.text_to_replace = avp->text_to_replace;
7992   local_avd.where_to_replace = avp->where_to_replace;
7993 
7994   if (vnp->data.intvalue == 1)
7995   {
7996     /* CDS Comment */
7997     SetCDSComment (sfp, &local_avd, NULL);
7998   }
7999   else if (vnp->data.intvalue <= 1 + num_gene_fields)
8000   {
8001     vn.data.intvalue = vnp->data.intvalue - 1;
8002     SetGeneFieldString (sfp, &local_avd, NULL);
8003   }
8004   else if (vnp->data.intvalue <= 1 + num_gene_fields + num_mrna_fields)
8005   {
8006     vn.data.intvalue = vnp->data.intvalue - num_gene_fields - 1;
8007     SetmRNAFieldString (sfp, &local_avd, NULL);
8008   }
8009   else if (vnp->data.intvalue <= 1 + num_gene_fields + num_mrna_fields + num_protein_fields)
8010   {
8011     vn.data.intvalue = vnp->data.intvalue - num_gene_fields - num_mrna_fields - 1;
8012     SetProteinFieldString (sfp, &local_avd, NULL);
8013   }
8014   
8015   /* no need to free any part of local_avd */
8016 
8017   return TRUE;
8018 }
8019 
8020 #define RNAFIELD_PRODUCT           1
8021 #define RNAFIELD_COMMENT           2
8022 #define RNAFIELD_CODONS_RECOGNIZED 3
8023 #define RNAFIELD_NCRNA_CLASS       4
8024 #define RNAFIELD_ANTICODON         5
8025 #define RNAFIELD_TRANSCRIPT_ID     6
8026 
8027 static CharPtr rna_field_list [] = 
8028 {
8029   "Product", "Comment", "Codons Recognized", "ncRNA class", "Anticodon", "Transcript ID"
8030 };
8031 
8032 static Int4 num_rna_fields = sizeof (rna_field_list) / sizeof (CharPtr);
8033 
8034 static CharPtr GetRNAFieldName (ValNodePtr vnp)
8035 {
8036   CharPtr label = NULL;
8037   
8038   if (vnp != NULL && vnp->data.intvalue >= 1)
8039   {
8040     if (vnp->data.intvalue <= num_rna_fields)
8041     {
8042       label = StringSave (rna_field_list [vnp->data.intvalue - 1]);
8043     }
8044     else if (vnp->data.intvalue <= num_rna_fields + num_gene_fields)
8045     {
8046       label = (CharPtr) MemNew ((StringLen (gene_field_list [vnp->data.intvalue - 1 - num_rna_fields]) + 6) * sizeof (Char));
8047       if (label != NULL)
8048       {
8049         sprintf (label, "Gene %s", gene_field_list [vnp->data.intvalue - 1 - num_rna_fields]);
8050       }
8051     }
8052   }
8053   return label;
8054 }
8055 
8056 extern DialoG
8057 RNAAddFieldSelectionDialog
8058 (GrouP                    h,
8059  Boolean                  allow_multi,
8060  Nlm_ChangeNotifyProc     change_notify,
8061  Pointer                  change_userdata)
8062 {
8063   ValNodePtr choice_list = NULL;
8064   DialoG     dlg;
8065   Int4       i;
8066   
8067   for (i = 0; i < 4; i++)
8068   {
8069     ValNodeAddInt (&choice_list, 0, i + 1);
8070   }
8071   for (i = 0; i < num_gene_fields; i++)
8072   {
8073     ValNodeAddInt (&choice_list, 0, i + num_rna_fields + 1);
8074   }
8075 
8076   dlg = ValNodeSelectionDialog (h, choice_list, TALL_SELECTION_LIST,
8077                                 GetRNAFieldName, NULL, 
8078                                 IntValNodeCopy, IntValNodeMatch,
8079                                 "RNA field", change_notify, change_userdata, 
8080                                 FALSE);
8081                                 
8082   return dlg;
8083 }
8084 
8085 extern DialoG
8086 RNARemoveFieldSelectionDialog
8087 (GrouP                    h,
8088  Boolean                  allow_multi,
8089  Nlm_ChangeNotifyProc     change_notify,
8090  Pointer                  change_userdata)
8091 {
8092   ValNodePtr choice_list = NULL;
8093   DialoG     dlg;
8094   Int4       i;
8095   
8096   for (i = 0; i < num_rna_fields; i++)
8097   {
8098     ValNodeAddInt (&choice_list, 0, i + 1);
8099   }
8100   for (i = 0; i < num_gene_fields; i++)
8101   {
8102     ValNodeAddInt (&choice_list, 0, i + num_rna_fields + 1);
8103   }
8104 
8105   dlg = ValNodeSelectionDialog (h, choice_list, TALL_SELECTION_LIST,
8106                                 GetRNAFieldName, NULL, 
8107                                 IntValNodeCopy, IntValNodeMatch,
8108                                 "RNA field", change_notify, change_userdata, 
8109                                 FALSE);
8110 
8111   return dlg;
8112 }
8113 
8114 extern DialoG
8115 RNAFieldSelectionDialog
8116 (GrouP                    h,
8117  Boolean                  allow_multi,
8118  Nlm_ChangeNotifyProc     change_notify,
8119  Pointer                  change_userdata)
8120 {
8121   ValNodePtr choice_list = NULL;
8122   DialoG     dlg;
8123   Int4       i;
8124   
8125   for (i = 0; i < 4; i++)
8126   {
8127     ValNodeAddInt (&choice_list, 0, i + 1);
8128   }
8129   for (i = 0; i < num_gene_fields; i++)
8130   {
8131     ValNodeAddInt (&choice_list, 0, i + num_rna_fields + 1);
8132   }
8133 
8134   dlg = ValNodeSelectionDialog (h, choice_list, TALL_SELECTION_LIST,
8135                                 GetRNAFieldName, NULL, 
8136                                 IntValNodeCopy, IntValNodeMatch,
8137                                 "RNA field", change_notify, change_userdata, 
8138                                 FALSE);
8139                                 
8140   return dlg;
8141 }
8142 
8143 static CharPtr rna_subtype_list [] = { "misc_RNA", "preRna", "mRNA", "tRNA",
8144                                         "rRNA", "ncRNA", "tmRNA"};
8145 static Int2    num_rna_subtypes = sizeof (rna_subtype_list) / sizeof (CharPtr); 
8146 
8147 static CharPtr GetRNASubtypeName (ValNodePtr vnp)
8148 {
8149   CharPtr label = NULL;
8150   
8151   if (vnp != NULL && vnp->choice < num_rna_subtypes)
8152   {
8153     label = StringSave (rna_subtype_list[vnp->choice]);
8154   }
8155   return label;
8156 }
8157 
8158 static DialoG RNASubtypeSelectionDialog
8159 (GrouP                    h,
8160  Boolean                  allow_multi,
8161  SeqEntryPtr              sep,
8162  Nlm_ChangeNotifyProc     change_notify,
8163  Pointer                  change_userdata)
8164 {
8165   ValNodePtr choice_list = NULL;
8166   DialoG     dlg;
8167   
8168   ValNodeAddInt (&choice_list, 0, FEATDEF_otherRNA);
8169   ValNodeAddInt (&choice_list, 1, FEATDEF_preRNA);
8170   ValNodeAddInt (&choice_list, 2, FEATDEF_mRNA);
8171   ValNodeAddInt (&choice_list, 3, FEATDEF_tRNA);
8172   ValNodeAddInt (&choice_list, 4, FEATDEF_rRNA);
8173   ValNodeAddInt (&choice_list, 5, FEATDEF_ncRNA);
8174   ValNodeAddInt (&choice_list, 6, FEATDEF_tmRNA);
8175 
8176   dlg = ValNodeSelectionDialog (h, choice_list, TALL_SELECTION_LIST,
8177                                 GetRNASubtypeName, NULL, 
8178                                 IntValNodeCopy, IntValNodeMatch,
8179                                 "RNA subtype", change_notify, change_userdata, 
8180                                 allow_multi);
8181   return dlg;
8182 }
8183 
8184 
8185 static CharPtr GetRNAProductString (SeqFeatPtr sfp)
8186 {
8187   RnaRefPtr  rrp;
8188   SeqMgrFeatContext context;
8189   CharPtr    str = NULL;
8190   GBQualPtr  gbqual;
8191 
8192   if (sfp == NULL || sfp->data.choice != SEQFEAT_RNA || sfp->data.value.ptrvalue == NULL)
8193   {
8194     return NULL;
8195   }
8196 
8197   rrp = sfp->data.value.ptrvalue;
8198   if (rrp->ext.choice == 0 
8199       || (rrp->ext.choice == 1 && StringHasNoText (rrp->ext.value.ptrvalue))
8200       || (rrp->ext.choice == 1 
8201           && (StringCmp (rrp->ext.value.ptrvalue, "ncRNA") == 0 
8202               || StringCmp (rrp->ext.value.ptrvalue, "tmRNA") == 0
8203               || StringCmp (rrp->ext.value.ptrvalue, "misc_RNA") == 0)))
8204   {
8205     gbqual = sfp->qual;
8206     while (gbqual != NULL && str == NULL) {
8207     if (StringICmp (gbqual->qual, "product") == 0
8208         && !StringHasNoText (gbqual->val)) 
8209     {
8210       str = StringSave (gbqual->val);
8211       }
8212       gbqual = gbqual->next;
8213     }
8214   }
8215 
8216   if (str == NULL)
8217   {
8218     if (rrp->ext.choice == 1 && !StringHasNoText (rrp->ext.value.ptrvalue)
8219         && StringCmp (rrp->ext.value.ptrvalue, "ncRNA") != 0
8220         && StringCmp (rrp->ext.value.ptrvalue, "tmRNA") != 0
8221         && StringCmp (rrp->ext.value.ptrvalue, "misc_RNA") != 0)
8222     {
8223       str = StringSave (rrp->ext.value.ptrvalue);        
8224     }
8225     else if (rrp->ext.choice == 2 && rrp->ext.value.ptrvalue != NULL)
8226     {
8227       if (SeqMgrGetDesiredFeature (sfp->idx.entityID, NULL, 0, 0, sfp, &context) != NULL
8228           && !StringHasNoText (context.label)
8229           && StringCmp (context.label, "tRNA") != 0)
8230       {
8231         str = (CharPtr) MemNew (sizeof (Char) + (StringLen (context.label) + 6));
8232         sprintf (str, "tRNA-%s", context.label);
8233       }
8234     }
8235   }
8236   return str;
8237 }
8238 
8239 extern CharPtr GetRNAFieldString (SeqFeatPtr sfp, ValNodePtr vnp, FilterSetPtr fsp)
8240 {
8241   RnaRefPtr  rrp;
8242   CharPtr    str = NULL;
8243   ValNode    vn;
8244   GeneRefPtr grp;
8245   SeqFeatPtr gene;
8246   SeqMgrFeatContext context;
8247   Int4              field_choice;
8248   GBQualPtr         qual;
8249   
8250   if (sfp == NULL || sfp->data.choice != SEQFEAT_RNA || vnp == NULL)
8251   {
8252     return NULL;
8253   }
8254   
8255   rrp = sfp->data.value.ptrvalue;
8256   
8257   while (vnp != NULL && str == NULL)
8258   {
8259     field_choice = vnp->data.intvalue;
8260     switch (vnp->data.intvalue)
8261     {
8262       case RNAFIELD_PRODUCT :        
8263         str = GetRNAProductString (sfp);
8264         break;
8265       case RNAFIELD_COMMENT :
8266         if (!StringHasNoText (sfp->comment))
8267         {
8268           str = StringSave (sfp->comment);
8269         }
8270         break;
8271       case RNAFIELD_NCRNA_CLASS :
8272         for (qual = sfp->qual; qual != NULL && str == NULL; qual = qual->next)
8273         {
8274           if (StringCmp (qual->qual, "ncRNA_class") == 0
8275               && !StringHasNoText (qual->val))
8276           {
8277             str = StringSave (qual->val);
8278           }
8279         }
8280         break;
8281       default:
8282         if (vnp->data.intvalue >= num_rna_fields + 1)
8283         {
8284           vn.choice = 0;
8285           vn.next = NULL;
8286           vn.data.intvalue = vnp->data.intvalue - num_rna_fields;
8287           grp = SeqMgrGetGeneXref (sfp);
8288           if (grp == NULL)
8289           {
8290             gene = SeqMgrGetOverlappingGene (sfp->location, &context);
8291             str = GetGeneFieldString (gene, &vn, NULL);
8292           }
8293           else
8294           {
8295             str = GetGeneFieldString (sfp, &vn, NULL);
8296           }
8297         }
8298         break;
8299           
8300     }
8301     vnp = vnp->next;
8302   }
8303   return str;
8304 }
8305 
8306 
8307 static Boolean IsParseabletRNAName (CharPtr name_string)
8308 {
8309   if (StringHasNoText(name_string)) 
8310   {
8311     return TRUE;
8312   }
8313   else if (StringNICmp (name_string, "trna-", 5) != 0)
8314   {
8315     return FALSE;
8316   }
8317   else if (StringLen (name_string) != 8)
8318   {
8319     return FALSE;
8320   }
8321   else if (ParseTRnaString (name_string, NULL, NULL, TRUE) == 0)
8322   {
8323     return FALSE;
8324   }
8325   else
8326   {
8327     return TRUE;
8328   }
8329 }
8330 
8331 
8332 static void SettRNAName (SeqFeatPtr sfp, ApplyValuePtr avp)
8333 {
8334   RnaRefPtr     rrp;
8335   tRNAPtr           trp;
8336   Uint1             new_aa;
8337   CharPtr           name_string;
8338   Boolean           justTrnaText = FALSE;
8339   Uint1             codon [6];
8340   GBQualPtr         gbqual, gbqual_last = NULL;
8341 
8342   if (sfp == NULL || sfp->data.value.ptrvalue == NULL 
8343       || sfp->idx.subtype != FEATDEF_tRNA
8344       || avp == NULL)
8345   {
8346     return;
8347   }
8348   
8349   rrp = sfp->data.value.ptrvalue;
8350   if (rrp->ext.choice == 0)
8351   {
8352     trp = MemNew (sizeof (tRNA));
8353     trp->aatype = 0;
8354     MemSet (trp->codon, 255, sizeof (trp->codon));
8355     trp->anticodon = NULL;
8356     rrp->ext.value.ptrvalue = trp;
8357     rrp->ext.choice = 2;
8358   }
8359   if (rrp->ext.choice != 2)
8360   {
8361     return;
8362   }
8363   trp = (tRNAPtr) rrp->ext.value.ptrvalue;
8364   
8365   name_string = GetRNAProductString (sfp);
8366   name_string = HandleApplyValue (name_string, avp);
8367   if (!IsParseabletRNAName(name_string))
8368   {
8369     if (trp->anticodon == NULL
8370         && trp->codon[0] == 255
8371         && trp->codon[1] == 255
8372         && trp->codon[2] == 255
8373         && trp->codon[3] == 255
8374         && trp->codon[4] == 255
8375         && trp->codon[5] == 255)
8376     {
8377       trp = MemFree (trp);
8378       rrp->ext.choice = 1;
8379       rrp->ext.value.ptrvalue = name_string;
8380     }
8381     else
8382     {
8383       trp->aa = 0;
8384       gbqual = sfp->qual;
8385       while (gbqual != NULL)
8386       {
8387         gbqual_last = gbqual;
8388         gbqual = gbqual->next;
8389       }
8390       gbqual = GBQualNew ();
8391       gbqual->qual = StringSave ("product");
8392       gbqual->val = name_string;
8393       if (gbqual_last == NULL)
8394       {
8395         sfp->qual = gbqual;
8396       }
8397       else
8398       {
8399         gbqual->next = gbqual_last->next;
8400         gbqual_last->next = gbqual;
8401       }
8402     }
8403   }
8404   else
8405   {
8406     new_aa = ParseTRnaString (name_string, &justTrnaText, codon, TRUE);
8407     trp->aa = new_aa;
8408     trp->aatype = 2;
8409     name_string = MemFree (name_string);
8410   }
8411 }
8412 
8413 
8414 static void SetRNAProduct (SeqFeatPtr sfp, ApplyValuePtr avp)
8415 {
8416   RnaRefPtr rrp;
8417   GBQualPtr gbq, prev_gbq = NULL;
8418 
8419   if (sfp == NULL || sfp->data.choice != SEQFEAT_RNA || sfp->data.value.ptrvalue == NULL || avp == NULL)
8420   {
8421     return;
8422   }
8423 
8424   rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
8425 
8426   gbq = sfp->qual;
8427   while (gbq != NULL && StringCmp (gbq->qual, "product") != 0)
8428   {
8429     prev_gbq = gbq;
8430     gbq = gbq->next;
8431   }
8432   if (gbq != NULL)
8433   {
8434     gbq->val = HandleApplyValue (gbq->val, avp);
8435     if (StringHasNoText (gbq->val))
8436     {
8437       if (prev_gbq == NULL)
8438       {
8439         sfp->qual = gbq->next;
8440       }
8441       else
8442       {
8443         prev_gbq->next = gbq->next;
8444       }
8445       gbq->next = NULL;
8446       gbq = GBQualFree (gbq);
8447     }
8448   }
8449   else if (sfp->idx.subtype == FEATDEF_tRNA || rrp->ext.choice == 2)
8450   {
8451     SettRNAName (sfp, avp);
8452   }
8453   else if (rrp->ext.choice == 1
8454            && (StringCmp (rrp->ext.value.ptrvalue, "ncRNA") == 0
8455                || StringCmp (rrp->ext.value.ptrvalue, "tmRNA") == 0
8456                || StringCmp (rrp->ext.value.ptrvalue, "misc_RNA") == 0))
8457   {
8458     gbq = GBQualNew();
8459     gbq->qual = StringSave ("product");
8460     gbq->val = HandleApplyValue (gbq->val, avp);
8461     gbq->next = sfp->qual;
8462     sfp->qual = gbq;
8463   }
8464   else if (rrp->ext.choice == 1 || rrp->ext.choice == 0)
8465   {
8466     rrp->ext.value.ptrvalue = HandleApplyValue (rrp->ext.value.ptrvalue, avp);
8467     if (StringHasNoText (rrp->ext.value.ptrvalue))
8468     {
8469       rrp->ext.value.ptrvalue = MemFree (rrp->ext.value.ptrvalue);
8470       rrp->ext.choice = 0;
8471     }
8472     else
8473     {
8474       rrp->ext.choice = 1;
8475     }
8476   }
8477 }
8478 
8479 
8480 static void SetRNAFieldString (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
8481 {
8482   RnaRefPtr     rrp;
8483   ApplyValuePtr avp;
8484   SeqFeatPtr    gene;
8485   GeneRefPtr    grp;
8486   SeqMgrFeatContext context;
8487   GBQualPtr         qual;
8488   Boolean           found = FALSE;
8489   
8490   if (sfp == NULL || sfp->data.choice != SEQFEAT_RNA || userdata == NULL)
8491   {
8492     return;
8493   }
8494   
8495   avp = (ApplyValuePtr) userdata;
8496   if (avp->field_list == NULL)
8497   {
8498     return;
8499   }
8500 
8501   rrp = sfp->data.value.ptrvalue;
8502     
8503   switch (avp->field_list->data.intvalue)
8504   {
8505     case RNAFIELD_PRODUCT :
8506       SetRNAProduct (sfp, avp);
8507       break;
8508     case RNAFIELD_COMMENT :
8509       sfp->comment = HandleApplyValue (sfp->comment, avp);
8510       break;
8511     case RNAFIELD_NCRNA_CLASS :
8512       for (qual = sfp->qual; qual != NULL; qual = qual->next)
8513       {
8514         if (StringCmp (qual->qual, "ncRNA_class") == 0)
8515         {
8516           qual->val = HandleApplyValue (qual->val, avp);
8517           found = TRUE;
8518         }
8519       }
8520       if (!found)
8521       {
8522         qual = GBQualNew ();
8523         qual->qual = StringSave ("ncRNA_class");
8524         qual->val = StringSave (avp->new_text);
8525         qual->next = sfp->qual;
8526         sfp->qual = qual;
8527       }
8528       break;
8529     default:
8530       if (avp->field_list->data.intvalue >= num_rna_fields + 1)
8531       {
8532         avp->field_list->data.intvalue -= num_rna_fields;
8533         grp = SeqMgrGetGeneXref (sfp);
8534         if (grp == NULL)
8535         {
8536           gene = SeqMgrGetOverlappingGene (sfp->location, &context);
8537           SetGeneFieldString (gene, avp, fsp);
8538         }
8539         else
8540         {
8541           SetGeneFieldString (sfp, avp, fsp);
8542         }
8543         avp->field_list->data.intvalue += num_rna_fields;
8544       }
8545       break;
8546   }
8547 }
8548 
8549 
8550 static void RemoveRNAProduct (SeqFeatPtr sfp)
8551 {
8552   RnaRefPtr rrp;
8553   GBQualPtr gbq, prev_gbq = NULL;
8554   tRNAPtr     trp;
8555 
8556   if (sfp == NULL || sfp->data.choice != SEQFEAT_RNA || sfp->data.value.ptrvalue == NULL)
8557   {
8558     return;
8559   }
8560 
8561   rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
8562 
8563   gbq = sfp->qual;
8564   while (gbq != NULL && StringCmp (gbq->qual, "product") != 0)
8565   {
8566     prev_gbq = gbq;
8567     gbq = gbq->next;
8568   }
8569   if (gbq != NULL)
8570   {
8571     if (prev_gbq == NULL)
8572     {
8573       sfp->qual = gbq->next;
8574     }
8575     else
8576     {
8577       prev_gbq->next = gbq->next;
8578     }
8579     gbq->next = NULL;
8580     gbq = GBQualFree (gbq);
8581   }
8582   else if (rrp->ext.choice == 1
8583            && (StringCmp (rrp->ext.value.ptrvalue, "ncRNA") == 0
8584                || StringCmp (rrp->ext.value.ptrvalue, "tmRNA") == 0
8585                || StringCmp (rrp->ext.value.ptrvalue, "misc_RNA") == 0))
8586   {
8587     /* do nothing - already have no product */
8588   }
8589   else if (rrp->ext.choice == 0)
8590   {
8591     /* do nothing - already have no product */
8592   }
8593   else if (rrp->ext.choice == 1)
8594   {
8595     rrp->ext.value.ptrvalue = MemFree (rrp->ext.value.ptrvalue);
8596     rrp->ext.choice = 0;
8597   }
8598   else if (rrp->ext.choice == 2)
8599   {
8600     trp = (tRNAPtr) rrp->ext.value.ptrvalue;
8601     if (trp != NULL)
8602     {
8603       trp->aatype = 0;
8604     }
8605   }
8606 }
8607 
8608 
8609 static void RemoveRNAField (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
8610 {
8611   RnaRefPtr     rrp;
8612   tRNAPtr       trp;
8613   ApplyValuePtr avp;
8614   SeqFeatPtr    gene;
8615   GeneRefPtr    grp;
8616   ValNode       vn;
8617   SeqMgrFeatContext context;
8618   GBQualPtr         qual, qual_prev = NULL, qual_next;
8619   
8620   if (sfp == NULL || sfp->data.choice != SEQFEAT_RNA || userdata == NULL)
8621   {
8622     return;
8623   }
8624   
8625   avp = (ApplyValuePtr) userdata;
8626   if (avp->field_list == NULL)
8627   {
8628     return;
8629   }
8630   
8631   rrp = sfp->data.value.ptrvalue;
8632 
8633   switch (avp->field_list->data.intvalue)
8634   {
8635     case RNAFIELD_PRODUCT :
8636       RemoveRNAProduct (sfp);
8637       break;
8638     case RNAFIELD_COMMENT :
8639       sfp->comment = MemFree (sfp->comment);
8640       break;
8641     case RNAFIELD_NCRNA_CLASS :
8642       qual = sfp->qual;
8643       while (qual != NULL)
8644       {
8645         qual_next = qual->next;
8646         if (StringCmp (qual->qual, "ncRNA_class") == 0)
8647         {
8648           if (qual_prev == NULL)
8649           {
8650             sfp->qual = qual_next;
8651           }
8652           else
8653           {
8654             qual_prev->next = qual_next;
8655           }
8656           qual->next = NULL;
8657           qual = GBQualFree (qual);
8658         }
8659         else
8660         {
8661           qual_prev = qual;
8662         }
8663         qual = qual_next;
8664       }
8665       break;
8666     case RNAFIELD_ANTICODON :
8667       if (rrp->ext.choice == 2) {
8668         trp = (tRNAPtr) rrp->ext.value.ptrvalue;
8669         if (trp != NULL && trp->anticodon != NULL) {
8670           trp->anticodon = SeqLocFree (trp->anticodon);
8671         }
8672       }
8673       break;
8674     case RNAFIELD_CODONS_RECOGNIZED :
8675       if (rrp->ext.choice == 2) {
8676         trp = (tRNAPtr) rrp->ext.value.ptrvalue;
8677         if (trp != NULL) {
8678           trp->codon [0] = 255;
8679           trp->codon [1] = 255;
8680           trp->codon [2] = 255;
8681           trp->codon [3] = 255;
8682           trp->codon [4] = 255;
8683           trp->codon [5] = 255;
8684         }
8685       }
8686       break;
8687     case RNAFIELD_TRANSCRIPT_ID :
8688       sfp->product = SeqLocFree (sfp->product);
8689       break;
8690     default:
8691       if (avp->field_list->data.intvalue >= num_rna_fields + 1)
8692       {
8693         vn.choice = 1;
8694         vn.next = NULL;
8695         vn.data.intvalue = avp->field_list->data.intvalue - num_rna_fields;
8696         grp = SeqMgrGetGeneXref (sfp);
8697         if (grp == NULL)
8698         {
8699           gene = SeqMgrGetOverlappingGene (sfp->location, &context);
8700           RemoveGeneFieldString (gene, &vn);
8701         }
8702         else
8703         {
8704           RemoveGeneFieldString (sfp, &vn);
8705         }
8706       }
8707       break;
8708   }
8709 }
8710 
8711 typedef struct exonfieldselection 
8712 {
8713   DIALOG_MESSAGE_BLOCK
8714   PopuP                    exon_field;
8715 
8716   Boolean                  allow_none;
8717   Nlm_ChangeNotifyProc     change_notify;
8718   Pointer                  change_userdata;  
8719 } ExonFieldSelectionData, PNTR ExonFieldSelectionPtr;
8720 
8721 #define EXONFIELD_ALLELE            1
8722 #define EXONFIELD_COMMENT           2
8723 #define EXONFIELD_EC_NUMBER         3
8724 #define EXONFIELD_FUNCTION          4
8725 #define EXONFIELD_OLD_LOCUS_TAG     5
8726 #define EXONFIELD_NUMBER            6
8727 #define EXONFIELD_PRODUCT           7
8728 
8729 static CharPtr exon_field_list [] = 
8730 {
8731   "allele", "comment", "EC_number", "function", "old_locus_tag", "number", "product"  
8732 };
8733 #define NUM_EXON_FIELDS 7
8734 
8735 extern DialoG
8736 ExonFieldSelectionDialog
8737 (GrouP                    h,
8738  Boolean                  allow_none,
8739  Nlm_ChangeNotifyProc     change_notify,
8740  Pointer                  change_userdata)
8741 {
8742   return FeatureFieldSelectionDialog (h, allow_none,
8743                                       NUM_EXON_FIELDS, exon_field_list, 
8744                                       change_notify, change_userdata);
8745 
8746 }
8747 
8748 extern CharPtr GetExonFieldString (SeqFeatPtr sfp, ValNodePtr exon_field)
8749 {
8750   ValNodePtr vnp;
8751   CharPtr    str = NULL;
8752   GBQualPtr  gbqual;
8753   
8754   if (sfp == NULL || exon_field == NULL || sfp->idx.subtype != FEATDEF_exon)
8755   {
8756     return NULL;
8757   }
8758   
8759   vnp = exon_field;
8760   while (vnp != NULL && StringHasNoText (str))
8761   {
8762     str = NULL;
8763     if (vnp->data.intvalue == EXONFIELD_COMMENT)
8764     {
8765       str = sfp->comment;
8766     }
8767     else
8768     {
8769       gbqual = sfp->qual;
8770       while (gbqual != NULL && StringHasNoText (str))
8771       {
8772         if (vnp->data.intvalue < NUM_EXON_FIELDS + 1
8773             && vnp->data.intvalue >= 1
8774             && StringCmp (gbqual->qual, exon_field_list[vnp->data.intvalue - 1]) == 0)
8775         {
8776           str = gbqual->val;
8777         }
8778         gbqual = gbqual->next;
8779       }    
8780     }
8781     vnp = vnp->next;
8782   }
8783   if (StringHasNoText (str))
8784   {
8785     str = NULL;
8786   }
8787   else
8788   {
8789     str = StringSave (str);
8790   }
8791   return str;
8792 }
8793 
8794 extern void RemoveExonFieldString (SeqFeatPtr sfp, ValNodePtr exon_field)
8795 {
8796   ValNodePtr vnp;
8797   Boolean    found_nonempty = FALSE;
8798   GBQualPtr  gbqual, prev_qual;
8799   
8800   if (sfp == NULL || exon_field == NULL || sfp->idx.subtype != FEATDEF_exon)
8801   {
8802     return;
8803   }
8804   
8805   vnp = exon_field;
8806   while (vnp != NULL && !found_nonempty)
8807   {
8808     if (vnp->data.intvalue == EXONFIELD_COMMENT)
8809     {
8810       if (!StringHasNoText (sfp->comment))
8811       {
8812         found_nonempty = TRUE;
8813         if (vnp->choice != 0)
8814         {
8815           sfp->comment = MemFree (sfp->comment);
8816         }
8817       }
8818     }
8819     else
8820     {     
8821       gbqual = sfp->qual;
8822       prev_qual = NULL;
8823       while (gbqual != NULL)
8824       {
8825         if (vnp->data.intvalue <= NUM_EXON_FIELDS + 1
8826             && vnp->data.intvalue >= 1
8827             && StringCmp (gbqual->qual, exon_field_list[vnp->data.intvalue - 1]) == 0)
8828         {
8829            if (!StringHasNoText (gbqual->val))
8830            {
8831             found_nonempty = TRUE;
8832             if (vnp->choice != 0)
8833             {
8834               if (prev_qual == NULL)
8835               {
8836                 sfp->qual = gbqual->next;
8837               } else {
8838                 prev_qual->next = gbqual->next;
8839               }
8840               gbqual->next = NULL;
8841               GBQualFree (gbqual);
8842               return;
8843             }
8844           }
8845         }
8846         prev_qual = gbqual;
8847         gbqual = gbqual->next;
8848       }
8849     }
8850     vnp = vnp->next;
8851   }
8852 }
8853 
8854 static void SetExonFieldString (SeqFeatPtr sfp, Pointer userdata)
8855 {
8856   ApplyValuePtr avp;
8857   GBQualPtr  gbqual, prev_qual = NULL;
8858   Boolean       found = FALSE;
8859   
8860   if (sfp == NULL || userdata == NULL || sfp->idx.subtype != FEATDEF_exon)
8861   {
8862     return;
8863   }
8864   
8865   avp = (ApplyValuePtr) userdata;
8866   if (avp->field_list == NULL 
8867       || avp->field_list->data.intvalue >= NUM_EXON_FIELDS + 1
8868       || avp->field_list->data.intvalue < 1)
8869   {
8870     return;
8871   }
8872   
8873   if (!StringHasNoText (avp->text_to_replace))
8874   {
8875     found = TRUE;
8876   }
8877   
8878   gbqual = sfp->qual;
8879   while (gbqual != NULL)
8880   {
8881     if (StringCmp (gbqual->qual, 
8882                    exon_field_list[avp->field_list->data.intvalue - 1]) == 0)
8883     {
8884       gbqual->val = HandleApplyValue (gbqual->val, avp);
8885       found = TRUE;
8886     }
8887     prev_qual = gbqual;
8888     gbqual = gbqual->next;
8889   }
8890   if (!found)
8891   {
8892     gbqual = GBQualNew ();
8893     gbqual->qual = StringSave (exon_field_list[avp->field_list->data.intvalue - 1]);
8894     gbqual->val = StringSave (avp->new_text);
8895     if (prev_qual == NULL)
8896     {
8897       sfp->qual = gbqual;
8898     }
8899     else
8900     {
8901       prev_qual->next = gbqual;
8902     }
8903   }
8904 }
8905 
8906 #define PARSE_FIELD_BIOSRC_TAXNAME  1
8907 #define PARSE_FIELD_BIOSRC_LINEAGE  2
8908 #define PARSE_FIELD_BIOSRC_DIVISION 3
8909 
8910 static CharPtr biosrc_string_list [] =
8911 {
8912   "Organism Name", "Lineage", "Division"
8913 };
8914 
8915 static int num_biosrc_strings = sizeof (biosrc_string_list) / sizeof (CharPtr);
8916 
8917 extern DialoG BioSourceStringDialog 
8918 (GrouP                    h,
8919  Boolean                  allow_multi,
8920  Nlm_ChangeNotifyProc     change_notify,
8921  Pointer                  change_userdata)
8922 {
8923   return FeatureFieldSelectionDialog (h, allow_multi,
8924                                       num_biosrc_strings, biosrc_string_list, 
8925                                       change_notify, change_userdata);
8926 }
8927 
8928 static CharPtr GetSourceStringFromBioSource (BioSourcePtr biop, ValNodePtr vnp)
8929 {
8930   if (biop == NULL || vnp == NULL || biop->org == NULL)
8931   {
8932     return NULL;
8933   }
8934   
8935   if (vnp->data.intvalue == PARSE_FIELD_BIOSRC_TAXNAME
8936       && !StringHasNoText (biop->org->taxname))
8937   {
8938     return StringSave (biop->org->taxname);
8939   }
8940   else if (vnp->data.intvalue == PARSE_FIELD_BIOSRC_LINEAGE
8941            && biop->org->orgname != NULL
8942            && !StringHasNoText (biop->org->orgname->lineage))
8943   {
8944     return StringSave (biop->org->orgname->lineage);
8945   }
8946   else if (vnp->data.intvalue == PARSE_FIELD_BIOSRC_DIVISION
8947            && biop->org->orgname != NULL
8948            && !StringHasNoText (biop->org->orgname->div))
8949   {
8950     return StringSave (biop->org->orgname->div);
8951   }
8952   else
8953   {
8954     return NULL;
8955   }
8956 }
8957 
8958 static CharPtr 
8959 GetSourceFeatureString 
8960 (SeqFeatPtr   sfp,
8961  ValNodePtr   vnp,
8962  FilterSetPtr fsp)
8963 {
8964   if (sfp == NULL || sfp->data.choice != SEQFEAT_BIOSRC || vnp == NULL)
8965   {
8966     return NULL;
8967   }
8968   
8969   return GetSourceStringFromBioSource (sfp->data.value.ptrvalue, vnp);
8970 }
8971 
8972 static CharPtr 
8973 GetSourceDescriptorString 
8974 (SeqDescrPtr  sdp,
8975  ValNodePtr   vnp,
8976  FilterSetPtr fsp)
8977 {
8978   if (sdp == NULL || sdp->choice != Seq_descr_source || vnp == NULL)
8979   {
8980     return NULL;
8981   }
8982   return GetSourceStringFromBioSource (sdp->data.ptrvalue, vnp);
8983 }
8984 
8985 static void ApplySourceStringBioSourceCallback (BioSourcePtr biop, Pointer userdata)
8986 {
8987   ApplyValuePtr avp;
8988   
8989   if (biop == NULL || userdata == NULL)
8990   {
8991     return;
8992   }
8993   
8994   avp = (ApplyValuePtr) userdata;
8995   if (avp->field_list != NULL && !StringHasNoText (avp->new_text))
8996   {
8997     if (biop->org == NULL)
8998     {
8999       biop->org = OrgRefNew();
9000     }
9001     if (avp->field_list->data.intvalue == PARSE_FIELD_BIOSRC_TAXNAME)
9002     {
9003       biop->org->taxname = HandleApplyValue (biop->org->taxname, avp);
9004     }
9005     else if (avp->field_list->data.intvalue == PARSE_FIELD_BIOSRC_LINEAGE)
9006     {
9007       if (biop->org->orgname == NULL)
9008       {
9009         biop->org->orgname = OrgNameNew ();
9010       }
9011       biop->org->orgname->lineage = HandleApplyValue (biop->org->orgname->lineage, avp);
9012     }
9013     else if (avp->field_list->data.intvalue == PARSE_FIELD_BIOSRC_DIVISION)
9014     {
9015       if (biop->org->orgname == NULL)
9016       {
9017         biop->org->orgname = OrgNameNew ();
9018       }
9019       biop->org->orgname->div = HandleApplyValue (biop->org->orgname->div, avp);
9020     }
9021   }
9022   
9023 }
9024 
9025 static void ApplySourceStringFeatureCallback (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
9026 {
9027   if (sfp == NULL || sfp->data.choice != SEQFEAT_BIOSRC || userdata == NULL)
9028   {
9029     return;
9030   }
9031   ApplySourceStringBioSourceCallback (sfp->data.value.ptrvalue, userdata);
9032 }
9033 
9034 static void ApplySourceStringDescriptorCallback (SeqDescrPtr sdp, Pointer userdata, FilterSetPtr fsp)
9035 {
9036   if (sdp == NULL || sdp->choice != Seq_descr_source || userdata == NULL)
9037   {
9038     return;
9039   }
9040   ApplySourceStringBioSourceCallback (sdp->data.ptrvalue, userdata);
9041 }
9042 
9043 
9044 static CharPtr GetDbxrefFromBioSource (BioSourcePtr biop, ValNodePtr vnp)
9045 {
9046   ValNodePtr dbx;
9047   DbtagPtr   dbtag;
9048   Char       buf[20];
9049 
9050   if (biop == NULL || vnp == NULL || vnp->data.ptrvalue == NULL || biop->org == NULL)
9051   {
9052     return NULL;
9053   }
9054   
9055   dbx = biop->org->db;
9056   while (dbx != NULL)
9057   {
9058     dbtag = (DbtagPtr) dbx->data.ptrvalue;
9059     if (dbtag != NULL && dbtag->tag != NULL
9060         && StringCmp (dbtag->db, vnp->data.ptrvalue) == 0)
9061     {
9062       if (dbtag->tag->str == NULL)
9063       {
9064         sprintf (buf, "%d", dbtag->tag->id);
9065         return StringSave (buf);
9066       }
9067       else
9068       {
9069         return StringSave (dbtag->tag->str);
9070       }
9071     }
9072     dbx = dbx->next;
9073   }
9074   return NULL;
9075 }
9076 
9077 static CharPtr 
9078 GetBioSourceFeatureDbxrefString 
9079 (SeqFeatPtr   sfp,
9080  ValNodePtr   vnp,
9081  FilterSetPtr fsp)
9082 {
9083   if (sfp == NULL || sfp->data.choice != SEQFEAT_BIOSRC || vnp == NULL)
9084   {
9085     return NULL;
9086   }
9087   
9088   return GetDbxrefFromBioSource (sfp->data.value.ptrvalue, vnp);
9089 }
9090 
9091 static CharPtr 
9092 GetBioSourceDescriptorDbxrefString 
9093 (SeqDescrPtr  sdp,
9094  ValNodePtr   vnp,
9095  FilterSetPtr fsp)
9096 {
9097   if (sdp == NULL || sdp->choice != Seq_descr_source || vnp == NULL)
9098   {
9099     return NULL;
9100   }
9101   return GetDbxrefFromBioSource (sdp->data.ptrvalue, vnp);
9102 }
9103 
9104 
9105 static void ApplyBioSourceDbxrefBioSourceCallback (BioSourcePtr biop, Pointer userdata)
9106 {
9107   ApplyValuePtr avp;
9108   ValNodePtr    dbx;
9109   DbtagPtr      dbtag;
9110   Boolean       found = FALSE;
9111   Char          buf[20];
9112   
9113   if (biop == NULL || userdata == NULL)
9114   {
9115     return;
9116   }
9117   
9118   avp = (ApplyValuePtr) userdata;
9119   if (avp->field_list != NULL && !StringHasNoText (avp->new_text))
9120   {
9121     if (biop->org == NULL)
9122     {
9123       biop->org = OrgRefNew();
9124     }
9125     dbx = biop->org->db;
9126     while (dbx != NULL && !found)
9127     {
9128       dbtag = (DbtagPtr) dbx->data.ptrvalue;
9129       if (dbtag != NULL && dbtag->tag != NULL
9130           && StringCmp (dbtag->db, avp->field_list->data.ptrvalue) == 0)
9131       {
9132         found = TRUE;
9133       }
9134       if (!found)
9135       {
9136         dbx = dbx->next;
9137       }
9138     }
9139     if (!found)
9140     {
9141       dbtag = DbtagNew();
9142       dbtag->db = StringSave (avp->field_list->data.ptrvalue);      
9143       ValNodeAddPointer (&(biop->org->db), 0, dbtag);
9144     }
9145     if (dbtag->tag == NULL)
9146     {
9147       dbtag->tag = ObjectIdNew();
9148     }
9149     /* if it was a number before, make it a string now */
9150     if (dbtag->tag->id > 0 && dbtag->tag->str == NULL)
9151     {
9152       sprintf (buf, "%s", dbtag->tag->id);
9153       dbtag->tag->id = 0;
9154       dbtag->tag->str = StringSave (buf);
9155     }
9156     dbtag->tag->str = HandleApplyValue (dbtag->tag->str, avp);
9157   }
9158   
9159 }
9160 
9161 static void ApplyBioSourceDbxrefFeatureCallback (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
9162 {
9163   if (sfp == NULL || sfp->data.choice != SEQFEAT_BIOSRC || userdata == NULL)
9164   {
9165     return;
9166   }
9167   ApplyBioSourceDbxrefBioSourceCallback (sfp->data.value.ptrvalue, userdata);
9168 }
9169 
9170 static void ApplyBioSourceDbxrefDescriptorCallback (SeqDescrPtr sdp, Pointer userdata, FilterSetPtr fsp)
9171 {
9172   if (sdp == NULL || sdp->choice != Seq_descr_source || userdata == NULL)
9173   {
9174     return;
9175   }
9176   ApplyBioSourceDbxrefBioSourceCallback (sdp->data.ptrvalue, userdata);
9177 }
9178 
9179 
9180 
9181 #define TEXT_PORTION_START_AFTER 1
9182 #define TEXT_PORTION_START_WITH  2
9183 #define TEXT_PORTION_END_AFTER   1
9184 #define TEXT_PORTION_END_WITH    2
9185 
9186 typedef struct textportiondialog
9187 {
9188   DIALOG_MESSAGE_BLOCK
9189 
9190   GrouP  start_choice;
9191   TexT   start_text;
9192   GrouP  end_choice;
9193   TexT   end_text;
9194   ButtoN rem_before;
9195   ButtoN also_rem_before;
9196   ButtoN rem_after;
9197   ButtoN also_rem_after;
9198   ButtoN insensitive;
9199   ButtoN whole_word;
9200 
9201   Boolean inside;
9202 
9203   Nlm_ChangeNotifyProc     change_notify;
9204   Pointer                  change_userdata;
9205 } TextPortionXDialogData, PNTR TextPortionXDialogPtr;
9206 
9207 
9208 static void OutsideEnableDisable (TextPortionXDialogPtr tp)
9209 {
9210   if (tp == NULL || tp->inside)
9211   {
9212     return;
9213   }
9214   if (GetStatus (tp->rem_before)) 
9215   {
9216     Enable (tp->start_text);
9217     Enable (tp->also_rem_before);
9218   }
9219   else
9220   {
9221     Disable (tp->start_text);
9222     Disable (tp->also_rem_before);
9223   }
9224   if (GetStatus (tp->rem_after)) 
9225   {
9226     Enable (tp->end_text);
9227     Enable (tp->also_rem_after);
9228   }
9229   else
9230   {
9231     Disable (tp->end_text);
9232     Disable (tp->also_rem_after);
9233   }
9234 }
9235 
9236 static void ResetTextPortionXDialog (TextPortionXDialogPtr tp)
9237 {
9238   if (tp == NULL)
9239   {
9240     return;
9241   }
9242   if (tp->inside)
9243   {
9244     SetValue (tp->start_choice, TEXT_PORTION_START_AFTER);
9245     SetValue (tp->end_choice, TEXT_PORTION_END_AFTER);
9246   }
9247   else
9248   {
9249     SetStatus (tp->rem_before, FALSE);
9250     SetStatus (tp->also_rem_before, FALSE);
9251     SetStatus (tp->rem_after, FALSE);
9252     SetStatus (tp->also_rem_after, FALSE);
9253   }
9254   SetTitle (tp->start_text, "");
9255   SetTitle (tp->end_text, "");
9256   SetStatus (tp->insensitive, FALSE);
9257   SetStatus (tp->whole_word, FALSE);
9258   OutsideEnableDisable (tp);
9259 }
9260 
9261 static void TextPortionXToDialog (DialoG d, Pointer data)
9262 {
9263   TextPortionXDialogPtr tdlg;
9264   TextPortionXPtr       tdata;
9265   Int4                 start_choice, end_choice;
9266   
9267   tdlg = (TextPortionXDialogPtr) GetObjectExtra (d);
9268   if (tdlg == NULL)
9269   {
9270     return;
9271   }
9272   tdata = (TextPortionXPtr) data;
9273   ResetTextPortionXDialog (tdlg);  
9274   if (tdata != NULL)
9275   {
9276     start_choice = tdata->end_choice;
9277     end_choice = tdata->end_choice;
9278     if (start_choice < TEXT_PORTION_START_AFTER || start_choice > TEXT_PORTION_START_WITH)
9279     {
9280       start_choice = TEXT_PORTION_START_AFTER;
9281     }
9282     if (end_choice < TEXT_PORTION_END_AFTER || end_choice > TEXT_PORTION_END_WITH)
9283     {
9284       end_choice = TEXT_PORTION_END_AFTER;
9285     }
9286     if (tdlg->inside)
9287     {
9288       SetValue (tdlg->start_choice, start_choice);
9289       SetValue (tdlg->end_choice, end_choice);
9290     }
9291     else
9292     {
9293       SetStatus (tdlg->rem_before, StringHasNoText (tdata->start_text));
9294       SetStatus (tdlg->rem_after, StringHasNoText (tdata->end_text));
9295       if (start_choice == TEXT_PORTION_START_AFTER)
9296       {
9297         SetStatus (tdlg->also_rem_before, TRUE);
9298       }
9299       else
9300       {
9301         SetStatus (tdlg->also_rem_before, FALSE);
9302       }
9303       if (end_choice == TEXT_PORTION_END_AFTER)
9304       {
9305         SetStatus (tdlg->also_rem_after, TRUE);
9306       }
9307       else
9308       {
9309         SetStatus (tdlg->also_rem_after, FALSE);
9310       }
9311     }
9312     if (tdata->start_text != NULL)
9313     {
9314       SetTitle (tdlg->start_text, tdata->start_text);
9315     }
9316     if (tdata->end_text != NULL)
9317     {
9318       SetTitle (tdlg->end_text, tdata->end_text);
9319     }
9320     SetStatus (tdlg->insensitive, tdata->insensitive);
9321     SetStatus (tdlg->whole_word, tdata->whole_word);
9322   }
9323   OutsideEnableDisable (tdlg);
9324 }
9325 
9326 static Pointer DialogToTextPortionX (DialoG d)
9327 {
9328   TextPortionXDialogPtr tdlg;
9329   TextPortionXPtr       tdata;
9330 
9331   tdlg = (TextPortionXDialogPtr) GetObjectExtra (d);
9332   if (tdlg == NULL)
9333