NCBI C Toolkit Cross Reference

C/sequin/sequin10.c


  1 /*   sequin10.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:  sequin10.c
 27 *
 28 * Author:  Colleen Bollin
 29 *
 30 * Version Creation Date:   9/3/2003
 31 *
 32 * $Revision: 1.465 $
 33 *
 34 * File Description: 
 35 *
 36 * Modifications:  
 37 * --------------------------------------------------------------------------
 38 * Date     Name        Description of modification
 39 * -------  ----------  -----------------------------------------------------
 40 *
 41 *
 42 * ==========================================================================
 43 */
 44 
 45 #include "sequin.h"
 46 #include <sqnutils.h>
 47 #include <subutil.h>
 48 #include <explore.h>
 49 #include <edutil.h>
 50 #include <tofasta.h>
 51 #include <gbftdef.h>
 52 #include <gbfeat.h>
 53 #include <biosrc.h>
 54 #include <findrepl.h>
 55 #include <asnenbin.h>
 56 #include <cdrgn.h>
 57 #define NLM_GENERATED_CODE_PROTO
 58 #include <objmacro.h>
 59 #include <macrodlg.h>
 60 #include <macroapi.h>
 61 #include <seqpanel.h>
 62 #include <salpanel.h>
 63 #include <alignmgr2.h>
 64 #include <salpedit.h>
 65 
 66 typedef struct deflineformdata {
 67   FEATURE_FORM_BLOCK
 68 
 69   ModifierItemLocalPtr modList;
 70   ButtoN PNTR modifier_btns;
 71   DeflineFeatureRequestList feature_requests;
 72   ButtoN    feature_btns[NumRemovableItems];
 73   GrouP     sourceListGrp;
 74   PopuP     customGrp;
 75   ButtoN    use_labels;
 76   ButtoN    keep_paren;
 77   ButtoN    exclude_sp;
 78   ButtoN    exclude_cf;
 79   ButtoN    exclude_aff;
 80   ButtoN    exclude_nr;
 81   ButtoN    allow_mod_at_end_of_taxname;
 82   ButtoN    include_country_extra;
 83   ButtoN    allow_semicolon_in_modifier;
 84   GrouP     clone_isolate_HIV_rule_num;
 85   PopuP     modLimit;
 86   PopuP     organelle_popup;
 87   BioseqPtr target_bsp;
 88   ButtoN    modify_only_target;
 89   ButtoN    suppress_alt_splice_phrase;
 90   ButtoN    remove_subfeatures;
 91   PopuP     featurePopup;
 92   GrouP     featureOptsGrp;
 93   GrouP     optional_features_grp;
 94   PopuP     misc_feat_parse_rule;
 95   GrouP     promoter_type;
 96   ButtoN    alternate_splice_flag;
 97   ButtoN    use_ncrna_note;
 98   ButtoN    suppress_locus_tags;
 99   ButtoN    gene_cluster_opp_strand;
100   DialoG    suppressed_feature_list;
101   GrouP     suppressed_feature_grp;
102 } DefLineFormData, PNTR DefLineFormPtr;
103 
104 static void DefLineFormMessageProc (ForM f, Int2 mssg)
105 
106 {
107   DefLineFormPtr  dlfp;
108 
109   dlfp = (DefLineFormPtr) GetObjectExtra (f);
110   if (dlfp != NULL) {
111     if (dlfp->appmessage != NULL) {
112       dlfp->appmessage (f, mssg);
113     }
114   }
115 }
116 
117 static void CleanupDefLineForm (
118   GraphiC g,
119   VoidPtr data
120 )
121 
122 {
123   DefLineFormPtr  dlfp;
124   Int4            i;
125 
126   dlfp = (DefLineFormPtr) data;
127   if (dlfp != NULL) {
128     if (dlfp->modList != NULL)
129     {
130       for (i=0; i < NumDefLineModifiers (); i++)
131       {
132         ValNodeFree (dlfp->modList[i].values_seen);
133       }
134       MemFree (dlfp->modList);
135     }
136     dlfp->modifier_btns = MemFree (dlfp->modifier_btns);
137   }
138   StdCleanupFormProc (g, data);
139 }
140 
141 static void ChangeCustomPopup (PopuP p)
142 
143 {
144   DefLineFormPtr  dlfp;
145 
146   dlfp = (DefLineFormPtr) GetObjectExtra (p);
147   if (dlfp == NULL) return;
148   if (GetValue (p) == 1) {
149     SafeDisable (dlfp->sourceListGrp);
150   } else {
151     SafeEnable (dlfp->sourceListGrp);
152   }
153 }
154 
155 static void ChangeFeaturePopup (PopuP p)
156 {
157   DefLineFormPtr  dlfp;
158 
159   dlfp = (DefLineFormPtr) GetObjectExtra (p);
160   if (dlfp == NULL) return;
161   if (GetValue (p) == 2 || GetValue (p) == 3)
162   {
163     SafeDisable (dlfp->featureOptsGrp);
164     SafeDisable (dlfp->suppressed_feature_grp);
165     SafeDisable (dlfp->optional_features_grp);
166     SafeDisable (dlfp->organelle_popup);
167     SafeDisable (dlfp->alternate_splice_flag);
168   }
169   else
170   {
171     SafeEnable (dlfp->featureOptsGrp);
172     SafeEnable (dlfp->suppressed_feature_grp);
173     SafeEnable (dlfp->optional_features_grp);
174     SafeEnable (dlfp->organelle_popup);
175     SafeEnable (dlfp->alternate_splice_flag);
176   }
177 }
178 
179 
180 static void DoAutoDefLine (ButtoN b)
181 {
182   DefLineFormPtr dlfp;
183   SeqEntryPtr sep;
184   ValNodePtr modifier_indices = NULL;
185   Int2 feature_index;
186   OrganismDescriptionModifiers odmp;
187   Int2 product_flag, feature_list_type;
188   Int4 i;
189   Boolean alternate_splice_flag;
190   Boolean gene_cluster_opp_strand;
191 
192   dlfp = GetObjectExtra (b);
193   if (b == NULL) return;
194   Hide (dlfp->form);
195   WatchCursor ();
196   Update ();
197 
198   InitOrganismDescriptionModifiers (&odmp, NULL);
199   odmp.use_labels = GetStatus (dlfp->use_labels);
200   odmp.keep_paren = GetStatus (dlfp->keep_paren);
201   odmp.exclude_sp = GetStatus (dlfp->exclude_sp);
202   odmp.exclude_cf = GetStatus (dlfp->exclude_cf);
203   odmp.exclude_aff = GetStatus (dlfp->exclude_aff);
204   odmp.exclude_nr = GetStatus (dlfp->exclude_nr);
205   odmp.include_country_extra = GetStatus (dlfp->include_country_extra);
206   odmp.use_modifiers = TRUE;
207   odmp.allow_semicolon_in_modifier = GetStatus (dlfp->allow_semicolon_in_modifier);
208   odmp.allow_mod_at_end_of_taxname = !GetStatus (dlfp->allow_mod_at_end_of_taxname);
209 
210   if (dlfp->clone_isolate_HIV_rule_num == NULL)
211   {
212     odmp.clone_isolate_HIV_rule_num = clone_isolate_HIV_rule_want_both;
213   }
214   else
215   {
216     odmp.clone_isolate_HIV_rule_num = GetValue (dlfp->clone_isolate_HIV_rule_num);
217   }
218 
219   if (GetValue (dlfp->customGrp) == 1)
220   {
221     /* take all features */
222     for (feature_index = 0; feature_index < NumDefLineModifiers (); feature_index++)
223     {
224       if (dlfp->modList[feature_index].any_present)
225       {
226         ValNodeAddInt (&modifier_indices, 0, feature_index);
227       }
228     }
229   }
230   else
231   {
232     /* take selected features */
233     for (feature_index = 0; feature_index < NumDefLineModifiers (); feature_index++)
234     {
235       if (GetStatus (dlfp->modifier_btns[feature_index]))
236       {
237         ValNodeAddInt (&modifier_indices, 0, feature_index);
238       }
239     }
240   }
241 
242   feature_list_type = GetValue (dlfp->featurePopup);
243   switch (feature_list_type)
244   {
245     case DEFLINE_USE_FEATURES :
246       dlfp->feature_requests.feature_list_type = DEFLINE_USE_FEATURES;
247       break;
248     case DEFLINE_COMPLETE_SEQUENCE :
249       dlfp->feature_requests.feature_list_type = DEFLINE_COMPLETE_SEQUENCE;
250       break;
251     case DEFLINE_COMPLETE_GENOME :
252       dlfp->feature_requests.feature_list_type = DEFLINE_COMPLETE_GENOME;
253       break;
254     case DEFLINE_SEQUENCE :
255       dlfp->feature_requests.feature_list_type = DEFLINE_SEQUENCE;
256       break;
257     default:
258       dlfp->feature_requests.feature_list_type = DEFLINE_USE_FEATURES;
259       break;
260   }
261 
262   for (i=0; i< NumRemovableItems; i++)
263   {
264     dlfp->feature_requests.keep_items[i] 
265               = GetStatus (dlfp->feature_btns[i]);
266   }
267   if (GetValue (dlfp->promoter_type) == 1) 
268   {
269     dlfp->feature_requests.add_fake_promoters = TRUE;
270   }
271   else
272   {
273     dlfp->feature_requests.add_fake_promoters = FALSE;
274   }
275 
276   dlfp->feature_requests.suppress_alt_splice_phrase = 
277                  GetStatus (dlfp->suppress_alt_splice_phrase);
278 
279   dlfp->feature_requests.use_ncrna_note = 
280                  GetStatus (dlfp->use_ncrna_note);
281   
282   dlfp->feature_requests.remove_subfeatures = 
283                  GetStatus (dlfp->remove_subfeatures);
284 
285   dlfp->feature_requests.suppress_locus_tags = 
286                  GetStatus (dlfp->suppress_locus_tags);
287 
288   dlfp->feature_requests.misc_feat_parse_rule = 
289                  GetValue (dlfp->misc_feat_parse_rule);
290                  
291   dlfp->feature_requests.suppressed_feature_list = DialogToPointer (dlfp->suppressed_feature_list);                 
292 
293   odmp.max_mods = GetValue (dlfp->modLimit);
294   if (odmp.max_mods > 1)
295   {
296     odmp.max_mods = odmp.max_mods - 1;
297   }
298   else
299   {
300     odmp.max_mods = -99;
301   }
302 
303   product_flag = GetValue (dlfp->organelle_popup) - 1;
304   alternate_splice_flag = GetStatus (dlfp->alternate_splice_flag);
305   gene_cluster_opp_strand = GetStatus (dlfp->gene_cluster_opp_strand);
306  
307   if (dlfp->target_bsp != NULL && GetStatus (dlfp->modify_only_target))
308   {
309     sep = GetBestTopParentForData (dlfp->input_entityID, dlfp->target_bsp);
310   }
311   else
312   { 
313     sep = GetTopSeqEntryForEntityID (dlfp->input_entityID);
314   }
315   if (sep == NULL) return;
316 
317   AutoDefForSeqEntry (sep, dlfp->input_entityID, &odmp, dlfp->modList, modifier_indices,
318                       &dlfp->feature_requests, product_flag, alternate_splice_flag, gene_cluster_opp_strand);
319                               
320   dlfp->feature_requests.suppressed_feature_list = ValNodeFree (dlfp->feature_requests.suppressed_feature_list);
321   modifier_indices = ValNodeFree (modifier_indices);
322 
323   ArrowCursor ();
324   Update ();
325   ObjMgrSetDirtyFlag (dlfp->input_entityID, TRUE);
326   ObjMgrSendMsg (OM_MSG_UPDATE, dlfp->input_entityID, 0, 0);
327   Remove (dlfp->form);
328   SeqEntrySetScope (NULL);
329 }
330 
331 static void IsTricky (
332   BioSourcePtr biop,
333   Pointer userdata
334 )
335 {
336   Boolean PNTR pTricky;
337   static CharPtr long_name = "Human immunodeficiency virus";
338   static CharPtr short_name = "HIV-";
339   OrgModPtr     mod;
340   OrgNamePtr    onp;
341   SubSourcePtr  ssp;
342 
343   pTricky = (Boolean PNTR) userdata;
344   if (pTricky == NULL
345     || *pTricky
346     || biop == NULL
347     || biop->org == NULL
348     || biop->org->taxname == NULL
349     || biop->org->orgname == NULL
350     || biop->subtype == NULL)
351   {
352     return;
353   }
354   if (StringNICmp (biop->org->taxname, long_name, StringLen (long_name)) != 0
355     && StringNICmp (biop->org->taxname, short_name, StringLen (short_name)) != 0)
356   {
357     return;
358   }
359 
360   onp = biop->org->orgname;
361   if (onp == NULL) return;
362   mod = onp->mod;
363   while (mod != NULL
364     && mod->subtype != ORGMOD_isolate)
365   {
366     mod = mod->next;
367   }
368   if (mod == NULL || mod->subname == NULL)
369   {
370     return;
371   }
372 
373   ssp = biop->subtype;
374   while (ssp != NULL && ssp->subtype != SUBSRC_clone)
375   {
376     ssp = ssp->next;
377   }
378   if (ssp == NULL || ssp->name == NULL)
379   {
380     return;
381   }
382   *pTricky = TRUE;
383   return;
384 }
385 
386 static Boolean HasTrickyHIVRecords (
387   SeqEntryPtr sep
388 )
389 {
390   Boolean     has_tricky;
391 
392   if (sep == NULL) return FALSE;
393   
394   has_tricky = FALSE;
395   VisitBioSourcesInSep (sep, &has_tricky, IsTricky);
396   return has_tricky;
397 }
398 
399 
400 static GrouP CreateDefLineFormHIVRule (
401   GrouP h
402 )
403 {
404   GrouP hiv_rule;
405 
406   hiv_rule = NormalGroup (h, 3, 0, "HIV rule", programFont, NULL);
407   RadioButton (hiv_rule, "Prefer Clone");
408   RadioButton (hiv_rule, "Prefer Isolate");
409   RadioButton (hiv_rule, "Want Both Isolate and Clone");
410   SetValue (hiv_rule, clone_isolate_HIV_rule_want_both);
411   return hiv_rule;
412 }
413 
414 static PopuP CreateDefLineFormModLimitPopup (
415   GrouP q,
416   Int2 count
417 )
418 {
419   PopuP limit;
420   Int2  i;
421   Char  str[10];
422 
423   StaticPrompt (q, "Max modifiers per line", 0, popupMenuHeight, programFont, 'l');
424   limit = PopupList (q, TRUE, NULL);
425   PopupItem (limit, "no limit");
426   for (i = 1; i <= count; i++) {
427     sprintf (str, "%d", (int) i);
428     PopupItem (limit, str);
429   }
430 
431   SetValue (limit, 1);
432   
433   return limit;
434 }
435 
436 static PopuP CreateDefLineFormModifierListPopuP (
437   GrouP          q,
438   DefLineFormPtr dlfp
439 )
440 {
441   PopuP popup;
442   StaticPrompt (q, "Modifier List", 0, popupMenuHeight, programFont, 'l');
443   popup = PopupList (q, TRUE, ChangeCustomPopup);
444   SetObjectExtra (popup, dlfp, NULL);
445   PopupItem (popup, "All");
446   PopupItem (popup, "Custom");
447   SetValue (popup, 2);
448   
449   return popup;
450 }
451   
452 static void SetHIVRuleEnable (Handle a)
453 {
454   DefLineFormPtr dlfp;
455  
456   dlfp = GetObjectExtra (a);
457   if (dlfp == NULL) return;
458   if (dlfp->clone_isolate_HIV_rule_num == NULL) return;
459   if (dlfp->modList == NULL) return;
460   if ((dlfp->modifier_btns [DEFLINE_POS_Clone] != NULL
461        && GetStatus (dlfp->modifier_btns [DEFLINE_POS_Clone]))
462       || (dlfp->modifier_btns [DEFLINE_POS_Isolate] != NULL
463           && GetStatus (dlfp->modifier_btns [DEFLINE_POS_Isolate])))
464   {
465     Disable (dlfp->clone_isolate_HIV_rule_num);
466   }
467   else
468   {
469     Enable (dlfp->clone_isolate_HIV_rule_num);
470   }
471 }
472 
473 static GrouP CreateDefLineFormSourceGroup (
474   GrouP          h,
475   DefLineFormPtr dlfp,
476   SeqEntryPtr    sep
477 )
478 {
479   GrouP p, g, g1, r;
480   Int2    item_index, num_label_columns, num_item_rows;
481   Int2    num_item_columns, count = 0;
482   Char    ch;
483   Boolean has_tricky;
484 
485   p = NormalGroup (h, -1, 0, "SOURCE", programFont, NULL);
486   SetGroupSpacing (p, 10, 10);
487 
488   count = 0;
489   for (item_index=0; item_index < NumDefLineModifiers (); item_index++)
490   {
491     if (dlfp->modList[item_index].any_present)
492     {
493       count++;
494     }
495   }
496   
497   g = HiddenGroup (p, 4, 0, NULL);
498   SetGroupSpacing (g, 20, 10);
499   dlfp->customGrp = CreateDefLineFormModifierListPopuP (g, dlfp);
500   dlfp->modLimit = CreateDefLineFormModLimitPopup (g, count);
501   dlfp->use_labels = CheckBox (p, "Use labels", NULL);
502   SetStatus (dlfp->use_labels, TRUE);
503   
504   num_item_rows = 6;
505   if (count > 18)
506     num_item_rows = 8;
507   if (count > 24)
508     num_item_rows = 10;
509   if (count > 30)
510     num_item_rows = 12;
511 
512   num_item_columns = count / num_item_rows;
513   if (count % num_item_rows != 0) num_item_columns ++;
514 
515   num_label_columns = 3;
516   if (count > 6)
517     num_label_columns --;
518   if (count > 12)
519     num_label_columns --;
520 
521   dlfp->sourceListGrp = NormalGroup (p,
522                                      0,
523                                      4,
524                                      "Available Modifiers",
525                                      programFont, NULL);
526   SetGroupSpacing (dlfp->sourceListGrp, 10, 10);                                     
527 
528   for (item_index=0; item_index < NumDefLineModifiers (); item_index++)
529   {
530     if (dlfp->modList[item_index].any_present)
531     {
532       g1 = HiddenGroup (dlfp->sourceListGrp, num_label_columns, 0, NULL);
533       SetGroupSpacing (g1, 10, 10);
534       dlfp->modifier_btns[item_index] = CheckBox (g1,
535                                              DefLineModifiers[item_index].name,
536                                              (BtnActnProc) SetHIVRuleEnable);
537       SetObjectExtra (dlfp->modifier_btns [item_index], dlfp, NULL);
538       SetStatus (dlfp->modifier_btns [item_index],
539                  dlfp->modList[item_index].required);
540       
541       if (num_label_columns > 1)
542       {
543         StaticPrompt (g1,
544                       dlfp->modList[item_index].status,
545                       0, popupMenuHeight, programFont, 'l');
546         if (num_label_columns > 2)
547         {
548                   if (StringLen (dlfp->modList[item_index].first_value_seen) > 50)
549                   {
550                     ch = dlfp->modList[item_index].first_value_seen [50];
551             dlfp->modList[item_index].first_value_seen [50] = 0;
552                   }
553                   else
554                   {
555                     ch = 0;
556                   }
557           StaticPrompt (g1,
558                         dlfp->modList[item_index].first_value_seen,
559                         0, popupMenuHeight, programFont, 'l');
560               if (ch != 0)
561                   {
562                     dlfp->modList[item_index].first_value_seen [50] = ch;
563                   }
564         }
565       }
566     }
567     else
568     {
569       dlfp->modifier_btns[item_index] = NULL;
570       dlfp->modList[item_index].required = FALSE;
571     }
572   }
573 
574   Enable (dlfp->sourceListGrp);
575 
576 
577   has_tricky = HasTrickyHIVRecords (sep);
578   if (has_tricky)
579   {
580     dlfp->clone_isolate_HIV_rule_num = CreateDefLineFormHIVRule (p);
581     SetObjectExtra (dlfp->clone_isolate_HIV_rule_num, dlfp, NULL);
582     SetHIVRuleEnable (dlfp->clone_isolate_HIV_rule_num);
583   }
584   else
585   {
586     dlfp->clone_isolate_HIV_rule_num = NULL;
587   }
588   r = NormalGroup (p, 3, 0, "Other Options", programFont, NULL);
589   SetGroupSpacing (r, 10, 10);
590   dlfp->keep_paren = CheckBox (r, "Leave in parenthetical organism info", NULL);
591   SetStatus (dlfp->keep_paren, TRUE);
592   dlfp->include_country_extra = CheckBox (r, "Include text after colon in country", NULL);
593   SetStatus (dlfp->include_country_extra, FALSE);
594   dlfp->allow_semicolon_in_modifier = CheckBox (r, "Include text after semicolon in modifiers", NULL);
595   SetStatus (dlfp->allow_semicolon_in_modifier, FALSE);
596   dlfp->exclude_sp = CheckBox (r, "Do not apply modifier to 'sp.' organisms",
597          NULL);
598   SetStatus (dlfp->exclude_sp, ShouldExcludeSp (sep));
599   dlfp->exclude_cf = CheckBox (r, "Do not apply modifier to 'cf.' organisms",
600          NULL);
601   SetStatus (dlfp->exclude_cf, FALSE);
602   
603   dlfp->exclude_aff = CheckBox (r, "Do not apply modifier to 'aff.' organisms",
604          NULL);
605   SetStatus (dlfp->exclude_aff, FALSE);
606   dlfp->exclude_nr = CheckBox (r, "Do not apply modifier to 'nr.' organisms", NULL);
607   SetStatus (dlfp->exclude_nr, FALSE);
608   
609   dlfp->allow_mod_at_end_of_taxname = CheckBox (r, "Do not apply modifier to organisms with matching tax name value", NULL);
610   SetStatus (dlfp->allow_mod_at_end_of_taxname, TRUE);
611 
612   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) dlfp->use_labels,
613                               (HANDLE) dlfp->sourceListGrp,
614                               (HANDLE) r,
615                               (HANDLE) dlfp->clone_isolate_HIV_rule_num,
616                               NULL);
617   return p;
618 }
619 
620 static PopuP CreateDefLineFormOrganellePopup (
621   GrouP h
622 )
623 {
624   PopuP o;
625 
626   o = PopupList (h, FALSE, NULL);
627   PopupItem (o, "No mitochondrial or chloroplast suffix");
628   PopupItem (o, "Nuclear gene(s) for mitochondrial product(s)");
629   PopupItem (o, "Nuclear gene(s) for chloroplast product(s)");
630   PopupItem (o, "Nuclear gene(s) for kinetoplast product(s)");
631   PopupItem (o, "Nuclear gene(s) for plastid product(s)");
632   PopupItem (o, "Nuclear gene(s) for chromoplast product(s)");
633   PopupItem (o, "Nuclear gene(s) for cyanelle product(s)");
634   PopupItem (o, "Nuclear gene(s) for apicoplast product(s)");
635   PopupItem (o, "Nuclear gene(s) for leucoplast product(s)");
636   PopupItem (o, "Nuclear gene(s) for proplastid product(s)");
637   PopupItem (o, "Nuclear genes based on CDS products");
638   SetValue (o, DEFAULT_ORGANELLE_CLAUSE + 1);
639   return o;
640 }
641 
642 static GrouP CreateDefLineFormFeatureListPopuP (
643   GrouP          g,
644   DefLineFormPtr dlfp
645 )
646 {
647   GrouP q;
648 
649   q = HiddenGroup (g, 2, 0, NULL);
650   StaticPrompt (q, "Features or Complete", 0, popupMenuHeight, programFont, 'l');
651   dlfp->featurePopup = PopupList (q, TRUE, ChangeFeaturePopup);
652   SetObjectExtra (dlfp->featurePopup, dlfp, NULL);
653   PopupItem (dlfp->featurePopup, "List Features");
654   PopupItem (dlfp->featurePopup, "Complete Sequence");
655   PopupItem (dlfp->featurePopup, "Complete Genome");
656   PopupItem (dlfp->featurePopup, "Sequence");
657   SetValue (dlfp->featurePopup, 1);
658   
659   return q;
660 }
661 
662 static void SetMiscFeatRuleEnable (Handle a)
663 {
664   DefLineFormPtr dlfp;
665 
666   if (a == NULL || ( dlfp = (DefLineFormPtr) GetObjectExtra (a)) == NULL)
667   {
668     return;
669   }
670   if (GetStatus (dlfp->feature_btns[RemovableNoncodingProductFeat]))
671   {
672     Enable (dlfp->misc_feat_parse_rule);
673   }
674   else
675   {
676     Disable (dlfp->misc_feat_parse_rule);
677   }
678   if (GetStatus (dlfp->feature_btns[RemovablePromoter]))
679   {
680     Enable (dlfp->promoter_type);
681   }
682   else
683   {
684     Disable (dlfp->promoter_type);
685   }
686 }
687   
688 static GrouP CreateDefLineFormFeatureOptionsGroup (
689   GrouP          h,
690   DefLineFormPtr dlfp
691 )
692 {
693   GrouP p, g1, s1, s2, k, k2;
694   Int4  i;
695   SeqEntryPtr sep;
696 
697   p = NormalGroup (h, -1, 0, "FEATURES", programFont, NULL);
698   SetGroupSpacing (p, 10, 10);
699 
700   g1 = HiddenGroup (p, 2, 0, NULL);
701   SetGroupSpacing (g1, 10, 10);
702   s1 = HiddenGroup (g1, -1, 0, NULL);
703   SetGroupSpacing (s1, 10, 10);
704   CreateDefLineFormFeatureListPopuP (s1, dlfp);
705   dlfp->organelle_popup = CreateDefLineFormOrganellePopup (s1);
706   dlfp->alternate_splice_flag = CheckBox (s1,
707                         "Append 'alternatively spliced'", NULL);
708   dlfp->use_ncrna_note = CheckBox (s1, "Use ncRNA note if no class or product", NULL);
709   AlignObjects (ALIGN_CENTER, (HANDLE) dlfp->featurePopup, 
710                               (HANDLE) dlfp->organelle_popup, 
711                               (HANDLE) dlfp->use_ncrna_note, 
712                               (HANDLE) dlfp->alternate_splice_flag, NULL);
713   
714   dlfp->optional_features_grp = NormalGroup (g1, 3, 0,
715                    "Optional Features", programFont, NULL);
716                    SetGroupSpacing (dlfp->optional_features_grp, 10, 10);
717   for (i=0; i < NumRemovableItems; i++)
718   {
719     if (i == 0 || i == 4 || i == 7)
720     {
721       k = HiddenGroup (dlfp->optional_features_grp, 0, 4, NULL);
722       SetGroupSpacing (k, 10, 10);
723     }
724     if (i != RemovableCDS)
725     {
726       dlfp->feature_btns[i] = 
727                      CheckBox (k, GetRemovableItemName (i), 
728                                (BtnActnProc) SetMiscFeatRuleEnable);
729       SetObjectExtra (dlfp->feature_btns[i], dlfp, NULL);
730       SetStatus (dlfp->feature_btns[i], FALSE);
731       if (i == RemovableNoncodingProductFeat) {
732         s2 = HiddenGroup (k, 2, 0, NULL);
733         StaticPrompt (s2, "        ", 8, popupMenuHeight, programFont, 'l');
734         dlfp->misc_feat_parse_rule = PopupList (s2, TRUE, NULL);
735         PopupItem (dlfp->misc_feat_parse_rule, "Use comment before first semicolon");
736         PopupItem (dlfp->misc_feat_parse_rule, "Look for Noncoding Products");
737         SetValue (dlfp->misc_feat_parse_rule, 2);
738         Disable (dlfp->misc_feat_parse_rule);
739       } else if (i == RemovablePromoter) {
740         k2 = HiddenGroup (k, 2, 0, NULL);
741         SetGroupSpacing (k2, 10, 10);
742         StaticPrompt (k2, "        ", 8, popupMenuHeight, programFont, 'l');
743         dlfp->promoter_type = HiddenGroup (k2, 0, 2, NULL);
744         RadioButton (dlfp->promoter_type, "All");
745         RadioButton (dlfp->promoter_type, "If present");
746         SetValue (dlfp->promoter_type, 1);
747         Disable (dlfp->promoter_type);
748         AlignObjects (ALIGN_CENTER, (HANDLE) dlfp->feature_btns[i],
749                                     (HANDLE) dlfp->promoter_type,
750                                     NULL);
751       }
752     }
753   }
754                                       
755   dlfp->suppressed_feature_grp = NormalGroup (g1, -1, 0,
756                     "Suppress Features", programFont, NULL);
757   sep = GetTopSeqEntryForEntityID(dlfp->input_entityID);
758   dlfp->suppressed_feature_list = FeatureSelectionDialogEx (dlfp->suppressed_feature_grp, TRUE, sep, NULL, NULL);
759   
760   dlfp->featureOptsGrp = NormalGroup (g1, 0, 4, "Suppress", programFont, NULL);
761   SetGroupSpacing (dlfp->featureOptsGrp, 10, 10);
762   dlfp->remove_subfeatures = CheckBox (dlfp->featureOptsGrp, "Mobile element subfeatures", NULL);
763   SetStatus (dlfp->remove_subfeatures, FALSE);
764   
765   dlfp->gene_cluster_opp_strand = CheckBox (dlfp->featureOptsGrp,
766              "Gene cluster/locus subfeatures (both strands)", NULL);
767   SetStatus (dlfp->gene_cluster_opp_strand, FALSE);
768 
769   dlfp->suppress_locus_tags = CheckBox (dlfp->featureOptsGrp, "Locus tags", NULL);
770   SetStatus (dlfp->suppress_locus_tags, FALSE);
771 
772   dlfp->suppress_alt_splice_phrase = CheckBox (dlfp->featureOptsGrp, "Alternative splice phrase", NULL);
773   SetStatus (dlfp->suppress_alt_splice_phrase, FALSE);
774 
775   return p;
776 }
777 
778 static void CreateDefLineForm (
779   BaseFormPtr bfp,
780   ModifierItemLocalPtr modList,
781   DeflineFeatureRequestList *feature_requests
782 )
783 {
784   DefLineFormPtr dlfp;
785   WindoW         w;
786   GrouP          h, k, g1, c, feat_opts;
787   ButtoN         b;
788   SeqEntryPtr    sep;
789 
790   dlfp = MemNew (sizeof (DefLineFormData));
791   if (dlfp == NULL) return;
792   dlfp->input_entityID = bfp->input_entityID;
793   dlfp->input_itemID = bfp->input_itemID;
794   dlfp->input_itemtype = bfp->input_itemtype;
795 
796   dlfp->modifier_btns = (ButtoN PNTR) MemNew (sizeof (ButtoN) * NumDefLineModifiers());
797 
798   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
799 
800   w = FixedWindow (-50, -33, -10, -10, "Automatic Definition Line",
801   StdCloseWindowProc);
802   SetObjectExtra (w, dlfp, CleanupDefLineForm);
803   dlfp->form = (ForM) w;
804   dlfp->formmessage = DefLineFormMessageProc;
805 
806   dlfp->modList = modList;
807   dlfp->feature_requests = *feature_requests;
808 
809   h = HiddenGroup (w, -1, 0, NULL);
810   SetGroupSpacing (h, 10, 10);
811 
812   k = HiddenGroup (h, -1, 0, NULL);
813   SetGroupSpacing (k, 10, 10);
814   g1 = CreateDefLineFormSourceGroup (k, dlfp, sep);
815 
816   feat_opts = CreateDefLineFormFeatureOptionsGroup (k, dlfp);
817   AlignObjects (ALIGN_CENTER, (HANDLE) g1, (HANDLE) feat_opts, NULL);
818 
819   c = HiddenGroup (h, 4, 0, NULL);
820   b = DefaultButton (c, "Accept", DoAutoDefLine);
821   SetObjectExtra (b, dlfp, NULL);
822   PushButton (c, "Cancel", StdCancelButtonProc);
823 
824   dlfp->target_bsp = GetBioseqGivenIDs (dlfp->input_entityID,
825           dlfp->input_itemID,
826           dlfp->input_itemtype);
827   dlfp->modify_only_target = CheckBox (c, "Only modify targeted record", NULL);
828   SetStatus (dlfp->modify_only_target, FALSE);
829   if (dlfp->target_bsp == NULL)
830   {
831     Disable (dlfp->modify_only_target);
832   }
833 
834   AlignObjects (ALIGN_CENTER, (HANDLE) k,
835                 (HANDLE) c, NULL);
836   RealizeWindow (w);
837   Show (w);
838   Update ();
839 }
840 
841 
842 /* The AddBestComboModifiersToModList function sets the modifiers
843  * selected by the FindBestCombo process as selected.
844  */
845 static void AddBestModifiersToModList (
846   ValNodePtr modifier_indices,
847   ModifierItemLocalPtr modList
848 )
849 {
850   ValNodePtr vnp;
851 
852   for (vnp = modifier_indices; vnp != NULL; vnp = vnp->next)
853   {
854     modList[vnp->data.intvalue].required = TRUE;
855   }
856 }
857 
858 
859 extern void AutoDefEntityIDNoOptions (Uint2 entityID, Boolean use_modifiers)
860 {
861   SeqEntryPtr sep;
862   DeflineFeatureRequestList feature_requests;
863   ModifierItemLocalPtr modList;
864   ValNodePtr modifier_indices = NULL;
865   OrganismDescriptionModifiers odmp;
866   Int4 index;
867   ValNodePtr defline_clauses = NULL;
868 
869   sep = GetTopSeqEntryForEntityID (entityID);
870   if (sep == NULL) return;
871 
872   InitFeatureRequests (&feature_requests);
873 
874   modList = MemNew (NumDefLineModifiers () * sizeof (ModifierItemLocalData));
875   if (modList == NULL) return;
876   SetRequiredModifiers (modList);
877   CountModifiers (modList, sep);
878 
879   InitOrganismDescriptionModifiers (&odmp, sep);
880   odmp.use_modifiers = use_modifiers;
881 
882     RemoveNucProtSetTitles (sep);  
883     SeqEntrySetScope (sep);
884 
885     BuildDefLineFeatClauseList (sep, entityID, &feature_requests,
886                                 DEFAULT_ORGANELLE_CLAUSE, FALSE, FALSE,
887                                 &defline_clauses);
888     if ( AreFeatureClausesUnique (defline_clauses))
889     {
890       modifier_indices = GetModifierIndicesFromModList (modList);
891     }
892     else
893     {
894       modifier_indices = FindBestModifiersForDeflineClauseList (defline_clauses, modList);
895     }
896 
897     BuildDefinitionLinesFromFeatureClauseLists (defline_clauses, modList,
898                                                 modifier_indices, &odmp);
899 
900     DefLineFeatClauseListFree (defline_clauses);
901     if (modList != NULL)
902     {
903       for (index=0; index < NumDefLineModifiers (); index++)
904       {
905         ValNodeFree (modList[index].values_seen);
906       }
907       MemFree (modList);
908     }
909     modifier_indices = ValNodeFree (modifier_indices);
910 
911     ClearProteinTitlesInNucProts (entityID, NULL);
912     InstantiateProteinTitles (entityID, NULL);
913 }
914 
915 
916 extern void AutoDefBaseFormCommon (
917   BaseFormPtr bfp,
918   Boolean use_form,
919   Boolean use_modifiers
920 )
921 {
922   SeqEntryPtr sep;
923   DeflineFeatureRequestList feature_requests;
924   ModifierItemLocalPtr modList;
925   ValNodePtr modifier_indices = NULL;
926   OrganismDescriptionModifiers odmp;
927   Int4 index;
928   ValNodePtr defline_clauses = NULL;
929 
930   if (bfp == NULL) return;
931   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
932   if (sep == NULL) return;
933 
934   InitFeatureRequests (&feature_requests);
935 
936   modList = MemNew (NumDefLineModifiers () * sizeof (ModifierItemLocalData));
937   if (modList == NULL) return;
938   SetRequiredModifiers (modList);
939   CountModifiers (modList, sep);
940   if (use_form)
941   {
942     modifier_indices = FindBestModifiersEx (sep, modList, TRUE);
943     AddBestModifiersToModList ( modifier_indices, modList);
944     modifier_indices = ValNodeFree (modifier_indices);
945     CreateDefLineForm (bfp, modList, &feature_requests);
946   }
947   else
948   {
949     WatchCursor ();
950     Update ();
951     InitOrganismDescriptionModifiers (&odmp, sep);
952     odmp.use_modifiers = use_modifiers;
953 
954     RemoveNucProtSetTitles (sep);  
955     SeqEntrySetScope (sep);
956 
957     BuildDefLineFeatClauseList (sep, bfp->input_entityID, &feature_requests,
958                                 DEFAULT_ORGANELLE_CLAUSE, FALSE, FALSE,
959                                 &defline_clauses);
960     if ( AreFeatureClausesUnique (defline_clauses))
961     {
962       modifier_indices = GetModifierIndicesFromModList (modList);
963     }
964     else
965     {
966       modifier_indices = FindBestModifiersForDeflineClauseList (defline_clauses, modList);
967     }
968 
969     BuildDefinitionLinesFromFeatureClauseLists (defline_clauses, modList,
970                                                 modifier_indices, &odmp);
971 
972     DefLineFeatClauseListFree (defline_clauses);
973     if (modList != NULL)
974     {
975       for (index=0; index < NumDefLineModifiers (); index++)
976       {
977         ValNodeFree (modList[index].values_seen);
978       }
979       MemFree (modList);
980     }
981     modifier_indices = ValNodeFree (modifier_indices);
982 
983     ClearProteinTitlesInNucProts (bfp->input_entityID, NULL);
984     InstantiateProteinTitles (bfp->input_entityID, NULL);
985 
986     ArrowCursor ();
987     Update ();
988     ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);  
989     ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
990     SeqEntrySetScope (NULL);
991   }
992 }
993 
994 
995 static const Int4 s_auto_def_id_preferred_quals[] = {
996   DEFLINE_POS_Strain,
997   DEFLINE_POS_Clone,
998   DEFLINE_POS_Isolate,
999   DEFLINE_POS_Cultivar,
1000   DEFLINE_POS_Specimen_voucher,
1001 };
1002 
1003 static const Int4 k_num_auto_def_id_preferred_quals = sizeof (s_auto_def_id_preferred_quals) / sizeof (Int4);
1004 
1005 extern void AutoDefId (Uint2 entityID)
1006 {
1007   SeqEntryPtr sep;
1008   DeflineFeatureRequestList feature_requests;
1009   ModifierItemLocalPtr modList;
1010   ValNodePtr modifier_indices = NULL;
1011   OrganismDescriptionModifiers odmp;
1012   Int4 index;
1013   Boolean added_required = FALSE;
1014   ValNodePtr defline_clauses = NULL;
1015 
1016   sep = GetTopSeqEntryForEntityID (entityID);
1017   if (sep == NULL) return;
1018 
1019   InitFeatureRequests (&feature_requests);
1020 
1021   modList = MemNew (NumDefLineModifiers () * sizeof (ModifierItemLocalData));
1022   if (modList == NULL) return;
1023   SetRequiredModifiers (modList);
1024   CountModifiers (modList, sep);
1025   /* first look for first modifier in list that is present on all sources */
1026   for (index = 0; index < k_num_auto_def_id_preferred_quals && !added_required; index++) {
1027     if (modList[s_auto_def_id_preferred_quals[index]].all_present) {
1028       modList[s_auto_def_id_preferred_quals[index]].required = TRUE;
1029       added_required = TRUE;
1030     }
1031   }
1032   /* if not found, then look for first modifier in list that is present on any sources */
1033   for (index = 0; index < k_num_auto_def_id_preferred_quals && !added_required; index++) {
1034     if (modList[s_auto_def_id_preferred_quals[index]].any_present) {
1035       modList[s_auto_def_id_preferred_quals[index]].required = TRUE;
1036       added_required = TRUE;
1037     }
1038   }
1039 
1040   WatchCursor ();
1041   Update ();
1042   InitOrganismDescriptionModifiers (&odmp, sep);
1043   odmp.use_modifiers = TRUE;
1044 
1045   RemoveNucProtSetTitles (sep);  
1046   SeqEntrySetScope (sep);
1047 
1048   BuildDefLineFeatClauseList (sep, entityID, &feature_requests,
1049                               DEFAULT_ORGANELLE_CLAUSE, FALSE, FALSE,
1050                               &defline_clauses);
1051   if ( AreFeatureClausesUnique (defline_clauses))
1052   {
1053     modifier_indices = GetModifierIndicesFromModList (modList);
1054   }
1055   else
1056   {
1057     modifier_indices = FindBestModifiersForDeflineClauseList (defline_clauses, modList);
1058   }
1059 
1060   BuildDefinitionLinesFromFeatureClauseLists (defline_clauses, modList,
1061                                               modifier_indices, &odmp);
1062 
1063   DefLineFeatClauseListFree (defline_clauses);
1064   if (modList != NULL)
1065   {
1066     for (index=0; index < NumDefLineModifiers (); index++)
1067     {
1068       ValNodeFree (modList[index].values_seen);
1069     }
1070     MemFree (modList);
1071   }
1072   modifier_indices = ValNodeFree (modifier_indices);
1073 
1074   ClearProteinTitlesInNucProts (entityID, NULL);
1075   InstantiateProteinTitles (entityID, NULL);
1076 
1077 }
1078 
1079 
1080 extern void AutoDefStrain (
1081   BaseFormPtr bfp
1082 )
1083 {
1084 
1085   if (bfp == NULL) return;
1086 
1087   WatchCursor ();
1088   Update ();
1089   AutoDefId (bfp->input_entityID);
1090 
1091   ArrowCursor ();
1092   Update ();
1093   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);  
1094   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1095   SeqEntrySetScope (NULL);
1096 }
1097 
1098 
1099 extern void AutoDefMiscFeat (
1100   BaseFormPtr bfp
1101 )
1102 {
1103   SeqEntryPtr sep;
1104   DeflineFeatureRequestList feature_requests;
1105   ModifierItemLocalPtr modList;
1106   ValNodePtr modifier_indices = NULL;
1107   OrganismDescriptionModifiers odmp;
1108   Int4 index;
1109   ValNodePtr defline_clauses = NULL;
1110 
1111   if (bfp == NULL) return;
1112   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1113   if (sep == NULL) return;
1114 
1115   InitFeatureRequests (&feature_requests);
1116   feature_requests.keep_items[RemovableNoncodingProductFeat] = TRUE;
1117 
1118   modList = MemNew (NumDefLineModifiers () * sizeof (ModifierItemLocalData));
1119   if (modList == NULL) return;
1120   SetRequiredModifiers (modList);
1121   CountModifiers (modList, sep);
1122 
1123   WatchCursor ();
1124   Update ();
1125   InitOrganismDescriptionModifiers (&odmp, sep);
1126   odmp.use_modifiers = TRUE;
1127 
1128   RemoveNucProtSetTitles (sep);  
1129   SeqEntrySetScope (sep);
1130 
1131   BuildDefLineFeatClauseList (sep, bfp->input_entityID, &feature_requests,
1132                               DEFAULT_ORGANELLE_CLAUSE, FALSE, FALSE,
1133                               &defline_clauses);
1134   if ( AreFeatureClausesUnique (defline_clauses))
1135   {
1136     modifier_indices = GetModifierIndicesFromModList (modList);
1137   }
1138   else
1139   {
1140     modifier_indices = FindBestModifiersForDeflineClauseList (defline_clauses, modList);
1141   }
1142 
1143   BuildDefinitionLinesFromFeatureClauseLists (defline_clauses, modList,
1144                                               modifier_indices, &odmp);
1145 
1146   DefLineFeatClauseListFree (defline_clauses);
1147   if (modList != NULL)
1148   {
1149     for (index=0; index < NumDefLineModifiers (); index++)
1150     {
1151       ValNodeFree (modList[index].values_seen);
1152     }
1153     MemFree (modList);
1154   }
1155   modifier_indices = ValNodeFree (modifier_indices);
1156 
1157   ClearProteinTitlesInNucProts (bfp->input_entityID, NULL);
1158   InstantiateProteinTitles (bfp->input_entityID, NULL);
1159 
1160   ArrowCursor ();
1161   Update ();
1162   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);  
1163   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1164   SeqEntrySetScope (NULL);
1165 }
1166 
1167 
1168 static void AutoDefCommon (IteM i, Boolean use_form, Boolean use_modifiers)
1169 {
1170   BaseFormPtr  bfp;
1171 
1172 #ifdef WIN_MAC
1173   bfp = currentFormDataPtr;
1174 #else
1175   bfp = GetObjectExtra (i);
1176 #endif
1177   if (bfp == NULL || bfp->input_entityID == 0) return;
1178   AutoDefBaseFormCommon (bfp, use_form, use_modifiers);
1179 }
1180 
1181 extern void AutoDef (IteM i)
1182 {
1183   AutoDefCommon (i, FALSE, TRUE);
1184 }
1185 
1186 extern void AutoDefWithOptions (IteM i)
1187 {
1188   AutoDefCommon (i, TRUE, TRUE);
1189 }
1190 
1191 
1192 extern void AutoDefWithoutModifiers (IteM i)
1193 {
1194   AutoDefCommon (i, FALSE, FALSE);
1195 }
1196 
1197 extern void AutoDefToolBtn (ButtoN b)
1198 {
1199   BaseFormPtr  bfp;
1200 
1201   bfp = (BaseFormPtr) GetObjectExtra (b);
1202   if (bfp == NULL) return;
1203   AutoDefBaseFormCommon (bfp, FALSE, TRUE);
1204 }
1205 
1206 extern void AutoDefOptionsToolBtn (ButtoN b)
1207 {
1208   BaseFormPtr  bfp;
1209 
1210   bfp = (BaseFormPtr) GetObjectExtra (b);
1211   if (bfp == NULL) return;
1212   AutoDefBaseFormCommon (bfp, TRUE, TRUE);
1213 }
1214 
1215 
1216 extern void AutoDefStrainToolBtn (ButtoN b)
1217 {
1218   BaseFormPtr  bfp;
1219 
1220   bfp = (BaseFormPtr) GetObjectExtra (b);
1221   if (bfp == NULL) return;
1222   AutoDefStrain (bfp);
1223 }
1224 
1225 
1226 extern void AutoDefMiscFeatToolBtn (ButtoN b)
1227 {
1228   BaseFormPtr  bfp;
1229 
1230   bfp = (BaseFormPtr) GetObjectExtra (b);
1231   if (bfp == NULL) return;
1232   AutoDefMiscFeat (bfp);
1233 }
1234 
1235 
1236 static void TrimQuotesAroundString (CharPtr str)
1237 {
1238   Int4 len;
1239   CharPtr src, dst;
1240 
1241   if (StringHasNoText (str) || *str != '"') return;
1242   len = StringLen (str);
1243   if (str[len - 1] != '"') return;
1244   src = str + 1;
1245   dst = str;
1246   while (*src != '"')
1247   {
1248     *dst = *src;
1249     dst++;
1250     src++;
1251   }
1252   *dst = 0;
1253 }
1254 
1255 
1256 typedef struct tablelinedata {
1257   Int4 num_parts;
1258   ValNodePtr parts;
1259 } TableLineData, PNTR TableLinePtr;
1260 
1261 static TableLinePtr MakeTableData (CharPtr line, ValNodePtr PNTR special_list)
1262 {
1263   TableLinePtr tlp;
1264   CharPtr p_start, p_end;
1265   Int4    plen;
1266   Boolean found_end;
1267   CharPtr val;
1268   ValNodePtr vnp;
1269 
1270   if (line == NULL) return NULL;
1271   tlp = MemNew (sizeof (TableLineData));
1272   if (tlp == NULL) return NULL;
1273   p_start = line;
1274   found_end = FALSE;
1275   while (*p_start != 0 && !found_end)
1276   {
1277     plen = StringCSpn (p_start, "\t\n");
1278     if (plen == 0)
1279     {
1280       ValNodeAddStr (&tlp->parts, 0, StringSave (""));
1281       tlp->num_parts ++;
1282       p_start++;
1283       if (*p_start == 0) {
1284         if (tlp->num_parts > 0)
1285         {
1286           ValNodeAddStr (&tlp->parts, 0, StringSave (""));
1287           tlp->num_parts ++;
1288         }
1289       }
1290       continue;
1291     }
1292     if (plen == StringLen (p_start))
1293     {
1294       found_end = TRUE;
1295     }
1296     else
1297     {
1298       p_end = p_start + plen;
1299       *p_end = 0;
1300     }
1301     TrimSpacesAroundString (p_start);
1302     TrimQuotesAroundString (p_start);
1303     val = StringSave (p_start);
1304 
1305     vnp = ValNodeAddStr (&tlp->parts, 0, val);
1306     SpecialCharFindWithContext ((CharPtr PNTR)&(vnp->data.ptrvalue), special_list, NULL, NULL);
1307     tlp->num_parts ++;
1308     if (!found_end)
1309     {
1310       p_start = p_end + 1;
1311     }
1312   }
1313   if (tlp->num_parts == 0)
1314   {
1315     MemFree (tlp);
1316     return NULL;
1317   } 
1318   return tlp;  
1319 }
1320 
1321 static void CleanUpTableData (ValNodePtr vnp)
1322 {
1323   TableLinePtr tlp;
1324   ValNodePtr   vnp_next;
1325 
1326   while (vnp != NULL)
1327   {
1328     vnp_next = vnp->next;
1329     vnp->next = NULL;
1330     tlp = vnp->data.ptrvalue;
1331     if (tlp != NULL)
1332     {
1333       ValNodeFreeData (tlp->parts);
1334     }
1335     vnp = ValNodeFree (vnp);
1336     vnp = vnp_next;
1337   }
1338 }
1339 
1340 static void FormatPopupWithTableDataColumns (PopuP p, ValNodePtr header_line)
1341 {
1342   TableLinePtr tlp;
1343   ValNodePtr   vnp;
1344   CharPtr      val_fmt = "Column %d (%s)";
1345   CharPtr      val;
1346   Int4         col = 1;
1347 
1348   if (p == NULL || header_line == NULL) return;
1349   tlp = (TableLinePtr) header_line->data.ptrvalue;
1350   while ((tlp == NULL || tlp->num_parts < 1) && header_line->next != NULL) {
1351     header_line = header_line->next;
1352     tlp = header_line->data.ptrvalue;
1353   }
1354   if (tlp == NULL || tlp->num_parts < 1) return;
1355   vnp = tlp->parts;
1356   while (vnp != NULL) {
1357     val = MemNew ((StringLen(val_fmt) + StringLen (vnp->data.ptrvalue) + 15) * sizeof (Char));
1358     sprintf (val, val_fmt, col, vnp->data.ptrvalue == NULL ? "" : vnp->data.ptrvalue);
1359     PopupItem (p, val);
1360     MemFree (val);
1361     vnp = vnp->next;
1362     col++;
1363   }
1364 }
1365 
1366 
1367 enum orgmodmatchtype 
1368 {
1369   eMatchAccession = 1,
1370   eMatchLocalID,
1371   eMatchTaxName,
1372   eMatchTMSMART,
1373   eMatchBankIt,
1374   eMatchGeneral,
1375   eMatchNone
1376 };
1377 
1378 
1379 typedef struct orgmodtablecolumn {
1380   Int4       match_choice;
1381   ValNodePtr apply_choice;
1382 } OrgModTableColumnData, PNTR OrgModTableColumnPtr;
1383 
1384 
1385 static OrgModTableColumnPtr OrgModTableColumnFree (OrgModTableColumnPtr t)
1386 {
1387   if (t != NULL) {
1388     t->apply_choice = ValNodeFreeData (t->apply_choice);
1389     t = MemFree (t);
1390   }
1391   return t;
1392 }
1393 
1394 
1395 static ValNodePtr OrgModTableColumnListFree (ValNodePtr vnp)
1396 {
1397   ValNodePtr vnp_next;
1398 
1399   while (vnp != NULL) 
1400   {
1401     vnp_next = vnp->next;
1402     vnp->next = NULL;
1403     vnp->data.ptrvalue = OrgModTableColumnFree (vnp->data.ptrvalue);
1404     vnp = ValNodeFree (vnp);
1405     vnp = vnp_next;
1406   }
1407   return vnp;
1408 }
1409 
1410 
1411 typedef struct orgmodtablecolumndlg {
1412   DIALOG_MESSAGE_BLOCK
1413 
1414   GrouP  action_choice;
1415   PopuP  match_choice;
1416   DialoG apply_choice;
1417  
1418   Nlm_ChangeNotifyProc change_notify;
1419   Pointer              change_userdata;
1420 } OrgModTableColumnDlgData, PNTR OrgModTableColumnDlgPtr;
1421 
1422 static Pointer OrgModTableColumnDialogToData (DialoG d)
1423 {
1424   OrgModTableColumnPtr o;
1425   OrgModTableColumnDlgPtr dlg;
1426   
1427   dlg = (OrgModTableColumnDlgPtr) GetObjectExtra (d);
1428   if (dlg == NULL) return NULL;
1429 
1430   o = (OrgModTableColumnPtr) MemNew (sizeof (OrgModTableColumnData));
1431 
1432   if (GetValue (dlg->action_choice) == 1) 
1433   {
1434     o->match_choice = GetValue (dlg->match_choice);
1435     o->apply_choice = NULL;
1436   }
1437   else
1438   {
1439     o->match_choice = 0;
1440     o->apply_choice = DialogToPointer (dlg->apply_choice);
1441   }
1442   return o;
1443 }
1444 
1445 
1446 static void ChangeOrgModTableColumnMatchChoice (PopuP p)
1447 {
1448   OrgModTableColumnDlgPtr dlg;
1449 
1450   dlg = (OrgModTableColumnDlgPtr) GetObjectExtra (p);
1451   if (dlg == NULL) return;
1452   if (dlg->change_notify != NULL) 
1453   {
1454     (dlg->change_notify) (dlg->change_userdata);
1455   }  
1456 }
1457   
1458 
1459 static void ChangeOrgModTableColumnActionChoice (GrouP g)
1460 {
1461   OrgModTableColumnDlgPtr dlg;
1462 
1463   dlg = (OrgModTableColumnDlgPtr) GetObjectExtra (g);
1464   if (dlg == NULL) return;
1465 
1466   if (GetValue (dlg->action_choice) == 1)
1467   {
1468     Enable (dlg->match_choice);
1469     Disable (dlg->apply_choice);
1470   }
1471   else
1472   {
1473     Enable (dlg->apply_choice);
1474     Disable (dlg->match_choice);
1475   }  
1476   if (dlg->change_notify != NULL) 
1477   {
1478     (dlg->change_notify) (dlg->change_userdata);
1479   }  
1480 }
1481 
1482 
1483 static void OrgModTableColumnDataToDialog (DialoG d, Pointer data)
1484 {
1485   OrgModTableColumnPtr o;
1486   OrgModTableColumnDlgPtr dlg;
1487   
1488   dlg = (OrgModTableColumnDlgPtr) GetObjectExtra (d);
1489   if (dlg == NULL) return;
1490 
1491   o = (OrgModTableColumnPtr) data;
1492 
1493   if (o == NULL)
1494   {
1495     SetValue (dlg->action_choice, 1);
1496     SetValue (dlg->match_choice, eMatchNone);
1497     PointerToDialog (dlg->apply_choice, NULL);
1498   }
1499   else
1500   {
1501     if (o->match_choice == 0)
1502     {
1503       SetValue (dlg->action_choice, 2);
1504       PointerToDialog (dlg->apply_choice, o->apply_choice);
1505     } 
1506     else
1507     {
1508       SetValue (dlg->action_choice, 1);
1509       SetValue (dlg->match_choice, o->match_choice);
1510     }
1511   }
1512   ChangeOrgModTableColumnActionChoice (dlg->action_choice);
1513 }
1514 
1515 
1516 static DialoG 
1517 OrgModTableColumnDialog 
1518 (GrouP                h,
1519  CharPtr              value_string,
1520  Int4                 num_blank,
1521  Nlm_ChangeNotifyProc change_notify,
1522  Pointer              change_userdata)
1523 {
1524   OrgModTableColumnDlgPtr dlg;
1525   GrouP            p, g;
1526   ValNodePtr       qual_selection_list;
1527   CharPtr real_title;
1528   CharPtr title_fmt = "%s (%d are blank)";
1529 
1530   dlg = (OrgModTableColumnDlgPtr) MemNew (sizeof (OrgModTableColumnDlgData));
1531 
1532   if (num_blank > 0) {
1533     real_title = (CharPtr) MemNew (sizeof (Char) * (StringLen (title_fmt) + StringLen (value_string) + 15));
1534     sprintf (real_title, title_fmt, value_string, num_blank);
1535   } else {
1536     real_title = value_string;
1537   }
1538 
1539   p = NormalGroup (h, 3, 0, real_title, programFont, NULL);
1540   SetObjectExtra (p, dlg, StdCleanupExtraProc);
1541 
1542   if (real_title != value_string) {
1543     real_title = MemFree (real_title);
1544   }
1545 
1546   dlg->dialog = (DialoG) p;
1547   dlg->fromdialog = OrgModTableColumnDialogToData;
1548   dlg->todialog = OrgModTableColumnDataToDialog;
1549   dlg->change_notify = change_notify;
1550   dlg->change_userdata = change_userdata;
1551 
1552   dlg->action_choice = HiddenGroup (p, 0, 2, ChangeOrgModTableColumnActionChoice);
1553   SetObjectExtra (dlg->action_choice, dlg, NULL);
1554   SetGroupSpacing (dlg->action_choice, 10, 10);
1555   RadioButton (dlg->action_choice, "Match to");
1556   RadioButton (dlg->action_choice, "Apply to");
1557   SetValue (dlg->action_choice, 1);
1558 
1559   g = HiddenGroup (p, 0, 3, NULL);
1560   /* list of matchable items */
1561   dlg->match_choice = PopupList (g, TRUE, ChangeOrgModTableColumnMatchChoice);
1562   SetObjectExtra (dlg->match_choice, dlg, NULL);
1563   PopupItem (dlg->match_choice, "Accession");
1564   PopupItem (dlg->match_choice, "Local ID");
1565   PopupItem (dlg->match_choice, "Organism Taxonomy Name");
1566   PopupItem (dlg->match_choice, "TMSMART ID");
1567   PopupItem (dlg->match_choice, "BankIt ID");
1568   PopupItem (dlg->match_choice, "General ID");
1569   PopupItem (dlg->match_choice, "None");
1570   SetValue (dlg->match_choice, eMatchNone);
1571 
1572 
1573   /* list of organism modifiers */
1574   qual_selection_list = GetSourceQualDescList (TRUE, TRUE, FALSE, FALSE);
1575   
1576   ValNodeAddPointer (&qual_selection_list, 1, StringSave ("Tax Name"));
1577   
1578     /* note - the ValNodeSelectionDialog will free the qual_selection_list when done */
1579   dlg->apply_choice = ValNodeSelectionDialog (g, qual_selection_list, 8, SourceQualValNodeName,
1580                                 ValNodeSimpleDataFree, SourceQualValNodeDataCopy,
1581                                 SourceQualValNodeMatch, "qual choice", 
1582                                 change_notify, change_userdata, FALSE);
1583 
1584   ChangeOrgModTableColumnActionChoice(dlg->action_choice);
1585   return (DialoG) p;  
1586 }
1587 
1588 
1589 typedef struct orgmodloadformdata {
1590   FEATURE_FORM_BLOCK
1591 
1592   ValNodePtr        line_list;
1593   BioSourcePtr PNTR biop_list;
1594   DialoG PNTR       columns;
1595   Int4              num_columns;
1596   Uint2             entityID;
1597   ButtoN            replace_with_blank_btn;
1598   ButtoN            accept_button;
1599   ButtoN            leave_dlg_up_btn;
1600   DialoG            taxname_options;
1601 
1602   /* These members are for importing modifiers in the
1603    * submission dialogs.
1604    */
1605   SeqEntryPtr       seq_list;
1606   Boolean           done;
1607   Boolean           mods_added;
1608   
1609 } OrgModLoadFormData, PNTR OrgModLoadFormPtr;
1610 
1611 static void SetFormModsEnable (Pointer userdata)
1612 {
1613   OrgModLoadFormPtr form_data;
1614   OrgModTableColumnPtr o;
1615   Boolean           have_apply = FALSE;
1616   Boolean           have_action = FALSE;
1617   Boolean           have_apply_taxname = FALSE;
1618   Int4              column_index;
1619 
1620   form_data = (OrgModLoadFormPtr) userdata;
1621   if (form_data == NULL) return;
1622  
1623   for (column_index = 0;
1624        column_index < form_data->num_columns;
1625        column_index ++)
1626   {
1627     o = (OrgModTableColumnPtr) DialogToPointer (form_data->columns[column_index]);
1628     if (o == NULL) continue;
1629     if (o->match_choice > 0 && o->match_choice != eMatchNone)
1630     {
1631       have_action = TRUE;
1632     }
1633     else if (o->apply_choice != NULL) 
1634     {
1635       have_apply = TRUE;
1636       if (o->apply_choice->choice > 0 && StringCmp (o->apply_choice->data.ptrvalue, "Tax Name") == 0)
1637       {
1638         have_apply_taxname = TRUE;
1639       }
1640     }
1641     o = OrgModTableColumnFree (o);
1642   }
1643 
1644   if (have_apply_taxname)
1645   {
1646     Enable (form_data->taxname_options);
1647   }
1648   else
1649   {
1650     Disable (form_data->taxname_options);
1651   }
1652 
1653   /* must have an action selected if there is more than one line */
1654   if ( ! have_action
1655     && form_data->line_list != NULL
1656     && form_data->line_list->next != NULL)
1657   {
1658     Disable (form_data->accept_button);
1659     return;
1660   }
1661 
1662   if (have_apply)
1663   {
1664     Enable (form_data->accept_button);
1665   }
1666   else
1667   {
1668     Disable (form_data->accept_button);
1669   }
1670 }
1671 
1672 static void CleanupOrgModLoadForm (
1673   GraphiC g,
1674   VoidPtr data
1675 )
1676 {
1677   OrgModLoadFormPtr form_data;
1678 
1679   form_data = (OrgModLoadFormPtr)data;
1680   if (form_data == NULL) return;
1681   form_data->columns = MemFree (form_data->columns);
1682   CleanUpTableData (form_data->line_list);
1683   StdCleanupFormProc (g, data);
1684 } 
1685 
1686 static CharPtr genome_names[] = 
1687 {
1688   "",
1689   "genomic",
1690   "chloroplast",
1691   "chromoplast",
1692   "kinteoplast",
1693   "mitochondrion",
1694   "plastid",
1695   "macronuclear",
1696   "extrachrom",
1697   "plasmid",
1698   "transposon",
1699   "insertion_seq",
1700   "cyanelle",
1701   "proviral",
1702   "virion",
1703   "nucleomorph",
1704   "apicoplast",
1705   "leucoplast",
1706   "proplastid",
1707   "endogenous_virus",
1708   "hydrogenosome",
1709   "chromosome",
1710   "chromatophore"
1711 };
1712 
1713 static Uint1 GetGenomeValFromString (CharPtr value_string)
1714 {
1715   Uint1 genome_val;
1716   
1717   if (StringHasNoText (value_string))
1718   {
1719     return 0;
1720   }
1721   for (genome_val = 1; genome_val < sizeof (genome_names); genome_val++)
1722   {
1723     if (StringICmp (value_string, genome_names[genome_val]) == 0)
1724     {
1725       return genome_val;
1726     }
1727   }
1728   return 0;
1729 }
1730 
1731 
1732 static void AddOneQualToOrg 
1733 ( BioSourcePtr biop,
1734   CharPtr      value_string,
1735   SourceQualDescPtr sqdp,
1736   ExistingTextPtr etp)
1737 {
1738   OrgRefPtr     orp;
1739   OrgModPtr     mod, last_mod;
1740   OrgNamePtr    onp;
1741   SubSourcePtr  ssp, last_ssp;
1742 
1743   if (biop == NULL || value_string == NULL || sqdp == NULL) return;
1744 
1745   orp = biop->org;
1746   if (orp == NULL) return;
1747 
1748   if (sqdp->isOrgMod)
1749   {
1750     onp = orp->orgname;
1751     if (onp == NULL) {
1752       onp = OrgNameNew ();
1753       if (onp == NULL) return;
1754       orp->orgname = onp;
1755     }
1756     mod = onp->mod;
1757     last_mod = NULL;
1758     while (mod != NULL
1759       && mod->subtype != sqdp->subtype)
1760     {
1761       last_mod = mod;
1762       mod = mod->next;
1763     }
1764     if (mod != NULL)
1765     {
1766       if (StringHasNoText (value_string)) {
1767         if (last_mod == NULL) {
1768           onp->mod = mod->next;
1769         } else {
1770           last_mod->next = mod->next;
1771         }
1772         mod->next = NULL;
1773         mod = OrgModFree (mod);
1774       } else {
1775         mod->subname = HandleExistingText (mod->subname,
1776                                            StringSave (value_string),
1777                                            etp); 
1778       }
1779     }
1780     else if (!StringHasNoText (value_string))
1781     {
1782       mod = OrgModNew ();
1783       mod->subtype = sqdp->subtype;
1784       mod->subname = StringSave (value_string);
1785       if (last_mod == NULL)
1786       {
1787         onp->mod = mod;
1788       }
1789       else
1790       {
1791         last_mod->next = mod;
1792       }
1793     }
1794   } else {
1795     ssp = biop->subtype;
1796     last_ssp = NULL;
1797     while (ssp != NULL && ssp->subtype != sqdp->subtype)
1798     {
1799       last_ssp = ssp;
1800       ssp = ssp->next;
1801     }
1802     if (ssp != NULL)
1803     {
1804       if (StringHasNoText (value_string)) {
1805         if (last_ssp == NULL) {
1806           biop->subtype = ssp->next;
1807         } else {
1808           last_ssp->next = ssp->next;
1809         }
1810         ssp->next = NULL;
1811         ssp = SubSourceFree (ssp);
1812       } else {
1813         ssp->name = HandleExistingText (ssp->name,
1814                                         StringSave (value_string),
1815                                         etp);
1816       }
1817     }
1818     else if (!StringHasNoText (value_string))
1819     {
1820       ssp = SubSourceNew ();
1821       ssp->subtype = sqdp->subtype;
1822       ssp->name = StringSave (value_string);
1823       if (last_ssp == NULL)
1824       {
1825         biop->subtype = ssp;
1826       }
1827       else
1828       {
1829         last_ssp->next = ssp;
1830       }
1831     }
1832   }
1833 }
1834 
1835 static void ApplyTaxNameToOrg (BioSourcePtr biop, CharPtr value_string, ExistingTextPtr etp)
1836 {
1837   if (biop == NULL) return;
1838   if (biop->org == NULL)
1839   {
1840         biop->org = OrgRefNew ();
1841   }
1842   if (biop->org == NULL) return;
1843   biop->org->taxname = HandleExistingText (biop->org->taxname,
1844                                            StringSave (value_string),
1845                                            etp);
1846 }
1847 
1848 static void ApplyLocationToOrg (BioSourcePtr biop, CharPtr value_string)
1849 {
1850   if (biop != NULL)
1851   {
1852     biop->genome = GetGenomeValFromString (value_string);
1853   }
1854 }
1855 
1856 
1857 static Boolean HasExtraAccession (
1858   CharPtr acc_str,
1859   GBBlockPtr gbp)
1860 {
1861   ValNodePtr vnp;
1862   if (acc_str == NULL || gbp == NULL) return FALSE;
1863   for (vnp = gbp->extra_accessions;
1864        vnp != NULL && StringCmp (acc_str, vnp->data.ptrvalue) != 0;
1865        vnp = vnp->next)
1866   {}
1867   if (vnp != NULL)
1868     return TRUE;
1869   else
1870     return FALSE;
1871 }
1872 
1873 static Boolean
1874 IDIsInTextList 
1875 (CharPtr id,
1876  CharPtr acc_str,
1877  Boolean look_for_tmsmart)
1878 {
1879   CharPtr wanted, found;
1880   Int4    len;
1881 
1882   if (id == NULL || acc_str == NULL) return FALSE;
1883 
1884   if (StringNCmp (acc_str, "TMSMART:", 8) == 0) {
1885     if (look_for_tmsmart) {
1886       wanted = acc_str + 8;
1887     } else {
1888       return FALSE;
1889     }
1890   } else {
1891     if (look_for_tmsmart) {
1892       return FALSE;
1893     } else {
1894       wanted = acc_str;
1895     }
1896   }
1897   len = StringLen (wanted);
1898   found = StringStr (id, wanted);
1899   if (found == NULL) {
1900     return FALSE;
1901   } else if (*(found + len) != 0 
1902              && *(found + len) != ','
1903              && ! isspace ((Int4)*(found + len))) {
1904     return FALSE;
1905   } else if (found != id
1906              && * (found - 1) != ','
1907              && ! isspace ((Int4)*(found - 1))) {
1908     return FALSE;
1909   } else {
1910     return TRUE;
1911   }
1912 }
1913 
1914 static Boolean IDListHasValue (
1915   CharPtr id,
1916   SeqIdPtr list,
1917   Boolean only_local,
1918   Boolean look_for_tmsmart,
1919   Boolean look_for_general)
1920 {
1921   SeqIdPtr sip;
1922   Char     acc_str [256];
1923   Int4     match_len, match_len2, db_len;
1924   DbtagPtr gnl_tag; 
1925 
1926   for (sip = list; sip != NULL; sip = sip->next)
1927   {
1928     if (sip->choice == SEQID_GENERAL 
1929         && look_for_general 
1930         && StringNICmp (id, "gnl|", 3) == 0
1931         && (db_len = StringCSpn (id + 4, "|")) > 0)
1932     {
1933       gnl_tag = (DbtagPtr) sip->data.ptrvalue;
1934       if (gnl_tag != NULL
1935           && StringNCmp (id + 4, gnl_tag->db, db_len) == 0
1936           && ((gnl_tag->tag->id > 0 && atoi (id + 5 + db_len) == gnl_tag->tag->id)
1937              || StringCmp (gnl_tag->tag->str, id + 5 + db_len) == 0))
1938       {
1939         return TRUE;
1940       }
1941     }
1942     if ((! only_local && sip->choice != SEQID_LOCAL)
1943       || (only_local && sip->choice == SEQID_LOCAL))
1944     {
1945       SeqIdWrite (sip, acc_str, PRINTID_REPORT, sizeof (acc_str));
1946       if (look_for_tmsmart)
1947       {
1948         if (StringNCmp (acc_str, "TMSMART:", 8) == 0
1949           && StringCmp (id, acc_str + 8) == 0)
1950         {
1951           return TRUE;
1952         } else if (IDIsInTextList (id, acc_str, TRUE)) {
1953           return TRUE;
1954         }
1955       } else {
1956         if (only_local)
1957         {
1958           if (StringCmp (id, acc_str) == 0)
1959           {
1960                 return TRUE;
1961           }
1962         }
1963         else 
1964         {
1965           match_len = StringCSpn (acc_str, ".");
1966           match_len2 = StringCSpn (id, ".");
1967           if (match_len == match_len2
1968             && match_len > 0 && StringNCmp (id, acc_str, match_len) == 0)
1969           {
1970             return TRUE;
1971           }
1972         }
1973       }
1974     }
1975   }
1976   return FALSE;
1977 }
1978 
1979 
1980 static CharPtr FindBankitNumberInTableString (CharPtr table_string)
1981 {
1982   CharPtr bankit_start;
1983   
1984   if (StringHasNoText (table_string))
1985   {
1986     return table_string;
1987   }
1988   bankit_start = table_string + StringSpn (table_string, " ");
1989   if (StringNICmp (bankit_start, "bankit", 6) == 0)
1990   {
1991     bankit_start += 6;
1992     bankit_start += StringSpn (bankit_start, " ");
1993   }
1994   return bankit_start;
1995 }
1996 
1997 
1998 
1999 typedef struct applycolumn {
2000   ValNodePtr apply_choice;
2001   CharPtr    apply_value;
2002 } ApplyColumnData, PNTR ApplyColumnPtr;
2003 
2004 
2005 static ApplyColumnPtr ApplyColumnFree (ApplyColumnPtr p)
2006 {
2007   if (p != NULL) {
2008     p->apply_value = MemFree (p->apply_value);
2009     p->apply_choice = ValNodeFreeData (p->apply_choice);
2010     p = MemFree (p);
2011   }
2012   return p;
2013 }
2014 
2015 
2016 static ValNodePtr ApplyColumnListFree (ValNodePtr vnp)
2017 {
2018   ValNodePtr vnp_next;
2019 
2020   while (vnp != NULL) {
2021     vnp_next = vnp->next;
2022     vnp->next = NULL;
2023     vnp->data.ptrvalue = ApplyColumnFree (vnp->data.ptrvalue);
2024     vnp = ValNodeFree (vnp);
2025     vnp = vnp_next;
2026   }
2027   return vnp;
2028 }
2029 
2030 
2031 typedef struct tabletobiosource {
2032   ValNodePtr identifiers;
2033   ValNodePtr columns_to_apply;
2034   ValNodePtr biop_list;
2035 } TableToBioSourceData, PNTR TableToBioSourcePtr;
2036 
2037 
2038 static TableToBioSourcePtr TableToBioSourceFree (TableToBioSourcePtr t)
2039 {
2040   if (t != NULL) {
2041     t->identifiers = ValNodeFreeData (t->identifiers);
2042     t->columns_to_apply = ApplyColumnListFree (t->columns_to_apply);
2043     t->biop_list = ValNodeFree (t->biop_list);
2044     t = MemFree (t);
2045   }
2046   return t;
2047 }
2048 
2049 
2050 static ValNodePtr TableToBioSourceListFree (ValNodePtr vnp)
2051 {
2052   ValNodePtr vnp_next;
2053 
2054   while (vnp != NULL) 
2055   {
2056     vnp_next = vnp->next;
2057     vnp->next = NULL;
2058     vnp->data.ptrvalue = TableToBioSourceFree (vnp->data.ptrvalue);
2059     vnp = ValNodeFree (vnp);
2060     vnp = vnp_next;;
2061   }
2062   return vnp;
2063 }
2064 
2065 
2066 static TableToBioSourcePtr TableToBioSourceFromTableLine (OrgModTableColumnPtr PNTR o_list, Int4 num_columns, TableLinePtr tlp)
2067 {
2068   Int4       column_index;
2069   ValNodePtr part;
2070   TableToBioSourcePtr t;
2071   ApplyColumnPtr      a;
2072   
2073   if (o_list == NULL || tlp == NULL || tlp->parts == NULL) return NULL;
2074 
2075   t = (TableToBioSourcePtr) MemNew (sizeof (TableToBioSourceData));
2076   for (column_index = 0, part = tlp->parts;
2077        column_index < num_columns;
2078        column_index ++)
2079   {
2080     if (o_list[column_index] == NULL) continue;
2081     if (o_list[column_index]->match_choice > 0 
2082         && o_list[column_index]->match_choice != eMatchNone
2083         && part != NULL)
2084     {
2085       ValNodeAddPointer (&(t->identifiers), o_list[column_index]->match_choice, StringSave (part->data.ptrvalue));
2086     }
2087     else if (o_list[column_index]->apply_choice != NULL)
2088     {
2089       a = (ApplyColumnPtr) MemNew (sizeof (ApplyColumnData));
2090       a->apply_choice = SourceQualValNodeDataCopy (o_list[column_index]->apply_choice);
2091       if (part == NULL)
2092       {
2093         a->apply_value = StringSave ("");
2094       }
2095       else
2096       {   
2097         a->apply_value = StringSave (part->data.ptrvalue);
2098       }
2099 
2100       ValNodeAddPointer (&(t->columns_to_apply), 0, a);
2101     }
2102 
2103     if (column_index < tlp->num_parts && part != NULL) 
2104     {
2105       part = part->next;
2106     }
2107   }
2108   return t;
2109 }
2110 
2111 
2112 static ValNodePtr OrgModLoadFormToApplyList (OrgModLoadFormPtr f)
2113 {
2114   ValNodePtr line;
2115   ValNodePtr apply_list = NULL;
2116   Int4       column_index;
2117   OrgModTableColumnPtr PNTR o_list;
2118 
2119   if (f == NULL) return NULL;
2120 
2121   o_list = (OrgModTableColumnPtr PNTR) MemNew (f->num_columns * sizeof (OrgModTableColumnPtr));
2122   for (column_index = 0; column_index < f->num_columns; column_index++)
2123   {
2124     o_list[column_index] = (OrgModTableColumnPtr) DialogToPointer (f->columns[column_index]);
2125   }
2126 
2127   for (line = f->line_list; line != NULL; line = line->next)
2128   {
2129     ValNodeAddPointer (&apply_list, 0, TableToBioSourceFromTableLine (o_list, f->num_columns, line->data.ptrvalue));
2130   }
2131   
2132   for (column_index = 0; column_index < f->num_columns; column_index++)
2133   {
2134     o_list[column_index] = OrgModTableColumnFree (o_list[column_index]);
2135   }
2136   o_list = MemFree (o_list);
2137   return apply_list;
2138 }
2139 
2140 
2141 static void AddBioSourceToValNodeListIfNotAlreadyPresent (ValNodePtr PNTR list, BioSourcePtr biop)
2142 {
2143   ValNodePtr vnp;
2144 
2145   if (list == NULL || biop == NULL) return;
2146 
2147   vnp = *list;
2148   if (vnp == NULL) {
2149     ValNodeAddPointer (list, 0, biop);
2150   } else {
2151     while (vnp->next != NULL) {
2152       if (biop == vnp->data.ptrvalue) {
2153         return;
2154       }
2155       vnp = vnp->next;
2156     }
2157     vnp->next = ValNodeNew(NULL);
2158     vnp->next->choice = 0;
2159     vnp->next->data.ptrvalue = biop;
2160   }
2161 }
2162 
2163 
2164 static void FindOrganismsForTableToBioSourceByTaxName (BioSourcePtr biop, Pointer userdata)
2165 {
2166   ValNodePtr apply_list, vnp, vnp_id;
2167   TableToBioSourcePtr    t;  
2168 
2169   if (biop == NULL || biop->org == NULL || userdata == NULL) return;
2170 
2171   apply_list = (ValNodePtr) userdata;
2172   for (vnp = apply_list; vnp != NULL; vnp = vnp->next)
2173   {
2174     t = (TableToBioSourcePtr) vnp->data.ptrvalue;
2175     for (vnp_id = t->identifiers; vnp_id != NULL; vnp_id = vnp_id->next)
2176     {
2177       if (vnp_id->choice == eMatchTaxName && StringCmp (biop->org->taxname, vnp_id->data.ptrvalue) == 0) {
2178         AddBioSourceToValNodeListIfNotAlreadyPresent (&(t->biop_list), biop);
2179       }
2180     }
2181   }
2182 }
2183 
2184 
2185 /* look for matches based on accession numbers, local IDs, or bankit IDs */
2186 static void FindOrganismsForTableToBioSourceByBioseq (BioseqPtr bsp, Pointer userdata)
2187 {
2188   ValNodePtr             apply_list, vnp, vnp_id;
2189   TableToBioSourcePtr    t;  
2190   SeqDescrPtr            sdp;
2191   GBBlockPtr             gbp;
2192   BioSourcePtr           biop;
2193   Boolean                use_local_id, look_for_tmsmart, look_for_general;
2194   Char                   match_str [30];
2195   SeqIdPtr               sip;
2196   DbtagPtr               dp;
2197   ObjectIdPtr            oip;
2198 
2199   biop = GetBiopForBsp (bsp);
2200   if (biop == NULL || biop->org == NULL || userdata == NULL) return;
2201 
2202   apply_list = (ValNodePtr) userdata;
2203 
2204   /* Find GenBankBlockPtr for extra accessions */
2205   gbp = NULL;
2206   sdp = BioseqGetSeqDescr (bsp, Seq_descr_genbank, NULL);
2207   if (sdp != NULL)
2208   {
2209     gbp = sdp->data.ptrvalue;
2210   }
2211 
2212   /* Find Bankit ID */
2213   match_str [0] = 0;
2214   for(sip = bsp->id; sip != NULL; sip = sip->next) {
2215     if(sip->choice == SEQID_GENERAL) {
2216       dp = (DbtagPtr) sip->data.ptrvalue;
2217       if(StringICmp(dp->db, "BankIt") == 0) {
2218         oip = dp->tag;
2219         sprintf (match_str, "%d", oip->id);
2220         break;
2221       }
2222     }
2223   }
2224 
2225   for (vnp = apply_list; vnp != NULL; vnp = vnp->next)
2226   {
2227     t = (TableToBioSourcePtr) vnp->data.ptrvalue;
2228     for (vnp_id = t->identifiers; vnp_id != NULL; vnp_id = vnp_id->next)
2229     {
2230       if (vnp_id->choice == eMatchAccession 
2231           || vnp_id->choice == eMatchLocalID 
2232           || vnp_id->choice == eMatchTMSMART
2233           || vnp_id->choice == eMatchGeneral)
2234       {
2235         if (vnp_id->choice == eMatchAccession 
2236             || vnp_id->choice == eMatchTMSMART
2237             || vnp_id->choice == eMatchGeneral) {
2238           use_local_id = FALSE;
2239         } else {
2240           use_local_id = TRUE;
2241         }
2242         if (vnp_id->choice == eMatchTMSMART) {
2243           look_for_tmsmart = TRUE;
2244         } else {
2245           look_for_tmsmart = FALSE;
2246         }
2247 
2248         if (vnp_id->choice == eMatchGeneral)
2249         {
2250           look_for_general = TRUE;
2251         }
2252         else
2253         {
2254           look_for_general = FALSE;
2255         }
2256 
2257         if (IDListHasValue ( vnp_id->data.ptrvalue,
2258                             bsp->id, use_local_id, look_for_tmsmart, look_for_general)
2259               || (! use_local_id && 
2260                   HasExtraAccession ( vnp_id->data.ptrvalue, gbp)))
2261         {
2262           AddBioSourceToValNodeListIfNotAlreadyPresent (&(t->biop_list), biop);
2263         }
2264       }        
2265       else if (vnp_id->choice == eMatchBankIt) 
2266       {
2267         if (StringCmp (FindBankitNumberInTableString(vnp_id->data.ptrvalue), 
2268                           match_str) == 0) {
2269           AddBioSourceToValNodeListIfNotAlreadyPresent (&(t->biop_list), biop);
2270         }
2271       }
2272     }
2273   }
2274 }
2275 
2276   
2277 static void FindOrganismsForTableToBioSourceList (ValNodePtr apply_list, SeqEntryPtr sep)
2278 {
2279   VisitBioSourcesInSep (sep, apply_list, FindOrganismsForTableToBioSourceByTaxName);
2280   VisitBioseqsInSep (sep, apply_list, FindOrganismsForTableToBioSourceByBioseq);
2281 
2282 }
2283 
2284 
2285 static Boolean ListOrganismsWithMultipleRows (ValNodePtr apply_list)
2286 {
2287   LogInfoPtr          lip;
2288   ValNodePtr          vnp, vnp_compare, vnp_biop, vnp_biop2;
2289   BioSourcePtr        biop;
2290   TableToBioSourcePtr t, t2;
2291   Int4                row1_num, row2_num;
2292   Boolean             rval;
2293 
2294   lip = OpenLog ("Organisms Affected by More Than One Row");
2295   for (vnp = apply_list, row1_num = 0; vnp != NULL; vnp = vnp->next, row1_num++) 
2296   {
2297     t = (TableToBioSourcePtr) vnp->data.ptrvalue;
2298     if (t == NULL || t->biop_list == NULL) continue;
2299     for (vnp_biop = t->biop_list; vnp_biop != NULL; vnp_biop = vnp_biop->next)
2300     {
2301       biop = vnp_biop->data.ptrvalue;
2302       if (biop == NULL) continue;
2303       for (vnp_compare = vnp->next, row2_num = row1_num + 1; vnp_compare != NULL; vnp_compare = vnp_compare->next, row2_num++)
2304       {
2305         t2 = (TableToBioSourcePtr) vnp_compare->data.ptrvalue;
2306         for (vnp_biop2 = t2->biop_list; vnp_biop2 != NULL; vnp_biop2 = vnp_biop2->next)
2307         {
2308           if (vnp_biop2->data.ptrvalue == biop)
2309           {
2310             fprintf (lip->fp, "Two rows (%d and %d) match the same organism", row1_num, row2_num);
2311             if (t->identifiers != NULL && t->identifiers->data.ptrvalue != NULL
2312                 && t2->identifiers != NULL && t2->identifiers->data.ptrvalue != NULL)
2313             {
2314               if (StringCmp (t->identifiers->data.ptrvalue, t2->identifiers->data.ptrvalue) == 0)
2315               {
2316                 fprintf (lip->fp, " (both are %s).\n", t->identifiers->data.ptrvalue);
2317               }
2318               else
2319               {
2320                 fprintf (lip->fp, " (%s and %s).\n", t->identifiers->data.ptrvalue, t2->identifiers->data.ptrvalue);
2321               }
2322             }
2323             else if (t->identifiers != NULL && t->identifiers->data.ptrvalue != NULL)
2324             {
2325               fprintf (lip->fp, " (%s).\n", t->identifiers->data.ptrvalue);
2326             }
2327             else if (t2->identifiers != NULL && t2->identifiers->data.ptrvalue != NULL)
2328             {
2329               fprintf (lip->fp, " (%s).\n", t2->identifiers->data.ptrvalue);
2330             }
2331             else
2332             {
2333               fprintf (lip->fp, ".\n");
2334             }
2335                 
2336             lip->data_in_log = TRUE;
2337           }
2338         }
2339       }
2340     }
2341   }
2342   rval = lip->data_in_log;
2343   CloseLog (lip);
2344   FreeLog (lip);
2345   return rval;
2346 }
2347 
2348 
2349 static Boolean ListRowsWithMultipleOrganisms (ValNodePtr apply_list)
2350 {
2351   LogInfoPtr          lip;
2352   ValNodePtr          vnp, vnp_id;
2353   TableToBioSourcePtr t;
2354   Boolean             rval;
2355 
2356   lip = OpenLog ("Rows with Multiple Organisms");
2357   for (vnp = apply_list; vnp != NULL; vnp = vnp->next) 
2358   {
2359     t = (TableToBioSourcePtr) vnp->data.ptrvalue;
2360     if (t == NULL || t->biop_list == NULL || t->biop_list->next == NULL || t->identifiers == NULL) continue;
2361     fprintf (lip->fp, "Row with the following match columns applies to %d organisms\n", ValNodeLen (t->biop_list));
2362     for (vnp_id = t->identifiers; vnp_id != NULL; vnp_id = vnp_id->next) 
2363     {
2364       fprintf (lip->fp, "\t%s\n", vnp_id->data.ptrvalue);
2365     }
2366     lip->data_in_log = TRUE;
2367   }
2368 
2369   rval = lip->data_in_log;
2370   CloseLog (lip);
2371   FreeLog (lip);
2372   return rval;
2373 }
2374 
2375 
2376 static void ListRowsWithoutOrganisms (ValNodePtr apply_list)
2377 {
2378   LogInfoPtr          lip;
2379   ValNodePtr          vnp, vnp_id;
2380   TableToBioSourcePtr t;
2381 
2382   lip = OpenLog ("Rows without Organisms");
2383   for (vnp = apply_list; vnp != NULL; vnp = vnp->next) 
2384   {
2385     t = (TableToBioSourcePtr) vnp->data.ptrvalue;
2386     if (t == NULL || t->biop_list != NULL || t->identifiers == NULL) continue;
2387     for (vnp_id = t->identifiers; vnp_id != NULL; vnp_id = vnp_id->next) 
2388     {
2389       fprintf (lip->fp, "No match found for %s\n", vnp_id->data.ptrvalue);
2390       lip->data_in_log = TRUE;
2391     }
2392   }
2393 
2394   CloseLog (lip);
2395   FreeLog (lip);
2396 }
2397 
2398 
2399 /* This code is used to detect existing modifiers before a change is made */
2400 static void FindOneQualOnOrg 
2401 ( BioSourcePtr biop,
2402   SourceQualDescPtr sqdp,
2403   GetSamplePtr gsp)
2404 {
2405   OrgModPtr     mod;
2406   SubSourcePtr  ssp;
2407 
2408   if (biop == NULL || gsp == NULL || sqdp == NULL) return;
2409 
2410   if (sqdp->isOrgMod)
2411   {
2412     if (biop->org == NULL
2413         || biop->org->orgname == NULL)
2414     {
2415       return;
2416     }
2417     
2418     mod = biop->org->orgname->mod;
2419     while (mod != NULL
2420            && mod->subtype != sqdp->subtype)
2421     {
2422       mod = mod->next;
2423     }
2424     if (mod != NULL)
2425     {
2426       gsp->num_found ++;
2427       if (gsp->sample_text == NULL)
2428       {
2429         gsp->sample_text = StringSave (mod->subname);
2430       }
2431       else if (StringCmp (gsp->sample_text, mod->subname) != 0)
2432       {
2433         gsp->all_same = FALSE;
2434       }
2435     }
2436   }
2437   else
2438   {
2439     ssp = biop->subtype;
2440     while (ssp != NULL && ssp->subtype != sqdp->subtype)
2441     {
2442       ssp = ssp->next;
2443     }
2444     if (ssp != NULL)
2445     {
2446       gsp->num_found ++;
2447       if (gsp->sample_text == NULL)
2448       {
2449         gsp->sample_text = StringSave (ssp->name);
2450       }
2451       else if (StringCmp (gsp->sample_text, ssp->name) != 0)
2452       {
2453         gsp->all_same = FALSE;
2454       }
2455     }
2456   }
2457 }
2458 
2459 
2460 static GetSamplePtr DetectExistingModifiersForTableToBioSourceList (ValNodePtr apply_list, Boolean replace_with_blank)
2461 {
2462   ValNodePtr vnp, vnp_col, vnp_biop;
2463   TableToBioSourcePtr    t; 
2464   BioSourcePtr           biop; 
2465   ApplyColumnPtr         a;
2466   GetSamplePtr           gsp;
2467 
2468   gsp = GetSampleNew ();
2469   for (vnp = apply_list; vnp != NULL; vnp = vnp->next) 
2470   {
2471     t = (TableToBioSourcePtr) vnp->data.ptrvalue;
2472     for (vnp_biop = t->biop_list; vnp_biop != NULL; vnp_biop = vnp_biop->next) 
2473     {
2474       biop = vnp_biop->data.ptrvalue;
2475       for (vnp_col = t->columns_to_apply; vnp_col != NULL; vnp_col = vnp_col->next) 
2476       {
2477         a = (ApplyColumnPtr) vnp_col->data.ptrvalue;
2478 
2479         if (replace_with_blank || ! StringHasNoText (a->apply_value))
2480         {
2481           if (a->apply_choice->choice == 0 && a->apply_choice->data.ptrvalue != NULL)
2482           {
2483             FindOneQualOnOrg (biop, a->apply_choice->data.ptrvalue, gsp);
2484           }
2485           else if (a->apply_choice->choice > 0
2486                  && (StringICmp (a->apply_choice->data.ptrvalue, "Tax Name") == 0
2487                      || StringICmp (a->apply_choice->data.ptrvalue, "Organism") == 0))
2488 
2489           {  
2490             if (biop->org != NULL && !StringHasNoText (biop->org->taxname))
2491             {
2492               gsp->num_found ++;
2493               if (gsp->sample_text == NULL)
2494               {
2495                 gsp->sample_text = StringSave (biop->org->taxname);
2496               }
2497               else if (StringCmp (gsp->sample_text, biop->org->taxname) != 0)
2498               {
2499                 gsp->all_same = FALSE;
2500               }
2501             }
2502           }
2503           else if (a->apply_choice->choice > 0 && StringICmp (a->apply_choice->data.ptrvalue, "Location") == 0)
2504           {
2505             if (biop->genome > 0)
2506             {
2507               gsp->num_found ++;
2508               if (gsp->sample_text == NULL)
2509               {
2510                 gsp->sample_text = StringSave (genome_names [biop->genome]);
2511               }
2512               else if (StringCmp (gsp->sample_text, genome_names [biop->genome]) != 0)
2513               {
2514                 gsp->all_same = FALSE;
2515               }
2516             }
2517           }
2518         }        
2519       }  
2520     }
2521   }
2522   return gsp;
2523 }
2524 
2525 
2526 static void 
2527 ApplyOneTableToBioSource 
2528 (TableToBioSourcePtr t,
2529  Boolean             replace_with_blank,
2530  ExistingTextPtr     etp,
2531  TaxnameOptionsPtr   taxname_options)
2532 {
2533   ValNodePtr vnp_col, vnp_biop;
2534   BioSourcePtr biop;
2535   ApplyColumnPtr a;
2536 
2537   if (t == NULL || t->columns_to_apply == NULL || t->biop_list == NULL) return;
2538 
2539   for (vnp_biop = t->biop_list; vnp_biop != NULL; vnp_biop = vnp_biop->next) 
2540   {
2541     biop = (BioSourcePtr) vnp_biop->data.ptrvalue;
2542     if (biop == NULL) continue;
2543     for (vnp_col = t->columns_to_apply; vnp_col != NULL; vnp_col = vnp_col->next)
2544     {
2545       a = (ApplyColumnPtr) vnp_col->data.ptrvalue;
2546       if (a == NULL 
2547           || a->apply_choice == NULL
2548           || (!replace_with_blank && StringHasNoText (a->apply_value))) continue;
2549 
2550       if (a->apply_choice->choice == 0 && a->apply_choice->data.ptrvalue != NULL)
2551       {
2552         AddOneQualToOrg (biop, a->apply_value, a->apply_choice->data.ptrvalue,
2553                           etp);
2554       }
2555       else if (a->apply_choice->choice > 0 
2556                 && (StringICmp (a->apply_choice->data.ptrvalue, "Tax Name") == 0
2557                     || StringICmp (a->apply_choice->data.ptrvalue, "Organism") == 0))
2558       {  
2559         ApplyTaxNameToOrg (biop, a->apply_value, etp);
2560         ApplyTaxnameOptionsToBioSource (biop, taxname_options);
2561       }
2562       else if (a->apply_choice->choice > 0 && StringICmp (a->apply_choice->data.ptrvalue, "Location") == 0)
2563       {
2564         ApplyLocationToOrg (biop, a->apply_value);
2565       }
2566     }
2567   }
2568 }
2569 
2570 
2571 static void 
2572 ApplyTableToBioSourceList 
2573 (ValNodePtr        apply_list,
2574  Boolean           replace_with_blank,
2575  ExistingTextPtr   etp,
2576  TaxnameOptionsPtr taxname_options)
2577 {
2578   ValNodePtr vnp;
2579 
2580   for (vnp = apply_list; vnp != NULL; vnp = vnp->next)
2581   {
2582     ApplyOneTableToBioSource (vnp->data.ptrvalue, replace_with_blank, etp, taxname_options);
2583   }
2584 }
2585 
2586 
2587 static void DoAcceptFormMods (ButtoN b)
2588 {
2589   OrgModLoadFormPtr form_data;
2590   SeqEntryPtr   sep;
2591   GetSamplePtr gsp;
2592   ValNodePtr apply_list;
2593   Boolean    replace_with_blank;
2594   ExistingTextPtr etp;
2595   TaxnameOptionsPtr taxname_options;
2596 
2597   form_data = GetObjectExtra (b);
2598   if (form_data == NULL) return;
2599 
2600   sep = GetTopSeqEntryForEntityID (form_data->entityID);
2601   if (sep == NULL) return;
2602   
2603   replace_with_blank = GetStatus (form_data->replace_with_blank_btn);
2604   apply_list = OrgModLoadFormToApplyList (form_data);
2605   FindOrganismsForTableToBioSourceList (apply_list, sep);
2606   if (ListOrganismsWithMultipleRows (apply_list)) 
2607   {
2608     Message (MSG_ERROR, "Multiple rows in the table apply to the same organism!  Table cannot be imported.");
2609     apply_list = TableToBioSourceListFree (apply_list);
2610     return;
2611   }
2612   ListRowsWithoutOrganisms (apply_list);
2613   if (ListRowsWithMultipleOrganisms (apply_list)) {
2614     if (ANS_CANCEL == Message (MSG_OKC, "Some rows in the table apply to more than one organism - continue?"))
2615     {
2616       apply_list = TableToBioSourceListFree (apply_list);
2617       return;
2618     }
2619   }
2620   gsp = DetectExistingModifiersForTableToBioSourceList (apply_list, replace_with_blank);
2621   etp = GetExistingTextHandlerInfo (gsp == NULL ? 0 : gsp->num_found, FALSE);
2622   gsp = GetSampleFree (gsp);
2623   if (etp != NULL && etp->existing_text_choice == eExistingTextChoiceCancel)
2624   {
2625     etp = MemFree (etp);
2626     apply_list = TableToBioSourceListFree (apply_list);
2627     return;
2628   }
2629   taxname_options = DialogToPointer (form_data->taxname_options);
2630   ApplyTableToBioSourceList (apply_list, replace_with_blank, etp, taxname_options);
2631   taxname_options = MemFree (taxname_options);
2632   etp = MemFree (etp);
2633   apply_list = TableToBioSourceListFree (apply_list);
2634 
2635   Update ();
2636   ObjMgrSetDirtyFlag (form_data->entityID, TRUE);
2637   ObjMgrSendMsg (OM_MSG_UPDATE, form_data->entityID, 0, 0);
2638   if (!GetStatus (form_data->leave_dlg_up_btn))
2639   {
2640     Remove (form_data->form);
2641   }
2642 }
2643 
2644 
2645 static ValNodePtr ReadTableData (void)
2646 {
2647   Char          path [PATH_MAX];
2648   Int4          max_columns;
2649   ValNodePtr    header_line;
2650   ValNodePtr    line_list;
2651   TableLinePtr  tlp;
2652   ValNodePtr    vnp;
2653   ReadBufferData rbd;
2654   CharPtr        line;
2655   ValNodePtr     special_list = NULL;
2656 
2657   path [0] = '\0';
2658   if (! GetInputFileName (path, sizeof (path), NULL, "TEXT")) return NULL;
2659   
2660   rbd.fp = FileOpen (path, "r");
2661   if (rbd.fp == NULL) return NULL;
2662   rbd.current_data = NULL;
2663 
2664   line_list = NULL;
2665   max_columns = 0;
2666   header_line = NULL;
2667   line = AbstractReadFunction (&rbd);
2668   while (line != NULL) 
2669   {
2670     tlp = MakeTableData (line, &special_list);
2671     if (tlp != NULL)
2672     {
2673       vnp = ValNodeNew (line_list);
2674       if (vnp == NULL) return NULL;
2675       if (line_list == NULL) line_list = vnp;
2676       vnp->data.ptrvalue = tlp;
2677       if (tlp->num_parts > max_columns)
2678       {
2679         max_columns = tlp->num_parts;
2680         header_line = vnp;
2681       }
2682     }
2683     line = MemFree (line);
2684     line = AbstractReadFunction (&rbd);
2685   }
2686   FileClose (rbd.fp);
2687   if (special_list != NULL && !FixSpecialCharactersForStringsInList (special_list, "The table contains special characters\nand cannot be used until they are replaced.", FALSE))
2688   {
2689     line_list = ValNodeFreeData (line_list);
2690     header_line = NULL;
2691   }
2692   /* throw out all lines before header line */
2693   else if (header_line != line_list)
2694   {
2695     vnp = line_list;
2696     while (vnp != NULL && vnp->next != header_line)
2697     {
2698       vnp = vnp->next;
2699     }
2700     vnp->next = NULL;
2701     ValNodeFreeData (line_list);
2702     line_list = NULL;
2703   }
2704   special_list = FreeContextList (special_list);
2705   return header_line;
2706 }
2707 
2708 
2709 static Int4Ptr GetColumnBlankCounts (ValNodePtr header_line, Int4 num_columns)
2710 {
2711   ValNodePtr   line_vnp, part_vnp;
2712   TableLinePtr tlp;
2713   Int4         i;
2714   Int4Ptr      blank_list;
2715   
2716   if (header_line == NULL || num_columns < 1) return NULL;
2717 
2718   blank_list = (Int4Ptr) MemNew (sizeof (Int4) * num_columns);
2719 
2720   for (line_vnp = header_line; line_vnp != NULL; line_vnp = line_vnp->next)
2721   {
2722     if (line_vnp->data.ptrvalue == NULL) continue;
2723     tlp = (TableLinePtr) line_vnp->data.ptrvalue;
2724     part_vnp = tlp->parts;
2725     for (i = 0; i < num_columns; i++) 
2726     {
2727       if (part_vnp == NULL || StringHasNoText (part_vnp->data.ptrvalue)) 
2728       {
2729         blank_list[i]++;
2730       }
2731       if (part_vnp != NULL) 
2732       {
2733         part_vnp = part_vnp->next;
2734       }
2735     }
2736   }
2737   return blank_list;
2738 }
2739 
2740 
2741 static void LoadOrganismModifierTableEx (IteM i, Boolean IsTaxConsult)
2742 {
2743   BaseFormPtr   bfp;
2744   ValNodePtr    header_line;
2745   ValNodePtr    vnp;
2746   TableLinePtr  tlp;
2747   WindoW        w;
2748   GrouP         h, g, k, c;
2749   OrgModLoadFormPtr form_data;
2750   Int4          index;
2751   Int4          max_columns;
2752   Int4Ptr       blank_list = NULL;
2753   OrgModTableColumnData o;
2754 
2755 #ifdef WIN_MAC
2756   bfp = currentFormDataPtr;
2757 #else
2758   bfp = GetObjectExtra (i);
2759 #endif
2760   if (bfp == NULL) return;
2761 
2762   header_line = ReadTableData ();
2763   if (header_line == NULL || header_line->data.ptrvalue == NULL) return;
2764   tlp = header_line->data.ptrvalue;
2765   max_columns = 0;
2766   for (vnp = tlp->parts; vnp != NULL; vnp = vnp->next)
2767   {
2768     max_columns ++;
2769   }
2770   
2771   form_data = MemNew (sizeof (OrgModLoadFormData));
2772   if (form_data == NULL) return;
2773   form_data->entityID = bfp->input_entityID;
2774   form_data->line_list = header_line;
2775 
2776   form_data->num_columns = max_columns;
2777   form_data->columns = (DialoG PNTR) MemNew (max_columns * sizeof (DialoG));
2778 
2779   /* now create a dialog to display values */
2780   w = FixedWindow (-50, -33, -10, -10, "Table Conversion", StdCloseWindowProc);
2781   SetObjectExtra (w, form_data, CleanupOrgModLoadForm);
2782   form_data->form = (ForM) w;
2783 
2784   h = HiddenGroup (w, -1, 0, NULL);
2785   SetGroupSpacing (h, 10, 10);
2786   g = HiddenGroup (h, 3, 0, NULL);
2787 
2788   /* pre-analyze table for blanks, so we can display the information in the column dialogs */
2789   blank_list = GetColumnBlankCounts (header_line, form_data->num_columns);
2790 
2791   tlp = header_line->data.ptrvalue;
2792   for (index = 0, vnp = tlp->parts; index < max_columns; index++)
2793   {
2794     form_data->columns[index] = OrgModTableColumnDialog (g, vnp == NULL ? NULL : vnp->data.ptrvalue,
2795                                                          blank_list == NULL ? 0 : blank_list[index],
2796                                                          SetFormModsEnable, form_data);
2797     if (vnp != NULL) vnp = vnp->next;
2798   }
2799   blank_list = MemFree (blank_list);
2800   if (max_columns > 1 && IsTaxConsult)
2801   {
2802     o.match_choice = eMatchAccession;
2803     o.apply_choice = NULL;
2804     PointerToDialog (form_data->columns[0], &o);
2805     o.match_choice = 0;
2806     ValNodeAddPointer (&o.apply_choice, 1, "Tax Name");
2807     PointerToDialog (form_data->columns[1], &o);
2808     o.apply_choice = ValNodeFree (o.apply_choice);
2809   }
2810 
2811   k = HiddenGroup (h, 1, 0, NULL);
2812   form_data->replace_with_blank_btn = CheckBox (k, "Erase current value when blank found in table", NULL);
2813 
2814   form_data->taxname_options = TaxnameOptionsDialog (h, NULL, NULL);
2815   Disable (form_data->taxname_options);
2816 
2817   c = HiddenGroup (h, 4, 0, NULL);
2818   form_data->accept_button = DefaultButton (c, "Accept", DoAcceptFormMods);
2819   SetObjectExtra (form_data->accept_button, form_data, NULL);
2820   PushButton (c, "Cancel", StdCancelButtonProc);
2821   form_data->leave_dlg_up_btn = CheckBox (c, "Leave Dialog Up", NULL);
2822 
2823   SetFormModsEnable(form_data);
2824 
2825   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) k, (HANDLE) form_data->taxname_options, (HANDLE) c, NULL);
2826 
2827   RealizeWindow (w);
2828   Show (w);
2829   Update ();
2830 }
2831 
2832 extern void LoadOrganismModifierTable (IteM i)
2833 {
2834   LoadOrganismModifierTableEx (i, FALSE);
2835 }
2836 
2837 extern void LoadTaxConsult (IteM i)
2838 {
2839   LoadOrganismModifierTableEx (i, TRUE);
2840 }
2841 
2842 
2843 extern Boolean ReplaceImportModifierName (CharPtr PNTR orig_name, Int4 col_num)
2844 {
2845   ModalAcceptCancelData acd;
2846   WindoW                w;
2847   Char                  title[128];
2848   GrouP                 g, k, c;
2849   ButtoN                b;
2850   DialoG                modifier_name_choice;
2851   ValNodePtr            mod_name_choice_list = NULL, default_vnp, choice_vnp;
2852   
2853   if (orig_name == NULL)
2854   {
2855     return FALSE;
2856   }
2857   acd.accepted = FALSE;
2858   acd.cancelled = FALSE;
2859   
2860   sprintf (title, "Choose import modifier for column %d", col_num);
2861   w = MovableModalWindow(-20, -13, -10, -10, title, NULL);
2862   g = HiddenGroup (w, -1, 0, NULL);
2863   
2864   k = NULL;
2865   if (!StringHasNoText (*orig_name))
2866   {
2867     k = HiddenGroup (g, 2, 0, NULL);
2868     StaticPrompt (k, "Unrecognized column name:", 0, popupMenuHeight, programFont, 'r');
2869     StaticPrompt (k, *orig_name, 0, popupMenuHeight, programFont, 'l');
2870   }
2871   
2872   ValNodeAddPointer (&mod_name_choice_list, 1, StringSave ("Ignore Column"));
2873   mod_name_choice_list->next = GetSourceQualDescList (TRUE, TRUE, FALSE, FALSE);
2874   ValNodeAddPointer (&mod_name_choice_list, 2, StringSave ("Organism"));
2875   ValNodeAddPointer (&mod_name_choice_list, 3, StringSave ("Location"));
2876   
2877   modifier_name_choice = ValNodeSelectionDialog (g, mod_name_choice_list, 6, SourceQualValNodeName,
2878                                 ValNodeSimpleDataFree, SourceQualValNodeDataCopy,
2879                                 SourceQualValNodeMatch, "feature list", 
2880                                 NULL, NULL, FALSE);
2881   default_vnp = ValNodeNew (NULL);
2882   default_vnp->choice = 1;
2883   default_vnp->data.ptrvalue = StringSave ("Ignore Column");
2884   default_vnp->next = NULL;
2885   PointerToDialog (modifier_name_choice, default_vnp);
2886   default_vnp = ValNodeFreeData (default_vnp);
2887 
2888   c = HiddenGroup (g, 2, 0, NULL);
2889   b = PushButton (c, "Accept", ModalAcceptButton);
2890   SetObjectExtra (b, &acd, NULL);
2891   b = PushButton (c, "Cancel", ModalCancelButton);
2892   SetObjectExtra (b, &acd, NULL);
2893   if (k == NULL)
2894   {
2895     AlignObjects (ALIGN_CENTER, (HANDLE) modifier_name_choice, (HANDLE) c, NULL);
2896   }
2897   else
2898   {
2899     AlignObjects (ALIGN_CENTER, (HANDLE) k, (HANDLE) modifier_name_choice, (HANDLE) c, NULL);
2900   }
2901   Show (w);
2902   Select (w);
2903   acd.accepted = FALSE;
2904   acd.cancelled = FALSE;
2905   while (!acd.accepted && ! acd.cancelled)
2906   {
2907     ProcessExternalEvent ();
2908     Update ();
2909   }
2910   ProcessAnEvent ();
2911   choice_vnp = (ValNodePtr) DialogToPointer (modifier_name_choice);
2912   
2913   Remove (w);
2914   if (acd.cancelled)
2915   {
2916     return FALSE;
2917   }
2918   else
2919   {
2920     *orig_name = MemFree (*orig_name);
2921     if (choice_vnp != NULL && choice_vnp->choice != 1)
2922     {
2923       *orig_name = SourceQualValNodeName (choice_vnp);
2924     }
2925     return TRUE;
2926   }
2927 }
2928 
2929 
2930 static ValNodePtr FreeTableData (ValNodePtr lines)
2931 {
2932   TableLinePtr tlp;
2933   
2934   if (lines == NULL)
2935   {
2936     return NULL;
2937   }
2938   lines->next = FreeTableData (lines->next);
2939   tlp = (lines->data.ptrvalue);
2940   if (tlp != NULL)
2941   {
2942     tlp->parts = ValNodeFreeData (tlp->parts);
2943     tlp = MemFree (tlp);
2944     lines->data.ptrvalue = NULL;
2945   }
2946   return ValNodeFree (lines);
2947 }
2948 
2949 
2950 typedef struct exportorgtable
2951 {
2952   ModifierItemLocalPtr modList;
2953   BioseqPtr            bsp;
2954   Boolean              list_tax_name;
2955   Boolean              list_accession;
2956   Boolean              list_local;
2957   Boolean              list_general;
2958 
2959   ValNodePtr           organism_id_profile;
2960   FILE *fp;  
2961 } ExportOrgTableData, PNTR ExportOrgTablePtr;
2962 
2963 #define ORGANISM_ID_PROFILE_HAS_ACCESSION 1
2964 #define ORGANISM_ID_PROFILE_HAS_LOCAL     2
2965 #define ORGANISM_ID_PROFILE_HAS_GENERAL   4
2966 #define ORGANISM_ID_PROFILE_HAS_TAX_NAME  8
2967 
2968 static void ExportOneOrganism (BioSourcePtr biop, Pointer userdata)
2969 {
2970   ExportOrgTablePtr eotp;
2971   Char              acc_str [256];
2972   SeqIdPtr          sip;
2973   SeqIdPtr          acc_sip = NULL, local_sip = NULL, gen_sip = NULL;
2974   Int4              i;
2975   OrgModPtr         mod;
2976   SubSourcePtr      ssp;
2977   Boolean           need_tab = FALSE;
2978   
2979   if (biop == NULL || userdata == NULL) return;
2980   eotp = (ExportOrgTablePtr) userdata;
2981   
2982   if (eotp->bsp == NULL || eotp->modList == NULL || eotp->fp == NULL) return;
2983   
2984   for (sip = eotp->bsp->id;
2985        sip != NULL && (acc_sip == NULL || local_sip == NULL);
2986        sip = sip->next)
2987   {
2988     if (acc_sip == NULL && sip->choice == SEQID_GENBANK)
2989     {
2990       acc_sip = sip;
2991     }
2992     else if (local_sip == NULL && sip->choice == SEQID_LOCAL)
2993     {
2994       local_sip = sip;
2995     }
2996     else if (gen_sip == NULL && sip->choice == SEQID_GENERAL)
2997     {
2998       gen_sip = sip;
2999     }
3000   }
3001 
3002   if (eotp->list_accession)
3003   {
3004     /* get accession number and print to column */
3005     if (acc_sip == NULL)
3006     {
3007       fprintf (eotp->fp, " ");
3008     }
3009     else
3010     {
3011       sip = acc_sip->next;
3012       acc_sip->next = NULL;
3013       SeqIdWrite (acc_sip, acc_str, PRINTID_TEXTID_ACC_VER, sizeof (acc_str));
3014       acc_sip->next = sip;
3015       fprintf (eotp->fp, "%s", acc_str);
3016     }
3017     need_tab = TRUE;
3018   }
3019   
3020   if (eotp->list_local)
3021   {
3022     if (need_tab) {
3023       fprintf (eotp->fp, "\t");
3024     }
3025     /* get local ID and print to column */
3026     if (local_sip == NULL)
3027     {
3028       fprintf (eotp->fp, " ");
3029     }
3030     else
3031     {
3032       sip = local_sip->next;
3033       local_sip->next = NULL;
3034       SeqIdWrite (local_sip, acc_str, PRINTID_TEXTID_ACCESSION, sizeof (acc_str));
3035       local_sip->next = sip;
3036       fprintf (eotp->fp, "%s", acc_str);
3037     }
3038     need_tab = TRUE;
3039   }
3040   
3041   if (eotp->list_general)
3042   {
3043     if (need_tab) {
3044       fprintf (eotp->fp, "\t");
3045     }
3046     /* get general ID and print to column */
3047     if (gen_sip == NULL)
3048     {
3049       fprintf (eotp->fp, " ");
3050     }
3051     else
3052     {
3053       sip = gen_sip->next;
3054       gen_sip->next = NULL;
3055       SeqIdWrite (gen_sip, acc_str, PRINTID_FASTA_GENERAL, sizeof (acc_str));
3056       gen_sip->next = sip;
3057       fprintf (eotp->fp, "%s", acc_str);
3058     }
3059     need_tab = TRUE;
3060   }
3061   
3062   if (eotp->list_tax_name)
3063   {
3064     if (need_tab) {
3065       fprintf (eotp->fp, "\t");
3066     }
3067     /* get tax name and print to column */
3068     if (biop->org != NULL && ! StringHasNoText (biop->org->taxname))
3069     {
3070       fprintf (eotp->fp, "%s", biop->org->taxname);
3071     }
3072     else
3073     {
3074       fprintf (eotp->fp, " ");
3075     }
3076     need_tab = TRUE;
3077   }
3078   
3079   /* print modifiers for each available column */
3080   for (i= 0; i < NumDefLineModifiers (); i++)
3081   {
3082     if (eotp->modList[i].any_present)
3083     {
3084       mod = NULL;
3085       ssp = NULL;
3086       if (DefLineModifiers[i].isOrgMod)
3087       {
3088         if ( biop->org != NULL && biop->org->orgname != NULL) 
3089         {
3090           mod = biop->org->orgname->mod;
3091           while (mod != NULL
3092                  && mod->subtype != DefLineModifiers[i].subtype)
3093           {
3094             mod = mod->next;
3095           }
3096         }
3097       }
3098       else
3099       {
3100         ssp = biop->subtype;
3101         while (ssp != NULL && ssp->subtype != DefLineModifiers[i].subtype)
3102         {
3103           ssp = ssp->next;
3104         }
3105       }
3106       if (need_tab) {
3107         fprintf (eotp->fp, "\t");
3108       }
3109           if (IsNonTextModifier (DefLineModifiers[i].name))
3110           {
3111             if (mod == NULL && ssp == NULL)
3112             {
3113               fprintf (eotp->fp, "FALSE");
3114                 }
3115                 else
3116                 {
3117                   fprintf (eotp->fp, "TRUE");
3118                 }
3119           }
3120       else if (mod != NULL && !StringHasNoText (mod->subname))
3121       {
3122         fprintf (eotp->fp, "%s", mod->subname);
3123       }
3124       else if (ssp != NULL && !StringHasNoText (ssp->name))
3125       {
3126         fprintf (eotp->fp, "%s", ssp->name);
3127       }
3128       else
3129       {
3130         fprintf (eotp->fp, " ");
3131       }
3132       need_tab = TRUE;
3133     }
3134   }
3135   fprintf (eotp->fp, "\n");
3136 }
3137 
3138 static void ExportOrganisms (SeqEntryPtr sep, ExportOrgTablePtr eotp)
3139 {
3140   BioseqSetPtr bssp;
3141   SeqEntryPtr  nsep;
3142   BioseqPtr    bsp;
3143   
3144   if (sep == NULL || eotp == NULL || sep->data.ptrvalue == NULL) return;
3145   
3146   if (IS_Bioseq (sep))
3147   {
3148     bsp = (BioseqPtr) sep->data.ptrvalue;
3149     if (bsp != NULL && !ISA_aa (bsp->mol)) {
3150       eotp->bsp = bsp;
3151       VisitBioSourcesOnBsp (eotp->bsp, eotp, ExportOneOrganism);
3152     }
3153   }
3154   else if (IS_Bioseq_set (sep))
3155   {
3156     bssp = (BioseqSetPtr) sep->data.ptrvalue;
3157     if (bssp->_class == BioseqseqSet_class_nuc_prot)
3158     {
3159       nsep = FindNucSeqEntry (sep);
3160       if (nsep != NULL)
3161       {
3162         eotp->bsp = (BioseqPtr) nsep->data.ptrvalue;
3163         VisitBioSourcesOnSep (sep, eotp, ExportOneOrganism);
3164       }
3165     }
3166     else
3167     {
3168       for (sep = bssp->seq_set; sep != NULL; sep = sep->next)
3169       {
3170         ExportOrganisms (sep, eotp);
3171       }
3172     }
3173   }
3174 }
3175 
3176 static void GetOneOrganismIdProfile (BioSourcePtr biop, Pointer userdata)
3177 {
3178   ExportOrgTablePtr eotp;
3179   SeqIdPtr          sip;
3180   Int4              profile_value = 0;
3181 
3182   if (biop == NULL || userdata == NULL) return;
3183   eotp = (ExportOrgTablePtr) userdata;
3184   
3185   if (eotp->bsp == NULL) return;
3186 
3187   for (sip = eotp->bsp->id;
3188        sip != NULL;
3189        sip = sip->next)
3190   {
3191     if (sip->choice == SEQID_GENBANK)
3192     {
3193           profile_value |= ORGANISM_ID_PROFILE_HAS_ACCESSION;
3194     }
3195     else if (sip->choice == SEQID_LOCAL)
3196     {
3197       profile_value |= ORGANISM_ID_PROFILE_HAS_LOCAL;
3198     }
3199     else if (sip->choice == SEQID_GENERAL)
3200     {
3201       profile_value |= ORGANISM_ID_PROFILE_HAS_GENERAL;
3202     }
3203   }
3204   
3205   if (biop->org != NULL && ! StringHasNoText (biop->org->taxname))
3206   {
3207     profile_value |= ORGANISM_ID_PROFILE_HAS_TAX_NAME;
3208   }
3209 
3210   ValNodeAddInt (&(eotp->organism_id_profile), 0, profile_value);
3211 }
3212 
3213 static void GetOrganismIDProfile (SeqEntryPtr sep, ExportOrgTablePtr eotp)
3214 {
3215   BioseqSetPtr bssp;
3216   SeqEntryPtr  nsep;
3217   
3218   if (sep == NULL || eotp == NULL || sep->data.ptrvalue == NULL) return;
3219   
3220   if (IS_Bioseq (sep))
3221   {
3222     eotp->bsp = (BioseqPtr) sep->data.ptrvalue;
3223     VisitBioSourcesOnBsp (eotp->bsp, eotp, GetOneOrganismIdProfile);  
3224   }
3225   else if (IS_Bioseq_set (sep))
3226   {
3227     bssp = (BioseqSetPtr) sep->data.ptrvalue;
3228     if (bssp->_class == BioseqseqSet_class_nuc_prot)
3229     {
3230       nsep = FindNucSeqEntry (sep);
3231       if (nsep != NULL)
3232       {
3233         eotp->bsp = (BioseqPtr) nsep->data.ptrvalue;
3234         VisitBioSourcesOnSep (sep, eotp, GetOneOrganismIdProfile);
3235       }
3236     }
3237     else
3238     {
3239       for (sep = bssp->seq_set; sep != NULL; sep = sep->next)
3240       {
3241         GetOrganismIDProfile (sep, eotp);
3242       }
3243     }
3244   }
3245 }
3246 
3247 static void GetOrganismIDProfileSummary (ValNodePtr organism_id_profile, Int4Ptr available, Int4Ptr recommended)
3248 {
3249   ValNodePtr vnp;
3250   Int4       has_vals = 0, recommended_vals = 0, missing_vals = 0;
3251 
3252   if (available != NULL)
3253   {
3254     *available = 0;
3255   }
3256   if (recommended != NULL)
3257   {
3258     *recommended = 0;
3259   }
3260 
3261   for (vnp = organism_id_profile;
3262            vnp != NULL;
3263            vnp = vnp->next)
3264   {
3265     has_vals |= vnp->data.intvalue;
3266         missing_vals |= !(vnp->data.intvalue);
3267         if (vnp->data.intvalue & ORGANISM_ID_PROFILE_HAS_ACCESSION)
3268         {
3269           recommended_vals |= ORGANISM_ID_PROFILE_HAS_ACCESSION;
3270         }
3271     else if (vnp->data.intvalue & ORGANISM_ID_PROFILE_HAS_LOCAL)
3272         {
3273           recommended_vals |= ORGANISM_ID_PROFILE_HAS_LOCAL;
3274         }
3275         else if (vnp->data.intvalue & ORGANISM_ID_PROFILE_HAS_GENERAL)
3276         {
3277           recommended_vals |= ORGANISM_ID_PROFILE_HAS_GENERAL;
3278         }
3279         else if (vnp->data.intvalue & ORGANISM_ID_PROFILE_HAS_TAX_NAME)
3280         {
3281           recommended_vals |= ORGANISM_ID_PROFILE_HAS_TAX_NAME;
3282         }
3283   }
3284 
3285   if (recommended_vals & ORGANISM_ID_PROFILE_HAS_TAX_NAME)
3286   {
3287     if (!(missing_vals & ORGANISM_ID_PROFILE_HAS_TAX_NAME))
3288         {
3289           recommended_vals = ORGANISM_ID_PROFILE_HAS_TAX_NAME;
3290         }
3291   }
3292   else if (recommended_vals & ORGANISM_ID_PROFILE_HAS_GENERAL)
3293   {
3294     if (!(missing_vals & ORGANISM_ID_PROFILE_HAS_GENERAL))
3295         {
3296           recommended_vals = ORGANISM_ID_PROFILE_HAS_GENERAL;
3297         }
3298   }
3299   else if (recommended_vals & ORGANISM_ID_PROFILE_HAS_LOCAL)
3300   {
3301     if (!(missing_vals & ORGANISM_ID_PROFILE_HAS_LOCAL))
3302         {
3303           recommended_vals = ORGANISM_ID_PROFILE_HAS_LOCAL;
3304         }
3305   }
3306   
3307   if (available != NULL)
3308   {
3309     *available = has_vals;
3310   }
3311 
3312   if (recommended != NULL)
3313   {
3314     *recommended = recommended_vals;
3315   }
3316 }
3317 
3318 typedef struct exportmodform
3319 {
3320   FEATURE_FORM_BLOCK
3321 
3322   DialoG selected_mods;
3323   ButtoN list_tax_name;
3324   ButtoN list_accession;
3325   ButtoN list_local;
3326   ButtoN list_general;
3327   ButtoN list_additional_mods;
3328   ButtoN accept_btn;
3329 } ExportModFormData, PNTR ExportModFormPtr;
3330 
3331 static void SetExportFormModsAccept (Pointer userdata)
3332 {
3333   ExportModFormPtr form_data;
3334   ValNodePtr       selected_mods;
3335 
3336   form_data = (ExportModFormPtr) userdata;
3337   if (form_data == NULL) return;
3338   
3339   if (GetStatus (form_data->list_additional_mods))
3340   {
3341     Enable (form_data->selected_mods); 
3342     selected_mods = (ValNodePtr) DialogToPointer (form_data->selected_mods);
3343     if (selected_mods == NULL)
3344     {
3345       Disable (form_data->accept_btn);
3346       return;
3347     }
3348     else
3349     {
3350             selected_mods = ValNodeFreeData (selected_mods);
3351     }
3352   }
3353   else
3354   {
3355     Disable (form_data->selected_mods);
3356   }
3357 
3358         if (!GetStatus (form_data->list_tax_name) && ! GetStatus (form_data->list_accession)
3359                 && !GetStatus (form_data->list_local) && ! GetStatus (form_data->list_general))
3360         {
3361     Disable (form_data->accept_btn);
3362         }
3363         else
3364         {
3365           Enable (form_data->accept_btn);
3366         }
3367 }
3368 
3369 static void SetExportFormModsAcceptBtn (ButtoN b)
3370 {
3371   SetExportFormModsAccept (GetObjectExtra (b));
3372 }
3373 
3374 static Boolean SelectModifiersForExport (ExportOrgTablePtr eotp)
3375 {
3376   Int4                  idx;
3377   ValNodePtr            available_mods_list = NULL, vnp;
3378   ModalAcceptCancelData acd;
3379   ExportModFormPtr      form_data;
3380   WindoW                w;
3381   GrouP                 h, g, c;
3382   ButtoN                b;
3383   ValNodePtr            selected_mods = NULL;
3384   Boolean               found_mod;
3385   Int4                  has_vals = 0, recommended_vals = 0;
3386 
3387   if (eotp == NULL)
3388   {
3389     return FALSE;
3390   }
3391 
3392   for (idx = 0; idx < NumDefLineModifiers (); idx++)
3393   {
3394     if (eotp->modList[idx].any_present)
3395     {
3396       ValNodeAddPointer (&available_mods_list, idx, StringSave (DefLineModifiers [idx].name));
3397     }
3398   }
3399 
3400   GetOrganismIDProfileSummary (eotp->organism_id_profile, &has_vals, &recommended_vals);
3401 
3402   form_data = (ExportModFormPtr) MemNew (sizeof (ExportModFormData));
3403 
3404   w = FixedWindow (-50, -33, -10, -10, "Choose Modifiers for Export", StdCloseWindowProc);
3405   SetObjectExtra (w, form_data, StdCleanupFormProc);
3406   form_data->form = (ForM) w;
3407 
3408   h = HiddenGroup (w, -1, 0, NULL);
3409   SetGroupSpacing (h, 10, 10);
3410 
3411   g = HiddenGroup (h, 0, 5, NULL);
3412   form_data->list_tax_name = CheckBox (g, "Tax Name", SetExportFormModsAcceptBtn);
3413   SetObjectExtra (form_data->list_tax_name, form_data, NULL);
3414   if (!(has_vals & ORGANISM_ID_PROFILE_HAS_TAX_NAME))
3415   {
3416     Disable (form_data->list_tax_name);
3417   }
3418   else if (recommended_vals & ORGANISM_ID_PROFILE_HAS_TAX_NAME)
3419   {
3420     SetStatus (form_data->list_tax_name, TRUE);
3421   }
3422   form_data->list_accession = CheckBox (g, "Accession", SetExportFormModsAcceptBtn);
3423   SetObjectExtra (form_data->list_accession, form_data, NULL);
3424   if (!(has_vals & ORGANISM_ID_PROFILE_HAS_ACCESSION))
3425   {
3426     Disable (form_data->list_accession);
3427   }
3428   else if (recommended_vals & ORGANISM_ID_PROFILE_HAS_ACCESSION)
3429   {
3430     SetStatus (form_data->list_accession, TRUE);
3431   }
3432   form_data->list_local = CheckBox (g, "Local ID", SetExportFormModsAcceptBtn);
3433   SetObjectExtra (form_data->list_local, form_data, NULL);
3434   if (!(has_vals & ORGANISM_ID_PROFILE_HAS_LOCAL))
3435   {
3436     Disable (form_data->list_local);
3437   }
3438   else if (recommended_vals & ORGANISM_ID_PROFILE_HAS_LOCAL)
3439   {
3440     SetStatus (form_data->list_local, TRUE);
3441   }
3442   form_data->list_general = CheckBox (g, "General ID", SetExportFormModsAcceptBtn);
3443   SetObjectExtra (form_data->list_general, form_data, NULL);
3444   if (!(has_vals & ORGANISM_ID_PROFILE_HAS_GENERAL))
3445   {
3446     Disable (form_data->list_general);
3447   }
3448   else if (recommended_vals & ORGANISM_ID_PROFILE_HAS_GENERAL)
3449   {
3450     SetStatus (form_data->list_general, TRUE);
3451   }
3452   
3453   form_data->list_additional_mods = CheckBox (g, "Additional Modifiers", SetExportFormModsAcceptBtn);
3454   SetObjectExtra (form_data->list_additional_mods, form_data, NULL);
3455   SetStatus (form_data->list_additional_mods, TRUE);
3456 
3457   form_data->selected_mods = ValNodeSelectionDialog (h, available_mods_list, TALL_SELECTION_LIST,
3458                                 ValNodeStringName,
3459                                 ValNodeSimpleDataFree, 
3460                                 ValNodeStringCopy,
3461                                 ValNodeStringMatch,
3462                                 "qualifiers", 
3463                                 SetExportFormModsAccept, form_data,
3464                                 TRUE);
3465 
3466   /* initialize dialog to "All" */
3467   SendMessageToDialog (form_data->selected_mods, NUM_VIB_MSG + 1);
3468 
3469   c = HiddenGroup (h, 2, 0, NULL);
3470   form_data->accept_btn = PushButton (c, "Accept", ModalAcceptButton);
3471   SetObjectExtra (form_data->accept_btn, &acd, NULL);
3472   b = PushButton (c, "Cancel", ModalCancelButton);
3473   SetObjectExtra (b, &acd, NULL);
3474   AlignObjects (ALIGN_CENTER, (HANDLE) form_data->selected_mods, (HANDLE) g, (HANDLE) c, NULL);
3475 
3476   SetExportFormModsAccept (form_data);
3477 
3478   Show (w);
3479   Select (w);
3480   acd.accepted = FALSE;
3481   acd.cancelled = FALSE;
3482   while (!acd.accepted && ! acd.cancelled)
3483   {
3484     ProcessExternalEvent ();
3485     Update ();
3486   }
3487   ProcessAnEvent ();
3488   
3489   Remove (w);
3490   if (acd.cancelled)
3491   {
3492     return FALSE;
3493   }
3494   else
3495   {
3496     if (GetStatus (form_data->list_additional_mods))
3497     {
3498       selected_mods = (ValNodePtr) DialogToPointer (form_data->selected_mods);
3499     }
3500     else
3501     {
3502       selected_mods = NULL;
3503     }
3504 
3505     for (idx = 0; idx < NumDefLineModifiers (); idx++)
3506     {
3507       if (eotp->modList[idx].any_present)
3508       {
3509         found_mod = FALSE;
3510             for (vnp = selected_mods; vnp != NULL && ! found_mod; vnp = vnp->next)
3511         {
3512           if (StringCmp (vnp->data.ptrvalue, DefLineModifiers [idx].name) == 0)
3513           {
3514             found_mod = TRUE;
3515           }
3516         }
3517         if (!found_mod)
3518         {
3519           eotp->modList[idx].any_present = FALSE;
3520         }
3521       }
3522     }
3523     selected_mods = ValNodeFreeData (selected_mods);
3524 
3525     eotp->list_tax_name = GetStatus (form_data->list_tax_name);
3526     eotp->list_accession = GetStatus (form_data->list_accession);
3527     eotp->list_local = GetStatus (form_data->list_local);
3528     eotp->list_general = GetStatus (form_data->list_general);
3529 
3530     return TRUE;
3531   }  
3532 }
3533 
3534 extern void ExportOrganismTable (IteM i)
3535 {
3536   BaseFormPtr        bfp;
3537   SeqEntryPtr        sep;
3538   ExportOrgTableData eotd;
3539   Char               path [PATH_MAX];
3540   Int4               idx;
3541   Char               lead_str[2];
3542 
3543 #ifdef WIN_MAC
3544   bfp = currentFormDataPtr;
3545 #else
3546   bfp = GetObjectExtra (i);
3547 #endif
3548   if (bfp == NULL) return;
3549 
3550   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3551   if (sep == NULL) return;
3552 
3553   eotd.modList = MemNew (NumDefLineModifiers () * sizeof (ModifierItemLocalData));
3554   if (eotd.modList == NULL) return;
3555 
3556   CountModifiers (eotd.modList, sep);
3557 
3558   eotd.organism_id_profile = NULL;
3559   GetOrganismIDProfile (sep, &eotd);
3560 
3561   if (SelectModifiersForExport (&eotd))
3562   {
3563     if (GetOutputFileName (path, sizeof (path), NULL))
3564         {
3565       eotd.fp = FileOpen (path, "w");
3566       if (eotd.fp == NULL) 
3567           {
3568             Message (MSG_ERROR, "Unable to open %s", path);
3569           }
3570           else
3571           {
3572             lead_str [0] = 0;
3573                 lead_str [1] = 0;
3574         /* print a header line */
3575             if (eotd.list_accession)
3576                 {
3577                   fprintf (eotd.fp, "Accession Number");
3578                   lead_str [0] = '\t';
3579                 }
3580                 if (eotd.list_local)
3581                 {
3582               fprintf (eotd.fp, "%sLocal ID", lead_str);
3583                   lead_str [0] = '\t';
3584                 }
3585         if (eotd.list_general)
3586                 {
3587                   fprintf (eotd.fp, "%sGeneral ID", lead_str);
3588                   lead_str [0] = '\t';
3589                 }
3590                 if (eotd.list_tax_name)
3591                 {
3592                   fprintf (eotd.fp, "%sTax Name", lead_str);
3593                   lead_str [0] = '\t';
3594                 }
3595 
3596         for (idx = 0; idx < NumDefLineModifiers (); idx++)
3597         {
3598           if (eotd.modList[idx].any_present)
3599           {
3600             fprintf (eotd.fp, "%s%s", lead_str, DefLineModifiers [idx].name);
3601             lead_str [0] = '\t';
3602           }
3603         }
3604         fprintf (eotd.fp, "\n");
3605         
3606         ExportOrganisms  (sep, &eotd);
3607         FileClose (eotd.fp);
3608           }
3609         }
3610   }
3611   for (idx=0; idx < NumDefLineModifiers (); idx++)
3612   {
3613     ValNodeFree (eotd.modList[idx].values_seen);
3614   }
3615   eotd.modList = MemFree (eotd.modList);
3616   eotd.organism_id_profile = ValNodeFree (eotd.organism_id_profile);
3617 }
3618 
3619 
3620 typedef struct qualifierselect {
3621   LisT gene_quals;
3622   LisT cds_quals;
3623   LisT import_quals;
3624 } QualifierSelectData, PNTR QualifierSelectPtr;
3625 
3626 typedef struct featurequalloadformdata {
3627   FEATURE_FORM_BLOCK
3628 
3629   ValNodePtr             line_list;
3630   ValNodePtr             featlist;
3631   Int4                   num_feats;
3632   Uint2                  entityID;
3633   LisT                   feature_type;
3634   QualifierSelectData    match_qual;
3635   QualifierSelectData    apply_qual;
3636   PopuP                  sequence_id_type;
3637   PopuP                  sequence_column;
3638   PopuP                  feature_column;
3639   PopuP                  apply_column;
3640   GrouP                  seq_group;
3641   GrouP                  match_group;
3642   GrouP                  apply_group;
3643   Boolean                asked_about_replace;
3644   Boolean                do_replace;
3645   Boolean                use_semicolon;
3646   ButtoN                 replace_with_blank_btn;
3647   Boolean                replace_with_blank;
3648   ButtoN                 accept_button;
3649 } FeatureQualLoadFormData, PNTR FeatureQualLoadFormPtr;
3650  
3651 static void CleanupFeatureQualLoadForm (
3652   GraphiC g,
3653   VoidPtr data
3654 )
3655 {
3656   FeatureQualLoadFormPtr form_data;
3657 
3658   form_data = (FeatureQualLoadFormPtr)data;
3659   if (form_data == NULL) return;
3660   CleanUpTableData (form_data->line_list);
3661   StdCleanupFormProc (g, data);
3662 } 
3663 
3664 typedef struct qualifierlistdata {
3665   CharPtr item_name;
3666 } QualifierListData, PNTR QualifierListPtr;
3667 
3668 static Int4 GetSubtypeFromOffsetInFeatureList (Int4 list_offset,
3669                                                ValNodePtr list)
3670 {
3671   ValNodePtr vnp;
3672 
3673   if (list == NULL || list_offset < 1) return -1;
3674 
3675   vnp = list;
3676   while (vnp != NULL && list_offset > 1)
3677   {
3678     list_offset --;
3679     vnp = vnp->next;
3680   }
3681   if (list_offset > 1) return -1;
3682   return vnp->choice;
3683 }
3684 
3685 static void ShowQualifierListBySubtype (QualifierSelectPtr qsp, Int4 feature_subtype)
3686 {
3687   if (feature_subtype == -1) {
3688     Hide (qsp->gene_quals);
3689     Hide (qsp->cds_quals);
3690     Hide (qsp->import_quals);
3691   } else if (feature_subtype == FEATDEF_GENE) {
3692     Show (qsp->gene_quals);
3693     Hide (qsp->cds_quals);
3694     Hide (qsp->import_quals);
3695   } else if (feature_subtype == FEATDEF_CDS) {
3696     Hide (qsp->gene_quals);
3697     Show (qsp->cds_quals);
3698     Hide (qsp->import_quals);
3699   } else {
3700     Hide (qsp->gene_quals);
3701     Hide (qsp->cds_quals);
3702     Show (qsp->import_quals);
3703   }
3704 }
3705 
3706 static void ShowQualifierLists (FeatureQualLoadFormPtr form_data)
3707 {
3708   Int4 feature_offset, feature_subtype;
3709 
3710   if (form_data == NULL) return;
3711 
3712   feature_offset = GetValue (form_data->feature_type);
3713   feature_subtype = GetSubtypeFromOffsetInFeatureList (feature_offset,
3714                                                        form_data->featlist);
3715   ShowQualifierListBySubtype (&(form_data->match_qual), feature_subtype);
3716   ShowQualifierListBySubtype (&(form_data->apply_qual), feature_subtype);
3717 }
3718 
3719 static QualifierListData GeneTableQualifiers [] = {
3720   { "allele"},
3721   { "locus" },
3722   { "locus_tag"},
3723   { "description"},
3724   { "product"}
3725 };
3726 
3727 #define NUM_GENE_TABLE_QUALIFIERS 5
3728 
3729 static QualifierListData ProtTableQualifiers [] = {
3730   { "product"},
3731   { "description"},
3732   { "comment"}
3733 };
3734 
3735 #define NUM_PROT_TABLE_QUALIFIERS 3
3736 
3737 /* check the appropriate list box for qualifier type,
3738  * keeping in mind that the first item is always "none"
3739  */
3740 static Int4 GetQualSelectBySubtype (QualifierSelectPtr qsp, Int4 feature_subtype)
3741 {
3742   Int4 qual_choice = -1;
3743 
3744   if (feature_subtype == -1) {
3745     qual_choice = -1;
3746   } else if (feature_subtype == FEATDEF_GENE) {
3747     qual_choice = GetValue (qsp->gene_quals);
3748     if (qual_choice < 2 
3749       || qual_choice > NUM_GENE_TABLE_QUALIFIERS + 2) {
3750       qual_choice = -1;
3751     } else {
3752       qual_choice = qual_choice - 1;
3753     }
3754   } else if (feature_subtype == FEATDEF_CDS) {
3755     qual_choice = GetValue (qsp->cds_quals);
3756     if (qual_choice < 2 
3757       || qual_choice > NUM_PROT_TABLE_QUALIFIERS + 2) {
3758       qual_choice = -1;
3759     } else {
3760       qual_choice = qual_choice - 1;
3761     }
3762   } else {
3763     qual_choice = GetValue (qsp->import_quals);
3764     if (qual_choice < 2
3765       || qual_choice > ParFlat_TOTAL_GBQUAL + 2) {
3766       qual_choice = -1;
3767     } else {
3768       qual_choice = qual_choice - 1;
3769     }
3770   }
3771   return qual_choice;
3772 
3773 }
3774 
3775 static void SetFeatureQualAcceptButton (Handle a)
3776 {
3777   FeatureQualLoadFormPtr form_data;
3778   Boolean                have_feature_select_column;
3779   Boolean                have_feature_qual_select_column;
3780   Int4                   feature_select_choice;
3781   Int4                   apply_qual_choice;
3782   Int4                   match_qual_choice;
3783   Int4                   feature_subtype;
3784   Boolean                seqid_select_ok;
3785   Int4                   seqid_select_type;
3786   Int4                   seqid_select_column;
3787 
3788   form_data = GetObjectExtra (a);
3789   if (form_data == NULL) return;
3790 
3791   ShowQualifierLists (form_data);
3792   have_feature_qual_select_column = FALSE;
3793   have_feature_select_column = FALSE;
3794   seqid_select_ok = FALSE;
3795 
3796   feature_select_choice = GetValue (form_data->feature_type);
3797   if ( feature_select_choice > 0 && feature_select_choice < form_data->num_feats)
3798   {
3799     have_feature_select_column = TRUE;
3800   }
3801   
3802   feature_subtype = GetSubtypeFromOffsetInFeatureList (feature_select_choice,
3803                                                        form_data->featlist);
3804   
3805   apply_qual_choice = GetQualSelectBySubtype (&(form_data->apply_qual),
3806                                               feature_subtype);
3807   if (apply_qual_choice != -1)
3808   {
3809     have_feature_qual_select_column = TRUE;
3810   }
3811 
3812   /* if a column is selected for a sequence identifier, must select type */
3813   /* if a column is not selected for a sequence identifier, must not select type */
3814   seqid_select_type = GetValue (form_data->sequence_id_type);
3815   seqid_select_column = GetValue (form_data->sequence_column);
3816   if (seqid_select_type == 1 || seqid_select_type == 2) {
3817     if (seqid_select_column > 0) {
3818       seqid_select_ok = TRUE;
3819     }
3820   } else {
3821     seqid_select_ok = TRUE;
3822   }
3823  
3824   /* if the feature column is not specified, must not have match qualifier */
3825   /* and must have sequence ID */
3826   /* if the feature column is specified, must have match qualifier */
3827   match_qual_choice = GetQualSelectBySubtype (&(form_data->match_qual),
3828                                               feature_subtype);
3829   if (GetValue (form_data->feature_column) < 1)
3830   {
3831     if (match_qual_choice != -1)
3832     {
3833       have_feature_select_column = FALSE;
3834     }
3835     else if (seqid_select_column < 1)
3836     {
3837       have_feature_select_column = FALSE;
3838     }
3839   } else {
3840     if (match_qual_choice == -1)
3841     {
3842       have_feature_select_column = FALSE;
3843     }
3844   }
3845 
3846   if (GetValue (form_data->apply_column) < 1) {
3847     have_feature_qual_select_column = FALSE;
3848   }
3849 
3850   if ( have_feature_select_column && have_feature_qual_select_column
3851     && seqid_select_ok)
3852   {
3853     Enable (form_data->accept_button);
3854   }
3855   else
3856   {
3857     Disable (form_data->accept_button);
3858   }
3859 }
3860 
3861 static Boolean ProductNameMatches (
3862   SeqLocPtr slp,
3863   BioseqPtr  bsp,
3864   CharPtr   pString
3865 )
3866 {
3867   SeqFeatPtr        sfp;
3868   SeqMgrFeatContext fcontext;
3869 
3870   if (slp == NULL || bsp == NULL || pString == NULL) return FALSE;
3871 
3872   sfp = SeqMgrGetNextFeature (bsp, NULL, SEQFEAT_CDREGION, 0, &fcontext);
3873   while (sfp != NULL)
3874   {
3875     if ( IsLocAInBonSameStrand (sfp->location, slp)
3876       && StringStr ( fcontext.label, pString) != NULL)
3877     {
3878       return TRUE;
3879     }
3880     sfp = SeqMgrGetNextFeature (bsp, sfp, SEQFEAT_CDREGION, 0, &fcontext);
3881   }
3882   return FALSE;
3883 }
3884 
3885 static Boolean GeneHasThisQualifier (
3886   SeqFeatPtr sfp,
3887   Uint2      entityID,
3888   CharPtr    pString,
3889   Int2       popup_offset
3890 )
3891 {
3892   BioseqPtr  bsp;
3893   GeneRefPtr grp;
3894 
3895   if (sfp == NULL || pString == NULL) return FALSE;
3896   if (popup_offset < 1 || popup_offset > NUM_GENE_TABLE_QUALIFIERS) return FALSE;
3897 
3898   grp = (GeneRefPtr) sfp->data.value.ptrvalue;
3899   if (grp == NULL) return FALSE;
3900 
3901   if ( StringCmp (GeneTableQualifiers [popup_offset - 1].item_name, "allele") == 0) {
3902     if (StringCmp (pString, grp->allele) == 0) {
3903       return TRUE;
3904     } else {
3905       return FALSE;
3906     }
3907   } else if ( StringCmp (GeneTableQualifiers [popup_offset - 1].item_name, "locus") == 0) {
3908     if (StringCmp (pString, grp->locus) == 0) {
3909       return TRUE;
3910     } else {
3911       return FALSE;
3912     }
3913   } else if ( StringCmp (GeneTableQualifiers [popup_offset - 1].item_name, "locus_tag") == 0) {
3914     if (StringCmp (pString, grp->locus_tag) == 0) {
3915       return TRUE;
3916     } else {
3917       return FALSE;
3918     }
3919   } else if ( StringCmp (GeneTableQualifiers [popup_offset - 1].item_name, "description") == 0) {
3920     if (StringCmp (pString, grp->desc) == 0) {
3921       return TRUE;
3922     } else {
3923       return FALSE;
3924     }
3925   } else if ( StringCmp (GeneTableQualifiers [popup_offset - 1].item_name, "product") == 0)
3926   {
3927     bsp = GetBioseqGivenSeqLoc (sfp->location, entityID);
3928     return ProductNameMatches (sfp->location, bsp, pString);
3929   }
3930   return FALSE;
3931 }
3932 
3933 static Boolean ProteinHasThisQualifier (
3934   SeqFeatPtr sfp,
3935   CharPtr    pString,
3936   Int2       popup_offset
3937 )
3938 {
3939   ProtRefPtr prp;
3940 
3941   if (sfp == NULL || sfp->data.choice != SEQFEAT_PROT || pString == NULL
3942     || popup_offset < 1 || popup_offset > NUM_PROT_TABLE_QUALIFIERS)
3943   {
3944     return FALSE;
3945   }
3946 
3947   prp = sfp->data.value.ptrvalue;
3948   if (prp == NULL) return FALSE;
3949 
3950   if (StringCmp (ProtTableQualifiers [ popup_offset - 1].item_name, "product") == 0)
3951   {
3952     if (prp->name != NULL
3953       && StringStr (prp->name->data.ptrvalue, pString) != NULL)
3954     {
3955       return TRUE;
3956     }
3957   } else if (StringCmp (ProtTableQualifiers [popup_offset - 1].item_name, "description") == 0) {
3958     if (StringStr (prp->desc, pString) != NULL)
3959     {
3960       return TRUE;
3961     }
3962   } else if (StringCmp (ProtTableQualifiers [popup_offset - 1].item_name, "comment") == 0) {
3963     if (StringStr (sfp->comment, pString) != NULL)
3964     {
3965       return TRUE;
3966     }
3967   }
3968   return FALSE;
3969 }
3970 
3971 static Boolean CDSHasThisQualifier (
3972   SeqFeatPtr sfp,
3973   Uint2      entityID,
3974   CharPtr    pString,
3975   Int2       popup_offset
3976 )
3977 {
3978   SeqFeatPtr protein;
3979 
3980   if (sfp == NULL || pString == NULL) return FALSE;
3981 
3982   if (StringCmp (ProtTableQualifiers [popup_offset - 1].item_name, "comment") == 0) {
3983     if (StringStr (sfp->comment, pString) != NULL)
3984     {
3985       return TRUE;
3986     }
3987   }
3988   else
3989   {
3990     protein = FindBestProtein (entityID, sfp->product);
3991     if (protein == NULL) return FALSE;
3992     return ProteinHasThisQualifier (protein, pString, popup_offset);
3993   }
3994   return FALSE;
3995 }
3996   
3997 static Boolean FeatureHasThisQualifier (
3998   SeqFeatPtr sfp,
3999   Uint2      entityID,
4000   CharPtr    pString,
4001   Int2       popup_offset
4002 )
4003 {
4004   Int2      qualval;
4005   GBQualPtr gbqual;
4006 
4007   if (popup_offset < 1) return FALSE;
4008   if (sfp == NULL || pString == NULL) return FALSE;
4009 
4010   if (sfp->idx.subtype == FEATDEF_GENE)
4011   {
4012     return GeneHasThisQualifier (sfp, entityID, pString, popup_offset);
4013   }
4014   else if (sfp->idx.subtype == FEATDEF_CDS)
4015   {
4016     return CDSHasThisQualifier (sfp, entityID, pString, popup_offset);
4017   }
4018   else
4019   {
4020     for (gbqual = sfp->qual; gbqual != NULL; gbqual = gbqual->next)
4021     {
4022       qualval = GBQualNameValid (gbqual->qual);
4023       if (qualval > -1 && qualval == popup_offset -1)
4024       {
4025         return TRUE;
4026       }
4027     }
4028   }
4029   return FALSE; 
4030 }
4031  
4032 static CharPtr GetDataForColumnOffset (ValNodePtr column_data, Int4 offset)
4033 {
4034   ValNodePtr vnp;
4035 
4036   for (vnp = column_data; vnp != NULL && offset > 1; vnp = vnp->next)
4037   {
4038     offset --;
4039   }
4040   if (offset > 1 || vnp == NULL) {
4041     return NULL;
4042   } else {
4043     return vnp->data.ptrvalue;
4044   }
4045 }
4046 
4047 static Boolean ApplyQualToThisFeature (
4048   SeqFeatPtr sfp,
4049   ValNodePtr parts,
4050   FeatureQualLoadFormPtr form_data
4051 )
4052 {
4053   Int4       column_index;
4054   CharPtr    val;
4055   Int4       subtype;
4056   Int4       popup_offset;
4057 
4058   if (sfp == NULL || parts == NULL || form_data == NULL) return FALSE;
4059 
4060   column_index = GetValue (form_data->feature_column);
4061   subtype = GetSubtypeFromOffsetInFeatureList (
4062                      GetValue (form_data->feature_type), form_data->featlist);
4063   val = GetDataForColumnOffset (parts, column_index);
4064 
4065   if (val != NULL && sfp->idx.subtype == subtype)
4066   {
4067     popup_offset = GetQualSelectBySubtype (&(form_data->match_qual),
4068                                               subtype);
4069     if (popup_offset < 1
4070       || FeatureHasThisQualifier (sfp, form_data->entityID, val, popup_offset))
4071     {
4072       return TRUE;
4073     }
4074   }
4075   return FALSE;
4076 }
4077 
4078 typedef struct featurequaltabledata {
4079   ValNodePtr parts;
4080   FeatureQualLoadFormPtr form_data;
4081 } FeatureQualTableData, PNTR FeatureQualTablePtr;
4082 
4083 static void ApplyOneQualToProt (
4084   SeqFeatPtr sfp,
4085   Int2       popup_offset,
4086   CharPtr    pString,
4087   Boolean PNTR asked_about_replace,
4088   Boolean PNTR do_replace,
4089   Boolean PNTR use_semicolon)
4090 {
4091   ProtRefPtr prp;
4092   CharPtr    cp;
4093 
4094   if (sfp == NULL || sfp->data.choice != SEQFEAT_PROT || pString == NULL
4095     || popup_offset < 1 || popup_offset > NUM_PROT_TABLE_QUALIFIERS
4096     || asked_about_replace == NULL
4097     || do_replace == NULL
4098     || use_semicolon == NULL)
4099   {
4100     return;
4101   }
4102 
4103   prp = sfp->data.value.ptrvalue;
4104   if (prp == NULL) return;
4105 
4106   if (StringCmp (ProtTableQualifiers [ popup_offset - 1].item_name, "product") == 0)
4107   {
4108     if (prp->name == NULL)
4109     {
4110       ValNodeAddStr (&prp->name, 0, StringSave (pString));
4111     }
4112     else
4113     {
4114       cp = prp->name->data.ptrvalue;
4115       AppendOrReplaceString (&cp, pString,
4116                             asked_about_replace, do_replace, use_semicolon);
4117       prp->name->data.ptrvalue = cp;
4118     }
4119   } else if (StringCmp (ProtTableQualifiers [popup_offset - 1].item_name, "description") == 0) {
4120     AppendOrReplaceString (&(prp->desc), pString,
4121                             asked_about_replace, do_replace, use_semicolon);
4122   } else if (StringCmp (ProtTableQualifiers [popup_offset - 1].item_name, "comment") == 0) {
4123     AppendOrReplaceString (&(sfp->comment), pString, 
4124                             asked_about_replace, do_replace, use_semicolon);
4125   }
4126 }
4127 
4128 static void ApplyOneQualToCDS (
4129   SeqFeatPtr sfp,
4130   Uint2      entityID,
4131   Int2       feat_qual_choice,
4132   CharPtr    pString,
4133   Boolean PNTR asked_about_replace,
4134   Boolean PNTR do_replace,
4135   Boolean PNTR use_semicolon)
4136 {
4137   SeqFeatPtr protein;
4138 
4139   if (sfp == NULL || pString == NULL
4140     || asked_about_replace == NULL
4141     || do_replace == NULL
4142     || use_semicolon == NULL)
4143   {
4144     return;
4145   }
4146 
4147   if (StringCmp (ProtTableQualifiers [feat_qual_choice - 1].item_name, "comment") == 0) {
4148     AppendOrReplaceString (&(sfp->comment), pString, 
4149                             asked_about_replace, do_replace, use_semicolon);
4150   }
4151   else
4152   {
4153     protein = FindBestProtein (entityID, sfp->product);
4154     if (protein == NULL) return;
4155     ApplyOneQualToProt (protein, feat_qual_choice, pString, 
4156                             asked_about_replace, do_replace, use_semicolon);
4157   }
4158 }
4159 
4160 static void ApplyGeneProductName (
4161   SeqLocPtr slp,
4162   Uint2     entityID,
4163   CharPtr   pString,
4164   Boolean PNTR asked_about_replace,
4165   Boolean PNTR do_replace,
4166   Boolean PNTR use_semicolon)
4167 {
4168   SeqFeatPtr        sfp;
4169   SeqMgrFeatContext fcontext;
4170   Int4              prot_popup_offset;
4171   BioseqPtr         bsp;
4172 
4173   if (slp == NULL || pString == NULL
4174     || asked_about_replace == NULL
4175     || do_replace == NULL
4176     || use_semicolon == NULL)
4177   {
4178     return;
4179   }
4180 
4181   bsp = GetBioseqGivenSeqLoc (slp, entityID);
4182   if (bsp == NULL) return;
4183 
4184   for (prot_popup_offset = 0;
4185        prot_popup_offset < NUM_PROT_TABLE_QUALIFIERS
4186          && StringCmp (ProtTableQualifiers [prot_popup_offset].item_name, "product") != 0;
4187        prot_popup_offset ++)
4188   {}
4189   if (prot_popup_offset >= NUM_PROT_TABLE_QUALIFIERS) return;
4190 
4191   sfp = SeqMgrGetNextFeature (bsp, NULL, SEQFEAT_CDREGION, 0, &fcontext);
4192   while (sfp != NULL)
4193   {
4194     if ( IsLocAInBonSameStrand (sfp->location, slp))
4195     {
4196       ApplyOneQualToCDS (sfp, entityID, prot_popup_offset + 1, pString, 
4197                             asked_about_replace, do_replace, use_semicolon);
4198     }
4199     sfp = SeqMgrGetNextFeature (bsp, sfp, SEQFEAT_CDREGION, 0, &fcontext);
4200   }
4201 }
4202 
4203 static void ApplyOneQualToGene (
4204   SeqFeatPtr sfp,
4205   Uint2      entityID,
4206   Int2       feat_qual_choice,
4207   CharPtr    pString, 
4208   Boolean PNTR asked_about_replace,
4209   Boolean PNTR do_replace,
4210   Boolean PNTR use_semicolon)
4211 {
4212   GeneRefPtr grp;
4213 
4214   if (sfp == NULL
4215     || sfp->idx.subtype != FEATDEF_GENE
4216     || feat_qual_choice < 1
4217     || feat_qual_choice > NUM_GENE_TABLE_QUALIFIERS
4218     || pString == NULL
4219     || asked_about_replace == NULL
4220     || do_replace == NULL
4221     || use_semicolon == NULL)
4222   {
4223     return;
4224   }
4225 
4226   grp = (GeneRefPtr) sfp->data.value.ptrvalue;
4227   if (grp == NULL) return;
4228 
4229   if (StringCmp ( GeneTableQualifiers [feat_qual_choice - 1].item_name,
4230                  "allele") == 0) {
4231     AppendOrReplaceString (&(grp->allele), pString, 
4232                             asked_about_replace, do_replace, use_semicolon);
4233   } else if (StringCmp ( GeneTableQualifiers [feat_qual_choice - 1].item_name,
4234                         "locus") == 0) {
4235     AppendOrReplaceString (&(grp->locus), pString, 
4236                             asked_about_replace, do_replace, use_semicolon);
4237   } else if (StringCmp ( GeneTableQualifiers [feat_qual_choice - 1].item_name,
4238                         "locus_tag") == 0) {
4239     AppendOrReplaceString (&(grp->locus_tag), pString, 
4240                             asked_about_replace, do_replace, use_semicolon);
4241   } else if (StringCmp ( GeneTableQualifiers [feat_qual_choice - 1].item_name,
4242                         "description") == 0) {
4243     AppendOrReplaceString (&(grp->desc), pString, 
4244                             asked_about_replace, do_replace, use_semicolon);
4245   } else if (StringCmp (GeneTableQualifiers [feat_qual_choice - 1].item_name,
4246                         "product") == 0) {
4247     ApplyGeneProductName (sfp->location, entityID, pString, 
4248                             asked_about_replace, do_replace, use_semicolon);
4249   }
4250 }
4251 
4252 static void ApplyOneQualToImportFeature (
4253   SeqFeatPtr sfp,
4254   Int2 feat_qual_choice,
4255   CharPtr pString,
4256   Boolean PNTR asked_about_replace,
4257   Boolean PNTR do_replace,
4258   Boolean PNTR use_semicolon)
4259 {
4260   GBQualPtr           gbqual;
4261 
4262   if (sfp == NULL
4263     || feat_qual_choice < 1
4264     || feat_qual_choice > ParFlat_TOTAL_GBQUAL
4265     || pString == NULL
4266     || asked_about_replace == NULL
4267     || do_replace == NULL
4268     || use_semicolon == NULL)
4269   {
4270     return;
4271   }
4272 
4273   gbqual = sfp->qual;
4274   while (gbqual != NULL
4275     && StringCmp (gbqual->qual,
4276                   ParFlat_GBQual_names [feat_qual_choice - 1].name) != 0)
4277   {
4278     gbqual = gbqual->next;
4279   }
4280   
4281   if (gbqual == NULL)
4282   {
4283     gbqual = GBQualNew ();
4284     if (gbqual == NULL) return;
4285     gbqual->qual = StringSave ( ParFlat_GBQual_names [feat_qual_choice - 1].name);
4286     gbqual->val = StringSave ( pString );
4287     gbqual->next = sfp->qual;
4288     sfp->qual = gbqual;
4289   }
4290   else
4291   {
4292     AppendOrReplaceString (&(gbqual->val), pString, 
4293                             asked_about_replace, do_replace, use_semicolon);
4294   }
4295 }
4296 
4297 static void ApplyOneQualToFeature (
4298   SeqFeatPtr sfp,
4299   Uint2      entityID,
4300   Int2       feat_qual_choice,
4301   CharPtr    pString,
4302   Boolean PNTR asked_about_replace,
4303   Boolean PNTR do_replace,
4304   Boolean PNTR use_semicolon)
4305 {
4306   if (sfp == NULL || pString == NULL 
4307     || asked_about_replace == NULL
4308     || do_replace == NULL
4309     || use_semicolon == NULL)
4310   {
4311     return;
4312   }
4313 
4314   switch (sfp->idx.subtype)
4315   {
4316     case FEATDEF_GENE :
4317       ApplyOneQualToGene (sfp, entityID, feat_qual_choice, pString,
4318                             asked_about_replace, do_replace, use_semicolon);
4319       break;
4320     case FEATDEF_CDS :
4321       ApplyOneQualToCDS (sfp, entityID, feat_qual_choice, pString,
4322                             asked_about_replace, do_replace, use_semicolon);
4323       break;
4324     default :
4325       ApplyOneQualToImportFeature (sfp, feat_qual_choice, pString,
4326                             asked_about_replace, do_replace, use_semicolon);
4327       break;
4328   }
4329 }
4330 
4331 static CharPtr GetImpFeatKeyFromSubtype (Uint2 subtype)
4332 {
4333   FeatDefPtr  curr;
4334   Uint1       key;
4335   CharPtr     label;
4336 
4337   curr = FeatDefFindNext (NULL, &key, &label, FEATDEF_ANY, TRUE);
4338   while (curr != NULL) {
4339     if (key == subtype)
4340     {
4341       return curr->typelabel;
4342     }
4343     curr = FeatDefFindNext (curr, &key, &label, FEATDEF_ANY, TRUE);
4344   }
4345   return NULL;
4346 }
4347 
4348 static void ApplyQualsToFeaturesOnBsp (BioseqPtr bsp,
4349  FeatureQualLoadFormPtr form_data,
4350  ValNodePtr             parts)
4351 {
4352   SeqFeatPtr sfp;
4353   SeqMgrFeatContext fcontext;
4354   Boolean found_feature = FALSE;
4355   Int4                subtype;
4356   Int4                column_index;
4357   Int2                qualval;
4358   Int2                matchval;
4359   CharPtr             val;
4360   ImpFeatPtr          ifp;
4361 
4362   subtype = GetSubtypeFromOffsetInFeatureList (
4363                           GetValue (form_data->feature_type), 
4364                           form_data->featlist);
4365   column_index = GetValue (form_data->apply_column);
4366   val = GetDataForColumnOffset (parts, column_index);
4367   /* if the value to be applied is blank and we're not replacing with blanks, skip */
4368   if (! form_data->replace_with_blank && StringHasNoText (val)) {
4369     return;
4370   }
4371   qualval = GetQualSelectBySubtype (&(form_data->apply_qual), subtype);
4372   if (subtype == -1 || val == NULL || column_index < 1 || qualval < 1) {
4373     /* do nothing */
4374   }
4375   else
4376   {
4377     sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &fcontext);
4378     while (sfp != NULL)
4379     {
4380       if ( ApplyQualToThisFeature (sfp, parts, form_data))
4381       {
4382         found_feature = TRUE;
4383         ApplyOneQualToFeature (sfp, form_data->entityID, qualval, val,
4384                                &(form_data->asked_about_replace),
4385                                &(form_data->do_replace),
4386                                &(form_data->use_semicolon));
4387       }
4388       sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &fcontext);
4389     }
4390 
4391     /* only want to create new features if no feature matching qualifier
4392      * was specified and no feature was found */
4393     matchval = GetQualSelectBySubtype (&(form_data->match_qual), subtype);
4394 
4395     if (! found_feature && matchval == -1)
4396     {
4397       if (subtype == FEATDEF_CDS)
4398       {
4399         sfp = CreateNewFeatureOnBioseq (bsp, SEQFEAT_CDREGION, NULL);
4400         if (sfp == NULL) return;
4401         sfp->data.value.ptrvalue = CdRegionNew ();
4402       } else if (subtype == FEATDEF_GENE) {
4403         sfp = CreateNewFeatureOnBioseq (bsp, SEQFEAT_GENE, NULL);
4404         if (sfp == NULL) return;
4405         sfp->data.value.ptrvalue = GeneRefNew ();
4406       } else {
4407         ifp = ImpFeatNew ();
4408         if (ifp == NULL) return;
4409         sfp = CreateNewFeatureOnBioseq (bsp, SEQFEAT_IMP, NULL);
4410         if (sfp == NULL) return;
4411         ifp->key = StringSave ( GetImpFeatKeyFromSubtype (subtype));
4412         sfp->data.value.ptrvalue = ifp;
4413       }
4414       SeqMgrIndexFeatures (0, (Pointer) bsp);
4415       ApplyOneQualToFeature (sfp, form_data->entityID, qualval, val,
4416                                &(form_data->asked_about_replace),
4417                                &(form_data->do_replace),
4418                                &(form_data->use_semicolon));
4419     }
4420   }
4421 }
4422 
4423 static void ApplyTableQuals (BioseqPtr bsp, Pointer userdata)
4424 {
4425   FeatureQualLoadFormPtr form_data;
4426   SeqDescrPtr            sdp;
4427   GBBlockPtr             gbp;
4428   Int4                   column_index;
4429   ValNodePtr             line;
4430   TableLinePtr           tlp;
4431   Boolean                use_local_id = FALSE;
4432   FeatureQualTableData   fqtd;
4433   Int2                   seq_match_choice;
4434   CharPtr                idval;
4435   
4436   form_data = (FeatureQualLoadFormPtr) userdata;
4437   if (form_data == NULL || bsp == NULL) return;
4438 
4439   gbp = NULL;
4440   sdp = BioseqGetSeqDescr (bsp, Seq_descr_genbank, NULL);
4441   if (sdp != NULL)
4442   {
4443     gbp = sdp->data.ptrvalue;
4444   }
4445 
4446   seq_match_choice = GetValue (form_data->sequence_id_type);
4447   if (seq_match_choice == 1) {
4448     use_local_id = FALSE;
4449   }
4450 
4451   fqtd.form_data = form_data;
4452   if (seq_match_choice == 1 || seq_match_choice == 2)
4453   {
4454     column_index = GetValue (form_data->sequence_column);
4455 
4456     for (line = form_data->line_list; line != NULL; line = line->next)
4457     {
4458       tlp = line->data.ptrvalue;
4459       if (tlp == NULL) continue;
4460       idval = GetDataForColumnOffset (tlp->parts, column_index);
4461       if (idval != NULL
4462         && ( IDListHasValue ( idval,
4463                               bsp->id, use_local_id, FALSE, FALSE)
4464           || (! use_local_id && 
4465               HasExtraAccession ( idval, gbp))))
4466       {
4467         fqtd.parts = tlp->parts;
4468         ApplyQualsToFeaturesOnBsp (bsp, form_data, tlp->parts);
4469       }
4470     }
4471   } else {
4472     for (line = form_data->line_list; line != NULL; line = line->next)
4473     {
4474       tlp = line->data.ptrvalue;
4475       if (tlp == NULL) continue;
4476       fqtd.parts = tlp->parts;
4477       ApplyQualsToFeaturesOnBsp (bsp, form_data, tlp->parts);
4478     }
4479   }
4480 }
4481 
4482 static void DoAcceptFeatureQuals (ButtoN b)
4483 {
4484   FeatureQualLoadFormPtr form_data;
4485   SeqEntryPtr   sep;
4486 
4487   form_data = GetObjectExtra (b);
4488   if (form_data == NULL) return;
4489 
4490   form_data->replace_with_blank = GetStatus (form_data->replace_with_blank_btn);
4491 
4492   sep = GetTopSeqEntryForEntityID (form_data->entityID);
4493   if (sep == NULL) return;
4494   
4495   VisitBioseqsInSep (sep, form_data, ApplyTableQuals);
4496   Update ();
4497   ObjMgrSetDirtyFlag (form_data->entityID, TRUE);
4498   ObjMgrSendMsg (OM_MSG_UPDATE, form_data->entityID, 0, 0);
4499   Remove (form_data->form);
4500 }
4501 
4502 static PopuP BuildColumnSelector ( GrouP g,
4503                                   FeatureQualLoadFormPtr parent_form,
4504                                   ValNodePtr parts )
4505 {
4506   PopuP      p;
4507   ValNodePtr this_part;
4508 
4509   if (g == NULL || parts == NULL) return NULL;
4510 
4511   p = PopupList (g, TRUE, (PupActnProc) SetFeatureQualAcceptButton);
4512   for (this_part = parts; this_part != NULL; this_part = this_part->next)
4513   {
4514     if (this_part->data.ptrvalue != NULL)
4515     {
4516       PopupItem (p, this_part->data.ptrvalue);
4517     }
4518   }
4519   SetObjectExtra (p, parent_form, NULL);
4520   return p;
4521 }
4522 
4523 static void BuildQualifierSelect ( GrouP parent, 
4524                                   FeatureQualLoadFormPtr parent_form,
4525                                   ValNodePtr parts,
4526                                   QualifierSelectPtr qsp )
4527 {
4528   GrouP g;
4529   Int4  listheight = 4;
4530   Int4  listwidth  = 13;
4531   Int4  j;
4532 
4533   if (parent_form == NULL || parts == NULL || qsp == NULL)
4534   {
4535     return;
4536   }
4537 
4538   g = HiddenGroup (parent, 0, 0, NULL);
4539 
4540   qsp->gene_quals = SingleList (g, listwidth, listheight,
4541                                    (LstActnProc) SetFeatureQualAcceptButton);
4542   SetObjectExtra (qsp->gene_quals, parent_form, NULL);
4543   ListItem (qsp->gene_quals, "None");
4544   for (j=0; j < NUM_GENE_TABLE_QUALIFIERS; j++) {
4545     ListItem (qsp->gene_quals, GeneTableQualifiers [j].item_name);
4546   }
4547   SetValue (qsp->gene_quals, 1);
4548 
4549   qsp->cds_quals = SingleList (g, listwidth, listheight,
4550                                    (LstActnProc) SetFeatureQualAcceptButton);
4551   SetObjectExtra (qsp->cds_quals, parent_form, NULL);
4552   ListItem (qsp->cds_quals, "None");
4553   for (j=0; j < NUM_PROT_TABLE_QUALIFIERS; j++) {
4554     ListItem (qsp->cds_quals, ProtTableQualifiers [j].item_name);
4555   }
4556   SetValue (qsp->cds_quals, 1);
4557 
4558   qsp->import_quals = SingleList (g, listwidth, listheight,
4559                                    (LstActnProc) SetFeatureQualAcceptButton);
4560   SetObjectExtra (qsp->import_quals, parent_form, NULL);
4561   ListItem (qsp->import_quals, "None");
4562   for (j = 0; j < ParFlat_TOTAL_GBQUAL; j++) {
4563     ListItem (qsp->import_quals, ParFlat_GBQual_names [j].name);
4564   }
4565   SetValue (qsp->import_quals, 1);
4566 }
4567 
4568 static void BuildSequenceSelect ( GrouP parent,
4569                                   FeatureQualLoadFormPtr parent_form,
4570                                   ValNodePtr parts )
4571 {
4572   if (parent == NULL || parent_form == NULL || parts == NULL) return;
4573 
4574   parent_form->seq_group = NormalGroup ( parent, 0, 2, "Sequence", programFont, NULL);
4575   StaticPrompt (parent_form->seq_group, "Identifier Type", 0, popupMenuHeight, programFont, 'l');
4576   parent_form->sequence_id_type = PopupList (parent_form->seq_group, TRUE, (PupActnProc) SetFeatureQualAcceptButton);
4577   PopupItem (parent_form->sequence_id_type, "Accession");
4578   PopupItem (parent_form->sequence_id_type, "Local ID");
4579   PopupItem (parent_form->sequence_id_type, "None");
4580   SetObjectExtra (parent_form->sequence_id_type, parent_form, NULL);
4581   SetValue (parent_form->sequence_id_type, 3);
4582 
4583   StaticPrompt (parent_form->seq_group, "Column", 0, popupMenuHeight, programFont, 'l');
4584   parent_form->sequence_column = BuildColumnSelector ( parent_form->seq_group, parent_form, parts);
4585 }
4586 
4587 static void BuildFeatureSelect ( GrouP parent,
4588                                  FeatureQualLoadFormPtr parent_form,
4589                                  ValNodePtr parts )
4590 {
4591   Int4  listheight = 4;
4592   ValNodePtr vnp;
4593 
4594   if (parent == NULL || parent_form == NULL || parts == NULL) return;
4595 
4596   parent_form->match_group = NormalGroup ( parent, 0, 2,
4597                                     "Feature to Edit", programFont, NULL);
4598   StaticPrompt (parent_form->match_group, "Feature type", 0, 
4599                                    popupMenuHeight, programFont, 'l');
4600   parent_form->feature_type = SingleList (parent_form->match_group, 
4601                                    9, listheight,
4602                    (LstActnProc) SetFeatureQualAcceptButton);
4603   SetObjectExtra (parent_form->feature_type, parent_form, NULL);
4604   for (vnp = parent_form->featlist; vnp != NULL; vnp = vnp->next)
4605   {
4606     ListItem (parent_form->feature_type, (CharPtr) vnp->data.ptrvalue);
4607   }
4608 
4609   StaticPrompt (parent_form->match_group, "Qualifier to match", 0, popupMenuHeight, programFont, 'l');
4610   BuildQualifierSelect ( parent_form->match_group, parent_form, parts, &(parent_form->match_qual));
4611 
4612   StaticPrompt (parent_form->match_group, "Column", 0, popupMenuHeight, programFont, 'l');
4613   parent_form->feature_column = BuildColumnSelector ( parent_form->match_group, parent_form, parts);
4614   
4615 }
4616 
4617 static void BuildFeatureApply ( GrouP parent,
4618                                FeatureQualLoadFormPtr parent_form,
4619                                ValNodePtr parts )
4620 {
4621   if (parent == NULL || parent_form == NULL || parts == NULL) return;
4622 
4623   parent_form->apply_group = NormalGroup ( parent, 0, 2, "Qualifier to Edit", programFont, NULL);
4624   
4625   StaticPrompt (parent_form->apply_group, "Qualifier Name", 0, popupMenuHeight, programFont, 'l');
4626   BuildQualifierSelect ( parent_form->apply_group, parent_form, parts, &(parent_form->apply_qual));
4627 
4628   StaticPrompt (parent_form->apply_group, "Column", 0, popupMenuHeight, programFont, 'l');
4629   parent_form->apply_column = BuildColumnSelector ( parent_form->apply_group, parent_form, parts);
4630   
4631 }
4632 
4633 extern void LoadFeatureQualifierTable (IteM i)
4634 {
4635   BaseFormPtr   bfp;
4636   ValNodePtr    header_line;
4637   ValNodePtr    vnp;
4638   TableLinePtr  tlp;
4639   WindoW        w;
4640   GrouP         h, g, c;
4641   FeatureQualLoadFormPtr form_data;
4642   Int4          max_columns;
4643 
4644 #ifdef WIN_MAC
4645   bfp = currentFormDataPtr;
4646 #else
4647   bfp = GetObjectExtra (i);
4648 #endif
4649   if (bfp == NULL) return;
4650 
4651   header_line = ReadTableData ();
4652   if (header_line == NULL || header_line->data.ptrvalue == NULL) return;
4653   tlp = header_line->data.ptrvalue;
4654   max_columns = 0;
4655   for (vnp = tlp->parts; vnp != NULL; vnp = vnp->next)
4656   {
4657     max_columns ++;
4658   }
4659   
4660   form_data = MemNew (sizeof (FeatureQualLoadFormData));
4661   if (form_data == NULL) return;
4662   form_data->asked_about_replace = FALSE;
4663   form_data->do_replace = FALSE;
4664   form_data->use_semicolon = FALSE;
4665   form_data->entityID = bfp->input_entityID;
4666   form_data->line_list = header_line;
4667   form_data->featlist = BuildFeatureValNodeList (TRUE, NULL, 0, TRUE, FALSE);
4668   form_data->num_feats = 0;
4669   for (vnp = form_data->featlist; vnp != NULL; vnp = vnp->next)
4670   {
4671     form_data->num_feats ++;
4672   }
4673 
4674   /* now create a dialog to display values */
4675   w = FixedWindow (-50, -33, -10, -10, "Table Conversion", StdCloseWindowProc);
4676   SetObjectExtra (w, form_data, CleanupFeatureQualLoadForm);
4677   form_data->form = (ForM) w;
4678 
4679   h = HiddenGroup (w, -1, 0, NULL);
4680   SetGroupSpacing (h, 10, 10);
4681 
4682   BuildSequenceSelect ( h, form_data, tlp->parts);
4683   BuildFeatureSelect (h, form_data, tlp->parts);
4684   BuildFeatureApply (h, form_data, tlp->parts);
4685   ShowQualifierLists (form_data);
4686 
4687   g = HiddenGroup (h, 1, 0, NULL);
4688   form_data->replace_with_blank_btn = CheckBox (g, "Erase current value when blank found in table", NULL);
4689   c = HiddenGroup (h, 4, 0, NULL);
4690   form_data->accept_button = DefaultButton (c, "Accept", DoAcceptFeatureQuals);
4691   SetObjectExtra (form_data->accept_button, form_data, NULL);
4692   Disable (form_data->accept_button);
4693   PushButton (c, "Cancel", StdCancelButtonProc);
4694 
4695   AlignObjects (ALIGN_CENTER,
4696                 (HANDLE) form_data->seq_group, 
4697                 (HANDLE) form_data->match_group,
4698                 (HANDLE) form_data->apply_group,
4699                 (HANDLE) c, NULL);
4700 
4701   RealizeWindow (w);
4702   Show (w);
4703   Update ();
4704 }
4705 
4706 
4707 typedef struct qualloadformdata {
4708   FEATURE_FORM_BLOCK
4709   ValNodePtr             table;
4710   DialoG                 list_dlg;
4711   DialoG PNTR            column_list;
4712   Int4                   num_columns;
4713   ButtoN                 remove_quotes;
4714   ButtoN                 accept_button;
4715 } QualLoadFormData, PNTR QualLoadFormPtr;
4716 
4717 static void CleanupQualLoadForm (
4718   GraphiC g,
4719   VoidPtr data
4720 )
4721 {
4722   QualLoadFormPtr form_data;
4723 
4724   form_data = (QualLoadFormPtr)data;
4725   if (form_data == NULL) return;
4726   form_data->table = FreeTabTable (form_data->table);
4727   StdCleanupFormProc (g, data);
4728 } 
4729 
4730 
4731 static void ChangeTabColumnChoice (Pointer data)
4732 {
4733   QualLoadFormPtr form_data;
4734   Int4            i;
4735   Boolean         have_match = FALSE, have_apply = FALSE;
4736   TabColumnConfigPtr t;
4737   ValNodePtr         err_list = NULL;
4738 
4739   if (data == NULL) return;
4740 
4741   form_data = (QualLoadFormPtr) data;
4742   /* must have one and only one match choice, must have at least one apply choice */
4743 
4744   if (form_data->list_dlg == NULL) {
4745     for (i = 0; i < form_data->num_columns; i++) {
4746       t = (TabColumnConfigPtr) DialogToPointer (form_data->column_list[i]);
4747       if (t != NULL) {
4748         if (t->match_type != NULL) {
4749           if (have_match) {
4750             Disable (form_data->accept_button);
4751             return;
4752           } else {
4753             have_match = TRUE;
4754           }
4755         } else if (!IsFieldTypeEmpty(t->field)) {
4756           have_apply = TRUE;
4757         }
4758       }
4759       t = TabColumnConfigFree (t);
4760     }
4761     if (have_match && have_apply) {
4762       Enable (form_data->accept_button);
4763     } else {
4764       Disable (form_data->accept_button);
4765     }
4766   } else {
4767     err_list = TestDialog (form_data->list_dlg);
4768     if (err_list == NULL) {
4769       Enable (form_data->accept_button);
4770     } else {
4771       Disable (form_data->accept_button);
4772       err_list = ValNodeFree (err_list);
4773     }
4774   }
4775 }
4776 
4777 
4778 static Boolean ApplyTableValues (SeqEntryPtr sep, ValNodePtr table, ValNodePtr columns)
4779 {
4780   ValNodePtr err_list, vnp, obj_table, dup_dest_errs;
4781   LogInfoPtr lip;
4782   Int4       msg_len = 0;
4783   CharPtr    msg = NULL, msg_end = "Continue with errors?  Hit cancel to scroll through details";
4784 
4785   lip = OpenLog ("Table Problems");
4786 
4787   err_list = ValidateTabTableValues (table, columns);
4788   for (vnp = err_list; vnp != NULL; vnp = vnp->next) {
4789     fprintf (lip->fp, "%s\n", vnp->data.ptrvalue);
4790     lip->data_in_log = TRUE;
4791   }
4792   err_list = ValNodeFreeData (err_list);
4793 
4794   obj_table = GetObjectTableForTabTable (sep, table, columns, &err_list);
4795 
4796   dup_dest_errs = CheckObjTableForRowsThatApplyToTheSameDestination (obj_table);
4797   if (dup_dest_errs != NULL) {
4798     for (vnp = dup_dest_errs; vnp != NULL; vnp = vnp->next) {
4799       fprintf (lip->fp, "%s\n", vnp->data.ptrvalue);
4800       lip->data_in_log = TRUE;
4801     }
4802     CloseLog (lip);
4803     Message (MSG_ERROR, "For one or more columns, two or more rows in the table apply to the same object.  Cannot continue.");
4804     dup_dest_errs = ValNodeFreeData (dup_dest_errs);
4805     err_list = ValNodeFreeData (err_list);
4806     FreeLog (lip);
4807     obj_table = FreeObjectTableForTabTable (obj_table);
4808     DeleteMarkedObjects (SeqMgrGetEntityIDForSeqEntry (sep), 0, NULL);
4809     return FALSE;
4810   }
4811 
4812   ValNodeLink (&err_list, CheckObjTableForExistingText (sep, table, columns, obj_table));
4813 
4814   msg_len = StringLen (msg_end) + 1;
4815   /* cycle through errors twice - first time, just print the ones with choice 1 (and sum lengths) */
4816   for (vnp = err_list; vnp != NULL; vnp = vnp->next) {
4817     if (vnp->choice == 1) {
4818       fprintf (lip->fp, "%s\n", vnp->data.ptrvalue);
4819       lip->data_in_log = TRUE;
4820       msg_len += StringLen (vnp->data.ptrvalue) + 2;
4821     }
4822   }
4823   /* then cycle again, printing 0s */
4824   for (vnp = err_list; vnp != NULL; vnp = vnp->next) {
4825     if (vnp->choice == 0) {
4826       fprintf (lip->fp, "%s\n", vnp->data.ptrvalue);
4827       lip->data_in_log = TRUE;
4828     }
4829   }
4830 
4831   /* now produce error message */
4832   if (lip->data_in_log) {
4833     msg = (CharPtr) MemNew (sizeof (Char) * msg_len);
4834     for (vnp = err_list; vnp != NULL; vnp = vnp->next) {
4835       if (vnp->choice == 1) {
4836         StringCat (msg, vnp->data.ptrvalue);
4837         StringCat (msg, "\n");
4838       }
4839     }
4840     StringCat (msg, msg_end);
4841   }
4842   
4843   err_list = ValNodeFreeData (err_list);
4844 
4845   CloseLog (lip);
4846   if (lip->data_in_log) {
4847     if (ANS_CANCEL == Message (MSG_OKC, msg)) {
4848       msg = MemFree (msg);
4849       FreeLog (lip);
4850       DeleteMarkedObjects (SeqMgrGetEntityIDForSeqEntry (sep), 0, NULL);
4851       return FALSE;
4852     }
4853   }
4854   msg = MemFree (msg);
4855   FreeLog (lip);
4856 
4857   err_list =  ApplyTableValuesToObjectTable (sep, table, columns, obj_table);
4858 
4859   lip = OpenLog ("Table Problems");
4860   for (vnp = err_list; vnp != NULL; vnp = vnp->next) {
4861     fprintf (lip->fp, "%s\n", vnp->data.ptrvalue);
4862     lip->data_in_log = TRUE;
4863   }
4864   err_list = ValNodeFreeData (err_list);
4865   CloseLog (lip);
4866   FreeLog (lip);
4867   obj_table = FreeObjectTableForTabTable (obj_table);
4868   DeleteMarkedObjects (SeqMgrGetEntityIDForSeqEntry (sep), 0, NULL);
4869   return TRUE;
4870 }
4871 
4872 
4873 static void DoAcceptQuals (ButtoN b)
4874 {
4875   QualLoadFormPtr form_data;
4876   ValNodePtr      columns = NULL;
4877   Int4            i;
4878   TabColumnConfigPtr t;
4879   SeqEntryPtr     sep;
4880 
4881   form_data = (QualLoadFormPtr) GetObjectExtra (b);
4882   if (form_data == NULL) return;
4883 
4884   if (GetStatus (form_data->remove_quotes)) {
4885     RemoveQuotesFromTabTable (form_data->table);
4886   }
4887 
4888   if (form_data->list_dlg == NULL) {
4889     for (i = 0; i < form_data->num_columns; i++) {
4890       t = DialogToPointer (form_data->column_list[i]);
4891       ValNodeAddPointer (&columns, 0, t);
4892     }
4893   } else {
4894     columns = DialogToPointer (form_data->list_dlg);
4895   }
4896 
4897   sep = GetTopSeqEntryForEntityID (form_data->input_entityID);
4898   if (ApplyTableValues (sep, form_data->table, columns)) {
4899     ObjMgrSetDirtyFlag (form_data->input_entityID, TRUE);
4900     ObjMgrSendMsg (OM_MSG_UPDATE, form_data->input_entityID, 0, 0);
4901     if (GetStatus (form_data->leave_dlg_up)) {
4902     } else {
4903       Remove (form_data->form);
4904     }
4905     Update();
4906   }
4907   columns = TabColumnConfigListFree (columns);
4908 
4909 }
4910 
4911 
4912 static void AutoMatchQuals (ButtoN b)
4913 {
4914   QualLoadFormPtr form_data;
4915   ValNodePtr      val, vnp;
4916   ValNodePtr      columns = NULL;
4917   Int4            i;
4918   TabColumnConfigPtr t;
4919 
4920   form_data = (QualLoadFormPtr) GetObjectExtra (b);
4921   if (form_data == NULL) return;
4922 
4923   if (form_data->list_dlg == NULL) {
4924     for (i = 0; i < form_data->num_columns; i++) {
4925       t = DialogToPointer (form_data->column_list[i]);
4926       ValNodeAddPointer (&columns, 0, t);
4927     }
4928   } else {
4929     columns = DialogToPointer (form_data->list_dlg);
4930   }
4931 
4932   for (val = form_data->table->data.ptrvalue, vnp = columns;
4933        val != NULL;
4934        val = val->next, vnp = vnp->next) {
4935     if (vnp == NULL) {
4936       vnp = ValNodeNew (columns);
4937     }
4938     t = vnp->data.ptrvalue;
4939     if (t == NULL) {
4940       t = TabColumnConfigNew ();
4941       vnp->data.ptrvalue = t;
4942     }
4943     if (t->match_type == NULL && t->field == NULL) {
4944       t->field = FieldTypeFromString (val->data.ptrvalue);
4945       if (t->field == NULL) {
4946         t = TabColumnConfigFree (t);
4947         vnp->data.ptrvalue = NULL;
4948       }
4949     }
4950   }
4951 
4952   if (form_data->list_dlg == NULL) {
4953     for (i = 0, vnp = columns; i < form_data->num_columns && vnp != NULL; i++, vnp = vnp->next) {
4954       PointerToDialog (form_data->column_list[i], vnp->data.ptrvalue);
4955     }
4956   } else {
4957     PointerToDialog (form_data->list_dlg, columns);
4958   }
4959   columns = TabColumnConfigListFree (columns);
4960 }
4961 
4962 
4963 static WindoW CreateTableReaderWindowWithTable (Uint2 entityID, ValNodePtr table);
4964 
4965 static void LoadNewTable (ButtoN b)
4966 {
4967   Char         path [PATH_MAX];
4968   FILE *fp;
4969   QualLoadFormPtr form_data, new_form_data;
4970   ValNodePtr      table, special_list, blank_list, columns = NULL, c_vnp;
4971   Int4            i;
4972   WindoW          w;
4973   TabColumnConfigPtr t;
4974 
4975   form_data = (QualLoadFormPtr) GetObjectExtra (b);
4976   if (form_data == NULL) return;
4977 
4978   path [0] = '\0';
4979   if (! GetInputFileName (path, sizeof (path), NULL, "TEXT")) return;
4980   
4981   fp = FileOpen (path, "r");
4982 
4983   table = ReadTabTableFromFile (fp);
4984   FileClose (fp);
4985   if (table == NULL) return;
4986   special_list = ScanTabTableForSpecialCharacters (table);
4987   if (special_list != NULL 
4988       && !FixSpecialCharactersForStringsInList (special_list, 
4989                                                 "The table contains special characters\nand cannot be used until they are replaced.",
4990                                                 FALSE)) {
4991     special_list = FreeContextList (special_list);
4992     return;
4993   }
4994   special_list = FreeContextList (special_list);
4995   if (form_data->list_dlg != NULL) {
4996     form_data->table = table;
4997     /* it's ok, can just repopulate dialogs */
4998     blank_list = CountTabTableBlanks (table);
4999     ChangeDataForTabColumnConfigListDialog (form_data->list_dlg, form_data->table->data.ptrvalue, blank_list);
5000     blank_list = ValNodeFree (blank_list);
5001   } else {
5002     /* build a new window */
5003     w = CreateTableReaderWindowWithTable (form_data->input_entityID, table);
5004     /* get old configurations */
5005     if (form_data->list_dlg == NULL) {
5006       for (i = 0; i < form_data->num_columns; i++) {
5007         t = DialogToPointer (form_data->column_list[i]);
5008         ValNodeAddPointer (&columns, 0, t);
5009       }
5010     } else {
5011       columns = DialogToPointer (form_data->list_dlg);
5012     }
5013 
5014     /* apply to new window */
5015     new_form_data = (QualLoadFormPtr) GetObjectExtra (w);
5016     if (new_form_data->list_dlg == NULL) {
5017       for (i = 0, c_vnp = columns; i < new_form_data->num_columns && c_vnp != NULL; i++, c_vnp = c_vnp->next) {
5018         PointerToDialog (new_form_data->column_list[i], c_vnp->data.ptrvalue);
5019       }
5020     } else {
5021       PointerToDialog (new_form_data->list_dlg, columns);
5022     }
5023     columns = ValNodeFree (columns);
5024     SetStatus (new_form_data->remove_quotes, GetStatus (form_data->remove_quotes));
5025     SetStatus (new_form_data->leave_dlg_up, GetStatus (form_data->leave_dlg_up));
5026 
5027     /* remove old window */
5028     Remove ((WindoW) form_data->form);
5029     
5030     RealizeWindow (w);
5031     Show (w);
5032     Update ();
5033   }
5034 
5035 
5036 }
5037 
5038 
5039 static WindoW CreateTableReaderWindowWithTable (Uint2 entityID, ValNodePtr table)
5040 {
5041   ValNodePtr   blank_list;
5042   ValNodePtr   col_vnp, blank_vnp;
5043   Int4         index;
5044   WindoW        w;
5045   GrouP         h, g, g2, c;
5046   QualLoadFormPtr form_data;
5047   CharPtr         title;
5048   Int4            col_for_list = 3;
5049   Char            buf[15];
5050   ButtoN          b;
5051   
5052   form_data = MemNew (sizeof (QualLoadFormData));
5053   if (form_data == NULL) return NULL;
5054   form_data->input_entityID = entityID;
5055   form_data->table = table;
5056   blank_list = CountTabTableBlanks (form_data->table);
5057   form_data->num_columns = ValNodeLen (blank_list);
5058   form_data->column_list = (DialoG PNTR) MemNew (sizeof (DialoG) * form_data->num_columns);
5059 
5060   /* now create a dialog to display values */
5061   w = FixedWindow (-50, -33, -10, -10, "Apply Qualifiers", StdCloseWindowProc);
5062   SetObjectExtra (w, form_data, CleanupQualLoadForm);
5063   form_data->form = (ForM) w;
5064 
5065   h = HiddenGroup (w, -1, 0, NULL);
5066   SetGroupSpacing (h, 10, 10);
5067 
5068   if (GetSequinAppParam ("SETTINGS", "tablecolumns", NULL, buf, sizeof (buf))) {
5069     col_for_list = atoi (buf);
5070   }
5071 
5072 
5073   if (form_data->num_columns >= col_for_list) {
5074     form_data->list_dlg = TabColumnConfigListDialog (h, form_data->table->data.ptrvalue, blank_list, ChangeTabColumnChoice, form_data);
5075     g = (GrouP) form_data->list_dlg;
5076   } else {
5077     g = HiddenGroup (h, 3, 0, NULL);
5078     col_vnp = form_data->table->data.ptrvalue;
5079     blank_vnp = blank_list;
5080     for (index = 0; index < form_data->num_columns; index++) {
5081       if (col_vnp == NULL || StringHasNoText (col_vnp->data.ptrvalue)) {
5082         title = StringSave ("First row value is blank");
5083       } else {
5084         title = StringSave (col_vnp->data.ptrvalue);
5085         if (StringLen (title) > 104) {
5086           StringCpy (title + 100, "...");
5087           *(title + 103) = 0;
5088         }
5089       }
5090       form_data->column_list[index] = TabColumnConfigDialog (g, title, blank_vnp->data.intvalue, ChangeTabColumnChoice, form_data);
5091       title = MemFree (title);
5092       if (col_vnp != NULL) {
5093         col_vnp = col_vnp->next;
5094       }
5095       blank_vnp = blank_vnp->next;
5096     }
5097   }
5098 
5099   g2 = HiddenGroup (h, 2, 0, NULL);
5100   b = PushButton (g2, "Automatch Qualifiers", AutoMatchQuals);
5101   SetObjectExtra (b, form_data, NULL);
5102   form_data->remove_quotes = CheckBox (g2, "Remove quotes around values", NULL);
5103   SetStatus (form_data->remove_quotes, TRUE);
5104 
5105   c = HiddenGroup (h, 4, 0, NULL);
5106   form_data->accept_button = DefaultButton (c, "Accept", DoAcceptQuals);
5107   SetObjectExtra (form_data->accept_button, form_data, NULL);
5108   Disable (form_data->accept_button);
5109   b = PushButton (c, "Load New Table", LoadNewTable);
5110   SetObjectExtra (b, form_data, NULL);
5111   PushButton (c, "Cancel", StdCancelButtonProc);
5112   form_data->leave_dlg_up = CheckBox (c, "Leave Dialog Up", NULL);
5113 
5114   AlignObjects (ALIGN_CENTER,
5115                 (HANDLE) g, 
5116                 (HANDLE) g2,
5117                 (HANDLE) c, NULL);
5118 
5119   blank_list = ValNodeFree (blank_list);
5120   return w;
5121 }
5122 
5123 
5124 static WindoW CreateTableReaderWindow (Uint2 entityID)
5125 {
5126   Char         path [PATH_MAX];
5127   FILE *fp;
5128 
5129   ValNodePtr   table;
5130   ValNodePtr      special_list;
5131 
5132   path [0] = '\0';
5133   if (! GetInputFileName (path, sizeof (path), NULL, "TEXT")) return NULL;
5134   
5135   fp = FileOpen (path, "r");
5136 
5137   table = ReadTabTableFromFile (fp);
5138   FileClose (fp);
5139   if (table == NULL) return NULL;
5140   special_list = ScanTabTableForSpecialCharacters (table);
5141   if (special_list != NULL 
5142       && !FixSpecialCharactersForStringsInList (special_list, 
5143                                                 "The table contains special characters\nand cannot be used until they are replaced.",
5144                                                 FALSE)) {
5145     special_list = FreeContextList (special_list);
5146     return NULL;
5147   }
5148   special_list = FreeContextList (special_list);
5149 
5150   return CreateTableReaderWindowWithTable (entityID, table);
5151 }
5152 
5153 
5154 extern void NewLoadFeatureQualifierTable (IteM i)
5155 {
5156   BaseFormPtr  bfp;
5157   WindoW        w;
5158   QualLoadFormPtr form_data;
5159   TabColumnConfigPtr t;
5160   ValNodePtr         column_list = NULL;
5161 
5162 #ifdef WIN_MAC
5163   bfp = currentFormDataPtr;
5164 #else
5165   bfp = GetObjectExtra (i);
5166 #endif
5167   if (bfp == NULL) return;
5168 
5169   w = CreateTableReaderWindow (bfp->input_entityID);
5170 
5171   if (w != NULL) {
5172     /* populate */
5173     form_data = (QualLoadFormPtr) GetObjectExtra (w);
5174     if (form_data != NULL) {
5175       t = TabColumnConfigNew ();
5176       t->match_type = MatchTypeNew ();
5177       t->match_type->match_location = eTableMatchNucID;
5178       if (form_data->list_dlg == NULL) {
5179         PointerToDialog (form_data->column_list[0], t);
5180       } else {
5181         ValNodeAddPointer (&column_list, 0, t);
5182         PointerToDialog (form_data->list_dlg, column_list);
5183         column_list = ValNodeFree (column_list);
5184       }
5185       t = TabColumnConfigFree (t);
5186     } 
5187 
5188     RealizeWindow (w);
5189     Show (w);
5190     Update ();
5191   }
5192 }
5193 
5194 
5195 extern void LoadTaxTableReader (IteM i)
5196 {
5197   BaseFormPtr  bfp;
5198   WindoW        w;
5199   QualLoadFormPtr form_data;
5200   TabColumnConfigPtr t;
5201   ValNodePtr         column_list = NULL, s;
5202 
5203 #ifdef WIN_MAC
5204   bfp = currentFormDataPtr;
5205 #else
5206   bfp = GetObjectExtra (i);
5207 #endif
5208   if (bfp == NULL) return;
5209 
5210   w = CreateTableReaderWindow (bfp->input_entityID);
5211 
5212   if (w != NULL) {
5213     /* populate */
5214     form_data = (QualLoadFormPtr) GetObjectExtra (w);
5215     if (form_data != NULL) {
5216       if (form_data->list_dlg == NULL) {
5217         if (form_data->num_columns > 1) {
5218           t = TabColumnConfigNew ();
5219           t->match_type = MatchTypeNew ();
5220           t->match_type->choice = eTableMatchBioSource;
5221           PointerToDialog (form_data->column_list[0], t);
5222           t->match_type = MatchTypeFree(t->match_type);
5223           t->field = ValNodeNew(NULL);
5224           t->field->choice = FieldType_source_qual;
5225           s = ValNodeNew (NULL);
5226           t->field->data.ptrvalue = s;
5227           s->choice = SourceQualChoice_textqual;
5228           s->data.intvalue = Source_qual_taxname;
5229           PointerToDialog (form_data->column_list[1], t);
5230           t = TabColumnConfigFree(t);
5231         }
5232       } else {
5233         t = TabColumnConfigNew ();
5234         t->match_type = MatchTypeNew ();
5235         t->match_type->choice = eTableMatchBioSource;
5236         PointerToDialog (form_data->column_list[0], t);
5237         ValNodeAddPointer (&column_list, 0, t);
5238         t = TabColumnConfigNew ();
5239         t->field = ValNodeNew(NULL);
5240         t->field->choice = FieldType_source_qual;
5241         s = ValNodeNew (NULL);
5242         t->field->data.ptrvalue = s;
5243         s->choice = SourceQualChoice_textqual;
5244         s->data.intvalue = Source_qual_taxname;
5245         ValNodeAddPointer (&column_list, 0, t);
5246         PointerToDialog (form_data->list_dlg, column_list);
5247         column_list = TabColumnConfigListFree (column_list);
5248       }
5249     } 
5250 
5251     RealizeWindow (w);
5252     Show (w);
5253     Update ();
5254   }
5255 }
5256 
5257 
5258 extern void NewLoadSourceQualifierTable (IteM i)
5259 {
5260   BaseFormPtr  bfp;
5261   WindoW        w;
5262   QualLoadFormPtr form_data;
5263   TabColumnConfigPtr t1, t2;
5264   ValNodePtr         column_list = NULL, vnp;
5265   Int4               n;
5266 
5267 #ifdef WIN_MAC
5268   bfp = currentFormDataPtr;
5269 #else
5270   bfp = GetObjectExtra (i);
5271 #endif
5272   if (bfp == NULL) return;
5273 
5274   w = CreateTableReaderWindow (bfp->input_entityID);
5275 
5276   if (w != NULL) {
5277     /* populate */
5278     form_data = (QualLoadFormPtr) GetObjectExtra (w);
5279     if (form_data != NULL) {
5280       t1 = TabColumnConfigNew ();
5281       t1->match_type = MatchTypeNew ();
5282       t1->match_type->match_location = eTableMatchNucID;
5283       t2 = TabColumnConfigNew ();
5284       vnp = ValNodeNew (NULL);
5285       vnp->choice = SourceQualChoice_textqual;
5286       vnp->data.intvalue = Source_qual_acronym;
5287       t2->field = ValNodeNew (NULL);
5288       t2->field->choice = FieldType_source_qual;
5289       t2->field->data.ptrvalue = vnp;
5290 
5291       if (form_data->list_dlg == NULL) {
5292         PointerToDialog (form_data->column_list[0], t1);
5293         PointerToDialog (form_data->column_list[1], t2);
5294       } else {
5295         ValNodeAddPointer (&column_list, 0, t1);
5296         for (n = 1; n < form_data->num_columns; n++) {
5297           ValNodeAddPointer (&column_list, 0, t2);
5298         }
5299         PointerToDialog (form_data->list_dlg, column_list);
5300         column_list = ValNodeFree (column_list);
5301       }
5302       t1 = TabColumnConfigFree (t1);
5303       t2 = TabColumnConfigFree (t2);
5304     } 
5305 
5306     RealizeWindow (w);
5307     Show (w);
5308     Update ();
5309   }
5310 }
5311 
5312 
5313 extern void ExternalSourceQualifierTableReader (IteM i)
5314 {
5315   Char         path [PATH_MAX];
5316   BaseFormPtr  bfp;
5317   ValNodePtr   table, columns = NULL, header_row, val;
5318   TabColumnConfigPtr t;
5319   LogInfoPtr         lip;
5320   Boolean            any_valid = FALSE;
5321   MsgAnswer          ans = ANS_OK;
5322   SeqEntryPtr        sep;
5323   FILE *fp;
5324 
5325 #ifdef WIN_MAC
5326   bfp = currentFormDataPtr;
5327 #else
5328   bfp = GetObjectExtra (i);
5329 #endif
5330   if (bfp == NULL || bfp->input_entityID == 0) return;
5331 
5332   path [0] = '\0';
5333   if (! GetInputFileName (path, sizeof (path), NULL, "TEXT")) return;
5334   
5335   fp = FileOpen (path, "r");
5336   if (fp == NULL) {
5337     Message (MSG_ERROR, "Unable to read from %s", path);
5338     return;
5339   }
5340 
5341   table = ReadTabTableFromFile (fp);
5342   FileClose (fp);
5343   if (table == NULL) {
5344     Message (MSG_ERROR, "Unable to read table from %s", path);
5345     return;
5346   }
5347 
5348   RemoveQuotesFromTabTable (table);
5349 
5350   /* first column is sequence ID */
5351   t = TabColumnConfigNew ();
5352   t->match_type = MatchTypeNew ();
5353   t->match_type->match_location = eTableMatchNucID;
5354   ValNodeAddPointer (&columns, 0, t);
5355 
5356   lip = OpenLog ("Table Problems");
5357   fprintf (lip->fp, "The following header values could not be matched to valid qualifier names.  They will be ignored.\n");
5358 
5359   /* automatch qualifiers */
5360   header_row = table->data.ptrvalue;
5361   if (header_row == NULL) {
5362     Message (MSG_ERROR, "First row of table must contain headers!");
5363   } else {
5364     for (val = header_row->next;
5365          val != NULL;
5366          val = val->next) {
5367       t = TabColumnConfigNew ();
5368       t->field = FieldTypeFromString (val->data.ptrvalue);
5369       if (t->field == NULL) {
5370         t = TabColumnConfigFree (t);
5371         fprintf (lip->fp, "%s\n", val->data.ptrvalue);
5372         lip->data_in_log = TRUE;
5373       } else {
5374         any_valid = TRUE;
5375       }
5376       ValNodeAddPointer (&columns, 0, t);
5377     }
5378   }
5379 
5380   CloseLog (lip);
5381   if (lip->data_in_log) {
5382     ans = Message (MSG_OKC, "Some column headers were not recognized.  The values in this column will be ignored.  Continue anyway?");
5383   }
5384   lip = FreeLog (lip);
5385 
5386   if (ans == ANS_OK) {
5387     sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
5388     if (ApplyTableValues (sep, table->next, columns)) {
5389       ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
5390       ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
5391       Update();
5392     }
5393   }
5394   columns = TabColumnConfigListFree (columns);
5395   table = FreeTabTable (table);
5396 }
5397 
5398 
5399 typedef struct prefixformdata {
5400   FEATURE_FORM_BLOCK
5401 
5402   ModifierItemLocalPtr modList;
5403   PopuP PNTR           popup_list;
5404   ButtoN               add_org_name;
5405   ButtoN               use_labels;
5406 } PrefixFormData, PNTR PrefixFormPtr;
5407 
5408 static void CleanupPrefixForm (
5409   GraphiC g,
5410   VoidPtr data
5411 )
5412 
5413 {
5414   PrefixFormPtr  pfp;
5415   Int4           i;
5416 
5417   pfp = (PrefixFormPtr) data;
5418   if (pfp != NULL) {
5419     if (pfp->modList != NULL)
5420     {
5421       for (i=0; i < NumDefLineModifiers (); i++)
5422       {
5423         ValNodeFree (pfp->modList[i].values_seen);
5424       }
5425       MemFree (pfp->modList);
5426     }
5427     if (pfp->popup_list != NULL)
5428     {
5429       MemFree (pfp->popup_list);
5430     }
5431   }
5432   StdCleanupFormProc (g, data);
5433 }
5434 
5435 static Int4 GetDefLineModifierPopupIndex (
5436   Int4 popup_index, 
5437   ModifierItemLocalPtr modList
5438 )
5439 {
5440   Int4 index;
5441   Int4 want_index;
5442   
5443   want_index = 0;
5444   for (index = 0;
5445        index < NumDefLineModifiers () && want_index < popup_index;
5446        index++)
5447   {
5448     if (modList [index].any_present)
5449     {
5450       want_index ++;
5451     }
5452   }
5453   if (index >= NumDefLineModifiers () || index == 0
5454     || want_index < popup_index)
5455   {
5456     return -1;
5457   }
5458   return index - 1;
5459 }
5460 
5461 static void AddPrefixesToOneDefLine (
5462   PrefixFormPtr pfp,
5463   BioseqPtr bsp,
5464   SeqEntryPtr sep
5465 )
5466 {
5467   BioSourcePtr biop;
5468   SeqDescrPtr  sdp;
5469   ValNodePtr   strings;
5470   Int4         index;
5471   Int4         qual_index;
5472   Int4         popup_choice;
5473   CharPtr      new_defline;
5474   Char         taxName [196];
5475   Char         modifier_text [256];
5476   OrgRefPtr    orp;
5477   OrgNamePtr   onp;
5478   OrgModPtr    mod;
5479   SubSourcePtr ssp;
5480   CharPtr  org_desc;
5481   CharPtr  cp;
5482   SeqMgrDescContext  dcontext;
5483   Boolean      use_labels;
5484   Uint4        no_semicolon_len;
5485   Int4         prefix_len;
5486 
5487   if (bsp == NULL || pfp == NULL
5488     || pfp->popup_list == NULL
5489     || pfp->modList == NULL
5490     || (biop = GetBiopForBsp (bsp)) == NULL)
5491   {
5492     return;
5493   }
5494 
5495   if (biop->org == NULL) return;
5496   if (biop->org->taxname == NULL) return;
5497   StringNCpy (taxName, biop->org->taxname, sizeof (taxName) - 1);
5498   taxName [ sizeof (taxName) - 1] = 0;
5499 
5500   strings = NULL;
5501   CleanUpTaxName (taxName, TRUE);
5502   if (GetStatus (pfp->add_org_name))
5503   {
5504     ValNodeCopyStr( &strings, 0, taxName);
5505   }
5506 
5507   use_labels = GetStatus (pfp->use_labels);
5508 
5509   orp = biop->org;
5510   if (orp == NULL) return;
5511   onp = orp->orgname;
5512   if (onp == NULL) return;
5513   for (index = 0; index < NumDefLineModifiers (); index ++)
5514   {
5515     if (pfp->popup_list [ index] != NULL
5516       && (popup_choice = GetValue (pfp->popup_list [ index])) > 0)
5517     {
5518       qual_index = GetDefLineModifierPopupIndex (popup_choice, pfp->modList);
5519       if (qual_index < 0 || qual_index >= NumDefLineModifiers ()) continue;
5520       if (DefLineModifiers[qual_index].isOrgMod)
5521       {
5522         mod = onp->mod;
5523         while (mod != NULL
5524           && mod->subtype != DefLineModifiers[qual_index].subtype)
5525         {
5526           mod = mod->next;
5527         }
5528         if ( UseOrgModifier (mod, taxName, FALSE))
5529         {
5530           no_semicolon_len = StringCSpn (mod->subname, ";");
5531           if (mod->subtype == ORGMOD_nat_host)
5532           {
5533             sprintf (modifier_text, "from ");
5534             if (no_semicolon_len > sizeof (modifier_text) - 6) {
5535               prefix_len = sizeof (modifier_text) - 1;
5536               no_semicolon_len = sizeof (modifier_text) - 6;
5537             } else {
5538                     prefix_len = no_semicolon_len + 5;
5539             }
5540             StringNCpy (modifier_text + 5, mod->subname, no_semicolon_len);
5541             modifier_text[prefix_len] = 0;
5542           }
5543           else
5544           {
5545             AddModifierLabel (use_labels, TRUE, mod->subtype, modifier_text);
5546             if (modifier_text[0] != 0)
5547               StringCat (modifier_text, " ");
5548             if (no_semicolon_len > sizeof (modifier_text) - StringLen (modifier_text) - 1) {
5549               no_semicolon_len = sizeof (modifier_text) - StringLen (modifier_text) - 1;
5550                     prefix_len = sizeof (modifier_text) - 1;
5551             } else {
5552                     prefix_len = no_semicolon_len + StringLen (modifier_text);
5553             }
5554 
5555             StringNCat (modifier_text, mod->subname, no_semicolon_len);
5556             modifier_text[prefix_len] = 0;
5557           }
5558           ValNodeCopyStr( &strings, 0, modifier_text);
5559         }
5560       } else {
5561         ssp = biop->subtype;
5562         while (ssp != NULL
5563             && ssp->subtype != DefLineModifiers[qual_index].subtype)
5564         {
5565           ssp = ssp->next;
5566         }
5567         if (ssp != NULL)
5568         {
5569           no_semicolon_len = StringCSpn (ssp->name, ";");
5570           AddModifierLabel (use_labels, FALSE, ssp->subtype, modifier_text);
5571           if (ssp->subtype == SUBSRC_country)
5572           {
5573             sprintf (modifier_text, "from ");
5574             if (no_semicolon_len > sizeof (modifier_text) - 6) {
5575               no_semicolon_len = sizeof (modifier_text) - 6;
5576                           prefix_len = sizeof(modifier_text);
5577                         } else {
5578                           prefix_len = StringLen (modifier_text) + no_semicolon_len;
5579                         }
5580             StringNCpy (modifier_text + 5, ssp->name, no_semicolon_len);
5581             modifier_text[prefix_len] = 0;
5582             cp = StringChr (modifier_text, ':');
5583             if (cp != NULL) *cp = 0;
5584           }
5585           else if (ssp->name != NULL
5586             && (ssp->subtype != SUBSRC_plasmid_name
5587               || StringCmp (ssp->name, "unnamed") != 0))
5588           {
5589             if (modifier_text[0] != 0)
5590               StringCat (modifier_text, " ");
5591             if (no_semicolon_len > sizeof (modifier_text) - StringLen (modifier_text) - 1) {
5592               no_semicolon_len = sizeof (modifier_text) - StringLen (modifier_text) - 1;
5593                           prefix_len = sizeof (modifier_text);
5594                         } else {
5595                           prefix_len = StringLen (modifier_text) + no_semicolon_len;
5596                         }
5597  
5598             StringNCat (modifier_text, ssp->name, no_semicolon_len);
5599             modifier_text[prefix_len] = 0;
5600           }
5601           ValNodeCopyStr( &strings, 0, modifier_text);
5602         }
5603       }
5604     }
5605   }
5606   org_desc = MergeValNodeStrings (strings, FALSE);
5607   ValNodeFreeData (strings);
5608 
5609   sdp = SeqEntryGetSeqDescr (sep, Seq_descr_title, NULL);
5610   if (sdp == NULL) {
5611     sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_title, &dcontext);
5612     if (sdp == NULL) return;
5613     cp = (CharPtr) sdp->data.ptrvalue;
5614     if (cp == NULL) return;
5615     sdp = SeqDescrAdd (&(bsp->descr));
5616     if (sdp == NULL) return;
5617     sdp->choice = Seq_descr_title;
5618     sdp->data.ptrvalue = StringSave (cp);
5619   }
5620   if (sdp == NULL) return;
5621   if (StringHasNoText (sdp->data.ptrvalue)) return;
5622   new_defline = MemNew ((StringLen (org_desc)
5623                         + StringLen (sdp->data.ptrvalue) + 4) * sizeof (Char));
5624   if (new_defline == NULL) return;
5625   StringCpy (new_defline, org_desc);
5626   StringCat (new_defline, " ");
5627   StringCat (new_defline, sdp->data.ptrvalue);
5628   MemFree (sdp->data.ptrvalue);
5629   sdp->data.ptrvalue = new_defline;
5630   ObjMgrSetDirtyFlag (pfp->input_entityID, TRUE);
5631 }
5632 
5633 static void AddPrefixesToDefLines (PrefixFormPtr pfp, SeqEntryPtr sep)
5634 {
5635   BioseqSetPtr bssp;
5636   if (pfp == NULL || sep == NULL) return;
5637   if (IS_Bioseq_set (sep)) {
5638     bssp = (BioseqSetPtr) sep->data.ptrvalue;
5639     if (bssp != NULL) {
5640       for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
5641         AddPrefixesToDefLines (pfp, sep);
5642       }
5643       return;
5644     }
5645   }
5646   if (! IS_Bioseq (sep)) return;
5647   AddPrefixesToOneDefLine (pfp, sep->data.ptrvalue, sep);
5648 }
5649 
5650 static void DoPrefixDefLines (ButtoN b)
5651 {
5652   PrefixFormPtr pfp;
5653   SeqEntryPtr   sep;
5654 
5655   pfp = GetObjectExtra (b);
5656   if (pfp == NULL) return;
5657 
5658   Hide (pfp->form);
5659   WatchCursor ();
5660   Update ();
5661   sep = GetTopSeqEntryForEntityID (pfp->input_entityID);
5662   if (sep == NULL) return;
5663   AddPrefixesToDefLines (pfp, sep);
5664 
5665   ArrowCursor ();
5666   Update ();
5667   ObjMgrSetDirtyFlag (pfp->input_entityID, TRUE);
5668   ObjMgrSendMsg (OM_MSG_UPDATE, pfp->input_entityID, 0, 0);
5669 }
5670 
5671 extern void PrefixDefLines (IteM i)
5672 {
5673   BaseFormPtr  bfp;
5674   SeqEntryPtr  sep;
5675   ModifierItemLocalPtr modList;
5676   Int4         index;
5677   WindoW       w;
5678   GrouP        h, g, k;
5679   Int4         popup_index, item_index, listed_index;
5680   GrouP        c;
5681   ButtoN       b;
5682   PrefixFormPtr pfp;
5683   Char         label [256];
5684 
5685 #ifdef WIN_MAC
5686   bfp = currentFormDataPtr;
5687 #else
5688   bfp = GetObjectExtra (i);
5689 #endif
5690   if (bfp == NULL || bfp->input_entityID == 0) return;
5691 
5692   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
5693   if (sep == NULL) return;
5694 
5695   modList = MemNew (NumDefLineModifiers () * sizeof (ModifierItemLocalData));
5696   if (modList == NULL) return;
5697   CountModifiers (modList, sep);
5698 
5699   pfp = MemNew (sizeof (PrefixFormData));
5700   if (pfp == NULL) return;
5701   pfp->input_entityID = bfp->input_entityID;
5702   pfp->modList = modList;
5703   pfp->popup_list = MemNew (sizeof (PopuP) * NumDefLineModifiers ());
5704   if (pfp->popup_list == NULL) return;
5705 
5706   w = FixedWindow (-50, -33, -10, -10, "Definition Line Prefixes",
5707                    StdCloseWindowProc);
5708   SetObjectExtra (w, pfp, CleanupPrefixForm);
5709   pfp->form = (ForM) w;
5710 
5711   h = HiddenGroup (w, -1, 0, NULL);
5712   SetGroupSpacing (h, 10, 10);
5713   g = HiddenGroup (h, 4, 0, NULL);
5714   for (index = 0; index < NumDefLineModifiers (); index++)
5715   {
5716     pfp->popup_list [index] = NULL;
5717   }
5718   popup_index = 0;
5719   for (index = 0; index < NumDefLineModifiers (); index++)
5720   {
5721     if (modList [ index].any_present)
5722     {
5723       k = HiddenGroup (g, 2, 0, NULL);
5724       sprintf (label, "%d", popup_index + 1);
5725       StaticPrompt (k, label, 0, popupMenuHeight, programFont, 'l');
5726       pfp->popup_list[popup_index] = PopupList (k, TRUE, NULL);
5727       listed_index = 0;
5728       for (item_index = 0; item_index < NumDefLineModifiers (); item_index ++)
5729       {
5730         if (modList [item_index].any_present)
5731         {
5732           PopupItem (pfp->popup_list[popup_index], 
5733                    DefLineModifiers[item_index].name);
5734           listed_index ++;
5735         }
5736       }
5737       PopupItem (pfp->popup_list[popup_index], "Ignore");
5738       listed_index++;
5739       SetValue (pfp->popup_list[popup_index], listed_index);
5740       popup_index ++;
5741     }
5742   }
5743 
5744   pfp->add_org_name = CheckBox (h, "Prefix with taxonomy name", NULL);
5745   SetStatus (pfp->add_org_name, TRUE);
5746   pfp->use_labels = CheckBox (h, "Use modifier labels", NULL);
5747   SetStatus (pfp->use_labels, TRUE);
5748 
5749   c = HiddenGroup (h, 4, 0, NULL);
5750   b = DefaultButton (c, "Accept", DoPrefixDefLines);
5751   SetObjectExtra (b, pfp, NULL);
5752   PushButton (c, "Cancel", StdCancelButtonProc);
5753 
5754   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) pfp->add_org_name,
5755                 (HANDLE) pfp->use_labels,
5756                 (HANDLE) c, NULL);
5757   RealizeWindow (w);
5758   Show (w);
5759   Update ();
5760 
5761 }
5762 
5763 #ifndef WIN16
5764 CharPtr objPrtMemStr = "PrintTemplateSet ::= {\n" \
5765 "{ name \"StdSeqDesc\" ,\n" \
5766 "format { asn1 \"Seqdesc\" , form block {\n" \
5767 "components {\n" \
5768 "{ asn1 \"Seqdesc.mol-type\" , label \"Molecule type\" , prefix \"\\n\" , form enum { } } ,\n" \
5769 "{ asn1 \"Seqdesc.modif\" , label \"Modifiers\" , prefix \"\\n\" , form block {\n" \
5770 "separator \", \" ,\n" \
5771 "components {\n" \
5772 "{ asn1 \"Seqdesc.modif.E\" , form enum { } } } } } ,\n" \
5773 "{ asn1 \"Seqdesc.method\" , label \"Method\" , prefix \"\\n\" , form enum { } } ,\n" \
5774 "{ asn1 \"Seqdesc.name\" , label \"Name\" , prefix \"\\n\" , form text { } } ,\n" \
5775 "{ asn1 \"Seqdesc.title\" , label \"Title\" , prefix \"\\n\" , form text { } } ,\n" \
5776 "{ asn1 \"Seqdesc.org\" , label \"Organism\" , prefix \"\\n\" , form use-template \"StdOrgRef\" } ,\n" \
5777 "{ asn1 \"Seqdesc.comment\" , label \"Comment\" , prefix \"\\n\" , form text { } } ,\n" \
5778 "{ asn1 \"Seqdesc.num\" , label \"Numbering\" , prefix \"\\n\" , form use-template \"StdNumbering\" } ,\n" \
5779 "{ asn1 \"Seqdesc.maploc\" , label \"Map location\" , prefix \"\\n\" , form use-template \"StdDbtag\" } ,\n" \
5780 "{ asn1 \"Seqdesc.pir\" , label \"PIR block\" , prefix \"\\n\" , form null NULL } ,\n" \
5781 "{ asn1 \"Seqdesc.genbank\" , label \"GenBank block\" , prefix \"\\n\" , form use-template \"StdGBBlock\" } ,\n" \
5782 "{ asn1 \"Seqdesc.pub\" , label \"Citation\" , prefix \"\\n\" , form use-template \"StdPubdesc\" } ,\n" \
5783 "{ asn1 \"Seqdesc.region\" , label \"Region\" , prefix \"\\n\" , form text { } } ,\n" \
5784 "{ asn1 \"Seqdesc.user\" , label \"User Type\" , prefix \"\\n\" , form use-template \"StdUserObj\" } ,\n" \
5785 "{ asn1 \"Seqdesc.sp\" , label \"SWISS-PROT block\" , prefix \"\\n\" , form null NULL } ,\n" \
5786 "{ asn1 \"Seqdesc.dbxref\" , label \"Cross reference\" , prefix \"\\n\" , form use-template \"StdDbtag\"  } ,\n" \
5787 "{ asn1 \"Seqdesc.embl\" , label \"EMBL block\" , prefix \"\\n\" , form null NULL } ,\n" \
5788 "{ asn1 \"Seqdesc.create-date\" , label \"Create date\" , prefix \"\\n\" , form user { printfunc \"StdDatePrint\" } } ,\n" \
5789 "{ asn1 \"Seqdesc.update-date\" , label \"Update date\" , prefix \"\\n\" , form user { printfunc \"StdDatePrint\" } } ,\n" \
5790 "{ asn1 \"Seqdesc.prf\" , label \"PRF block\" , prefix \"\\n\" , form null NULL } ,\n" \
5791 "{ asn1 \"Seqdesc.pdb\" , label \"PDB block\" , prefix \"\\n\" , form null NULL } ,\n" \
5792 "{ asn1 \"Seqdesc.het\" , label \"Heterogen\" , prefix \"\\n\" , form text { } } ,\n" \
5793 "{ asn1 \"Seqdesc.source\" , label \"Biological Source\" , prefix \"\\n\" , form use-template \"StdBioSource\" } ,\n" \
5794 "{ asn1 \"Seqdesc.molinfo\" , label \"Molecule Information\" , prefix \"\\n\" , form block {\n" \
5795 "separator \", \" ,\n" \
5796 "components {\n" \
5797 "{ asn1 \"MolInfo.biomol\" , form enum { } } ,\n" \
5798 "{ asn1 \"MolInfo.tech\" , form enum { } } ,\n" \
5799 "{ asn1 \"MolInfo.completeness\" , form enum { } } } } } } } } } ,\n" \
5800 "{ name \"StdSeqFeatLocation\" ,\n" \
5801 "format { asn1 \"Seq-feat.location\" , label \"Location\" , prefix \"\\t\" , form user { printfunc \"StdSeqLocPrint\" } } } ,\n" \
5802 "{ name \"StdSeqFeatProduct\" ,\n" \
5803 "format { asn1 \"Seq-feat.product\" , label \"Product\" , prefix \"\\t\" , form user { printfunc \"StdSeqLocPrint\" } } } ,\n" \
5804 "{ name \"EntrySeqFeatData\" ,\n" \
5805 "labelfrom \"Seq-feat.data\" ,\n" \
5806 "format { asn1 \"Seq-feat.data\" , prefix \"\\t\" , form use-template \"StdSeqFeatData\" } } ,\n" \
5807 "{ name \"StdSeqFeat\" ,\n" \
5808 "labelfrom \"Seq-feat.data\" ,\n" \
5809 "format { asn1 \"Seq-feat\" , prefix \"\\n\" , suffix \"\\n\" , form block {\n" \
5810 "separator \"\\n\" ,\n" \
5811 "components {\n" \
5812 "{ asn1 \"Seq-feat.data\" , form use-template \"StdSeqFeatData\" } ,\n" \
5813 "{ asn1 \"Seq-feat\" , form use-template \"StdSeqFeatCommon\" } ,\n" \
5814 "{ asn1 \"Seq-feat.product\" , label \"Product\" , prefix \" \" , form user { printfunc \"StdSeqLocPrint\" } } ,\n" \
5815 "{ asn1 \"Seq-feat.location\" , label \"Location\" , prefix \" \" , form user { printfunc \"StdSeqLocPrint\" } } ,\n" \
5816 "{ asn1 \"Seq-feat.cit\" , label \"Citations\" , prefix \"\\n\" , form block {\n" \
5817 "separator \"\\n\" ,\n" \
5818 "components {\n" \
5819 "{ asn1 \"Seq-feat.cit.pub.E\" , form use-template \"StdPub\" } } } } ,\n" \
5820 "{ asn1 \"Seq-feat.xref\" , label \"Cross-reference\" , prefix \"\\n\" , form block {\n" \
5821 "separator \"\\n\" ,\n" \
5822 "components {\n" \
5823 "{ asn1 \"Seq-feat.xref.E\" , form use-template \"StdSeqFeatXref\" } } } } } } } } ,\n" \
5824 "{ name \"StdSeqFeatData\" ,\n" \
5825 "format { asn1 \"SeqFeatData\" , form block {\n" \
5826 "components {\n" \
5827 "{ asn1 \"SeqFeatData.gene\" , label \"Gene\" , form use-template \"StdGeneRef\" } ,\n" \
5828 "{ asn1 \"SeqFeatData.org\" , label \"Organism\" , form use-template \"StdOrgRef\" } ,\n" \
5829 "{ asn1 \"SeqFeatData.cdregion\" , label \"Coding Region\" , form use-template \"StdCdRegion\" } ,\n" \
5830 "{ asn1 \"SeqFeatData.prot\" , label \"Protein\" , form use-template \"StdProtRef\" } ,\n" \
5831 "{ asn1 \"SeqFeatData.rna\" , label \"RNA\" , form use-template \"StdRNARef\" } ,\n" \
5832 "{ asn1 \"SeqFeatData.pub\" , label \"Citation\" , form use-template \"StdPubdesc\" } ,\n" \
5833 "{ asn1 \"SeqFeatData.seq\" , label \"Sequence\" , form user { printfunc \"StdSeqLocPrint\" } } ,\n" \
5834 "{ asn1 \"SeqFeatData.imp.key\" , label \"Import\" , form use-template \"StdImpFeat\" } ,\n" \
5835 "{ asn1 \"SeqFeatData.region\" , label \"Region\" , form text { } } ,\n" \
5836 "{ asn1 \"SeqFeatData.comment\" , label \"Comment\" , form null NULL } ,\n" \
5837 "{ asn1 \"SeqFeatData.bond\" , label \"Bond\" , form enum { } } ,\n" \
5838 "{ asn1 \"SeqFeatData.site\" , label \"Site\" , form enum { } } ,\n" \
5839 "{ asn1 \"SeqFeatData.rsite\" , label \"Rest. Site\" , form use-template \"StdRsiteRef\" } ,\n" \
5840 "{ asn1 \"SeqFeatData.user\" , label \"User Type\" , form use-template \"StdUserObj\" } ,\n" \
5841 "{ asn1 \"SeqFeatData.txinit\" , label \"TxInit\" , form use-template \"StdTxInit\" } ,\n" \
5842 "{ asn1 \"SeqFeatData.num\" , label \"Numbering\" , form use-template \"StdNumbering\" } ,\n" \
5843 "{ asn1 \"SeqFeatData.psec-str\" , label \"Sec. Struct\" , form enum { } } ,\n" \
5844 "{ asn1 \"SeqFeatData.non-std-residue\" , label \"NonStd Residue\" , form text { } } ,\n" \
5845 "{ asn1 \"SeqFeatData.het\" , label \"Heterogen\" , form text { } } ,\n" \
5846 "{ asn1 \"SeqFeatData.biosrc\" , label \"Biological Source\" , prefix \"\\n\" , form use-template \"StdBioSource\" } } } } } ,\n" \
5847 "{ name \"StdGeneRef\" ,\n" \
5848 "format { asn1 \"Gene-ref\" , form block {\n" \
5849 "separator \"\\n\" ,\n" \
5850 "components {\n" \
5851 "{ asn1 \"Gene-ref\" , form block {\n" \
5852 "components {\n" \
5853 "{ asn1 \"Gene-ref.locus\" , form text { } } ,\n" \
5854 "{ asn1 \"Gene-ref.allele\" , prefix \" \" , form text { } } } } } ,\n" \
5855 "{ asn1 \"Gene-ref.desc\" , prefix \"[\" , suffix \"]\" , form text { } } ,\n" \
5856 "{ asn1 \"Gene-ref.pseudo\" , form boolean {\n" \
5857 "true \"This is a pseudogene.\" } } ,\n" \
5858 "{ asn1 \"Gene-ref.syn\" , label \"Synonyms\" , prefix \" (\" , suffix \")\" , form block {\n" \
5859 "separator \", \" ,\n" \
5860 "components {\n" \
5861 "{ asn1 \"Gene-ref.syn.E\" , form text { } } } } } ,\n" \
5862 "{ asn1 \"Gene-ref.maploc\" , label \"Map Location\" , prefix \" \" , form text { } } ,\n" \
5863 "{ asn1 \"Gene-ref.db\" , label \"Cross Reference\" , prefix \" \" , form block {\n" \
5864 "separator \", \" ,\n" \
5865 "components {\n" \
5866 "{ asn1 \"Gene-ref.db.E\" , prefix \"(\" , suffix \")\" , form use-template \"StdDbtag\" } } } } } } } } ,\n" \
5867 "{ name \"StdUserObj\" ,\n" \
5868 "format { asn1 \"User-object\" , label \"User-object\" , prefix \"\\n\" , form block {\n" \
5869 "separator \": \" ,\n" \
5870 "components {\n" \
5871 "{ asn1 \"User-object.class\" , form text { } } ,\n" \
5872 "{ asn1 \"User-object.type\" , form use-template \"StdObjectId\" } } } } } ,\n" \
5873 "{ name \"StdPubOnFeat\" ,\n" \
5874 "format { asn1 \"Pub\" , label \"Citation\" , prefix \"\\n\" , form block {\n" \
5875 "separator \"\\n\" ,\n" \
5876 "components {\n" \
5877 "{ asn1 \"Pub\" , form use-template \"StdPub\" } } } } } ,\n" \
5878 "{ name \"StdPub\" ,\n" \
5879 "format { asn1 \"Pub\" , form block {\n" \
5880 "separator \"\\n\" ,\n" \
5881 "components {\n" \
5882 "{ asn1 \"Pub.gen\" , form use-template \"StdCitGen\" } ,\n" \
5883 "{ asn1 \"Pub.sub\" , form use-template \"StdCitSub\" } ,\n" \
5884 "{ asn1 \"Pub.medline\" , form use-template \"StdMedlineEntry\" } ,\n" \
5885 "{ asn1 \"Pub.muid\" , label \"MEDLINE uid: \" , form text { } } ,\n" \
5886 "{ asn1 \"Pub.pmid\" , label \"PubMed id: \" , form text { } } ,\n" \
5887 "{ asn1 \"Pub.article\" , form use-template \"StdCitArt\" } ,\n" \
5888 "{ asn1 \"Pub.journal\" , form use-template \"StdCitJour\" } ,\n" \
5889 "{ asn1 \"Pub.book\" , form use-template \"StdCitBook\" } ,\n" \
5890 "{ asn1 \"Pub.proc\" , form use-template \"StdCitProc\" } ,\n" \
5891 "{ asn1 \"Pub.patent\" , form use-template \"StdCitPat\" } ,\n" \
5892 "{ asn1 \"Pub.pat-id\" , form use-template \"StdIdPat\" } ,\n" \
5893 "{ asn1 \"Pub.man\" , form use-template \"StdCitLet\" } ,\n" \
5894 "{ asn1 \"Pub.equiv\" , form use-template \"StdPubEquiv\" } } } } } ,\n" \
5895 "{ name \"StdCitGen\" ,\n" \
5896 "format { asn1 \"Cit-gen\" , form block {\n" \
5897 "separator \"\\n\" ,\n" \
5898 "components {\n" \
5899 "{ asn1 \"Cit-gen.serial-number\" , prefix \"[\" , suffix \"]\" , form text { } } ,\n" \
5900 "{ asn1 \"Cit-gen.authors\" , form use-template \"StdAuthList\" } ,\n" \
5901 "{ asn1 \"Cit-gen.date\" , prefix \"(\" , suffix \")\" , form user { printfunc \"StdDatePrint\" } } ,\n" \
5902 "{ asn1 \"Cit-gen.title\" , form text { } } ,\n" \
5903 "{ asn1 \"Cit-gen.cit\" , form text { } } ,\n" \
5904 "{ asn1 \"Cit-gen\" , form block {\n" \
5905 "separator \" \" ,\n" \
5906 "components {\n" \
5907 "{ asn1 \"Cit-gen.journal\" , suffix \":\" , form use-template \"StdTitle\" } ,\n" \
5908 "{ asn1 \"Cit-gen.issue\" , suffix \";\" , form text { } } ,\n" \
5909 "{ asn1 \"Cit-gen.pages\" , form text { } } } } } } } } } ,\n" \
5910 "{ name \"StdCitSub\" ,\n" \
5911 "format { asn1 \"Cit-sub\" , prefix \"Data Submission \" , form block {\n" \
5912 "components {\n" \
5913 "{ asn1 \"Cit-sub.medium\" , prefix \"on \" , suffix \" \" , form enum { } } ,\n" \
5914 "{ asn1 \"Cit-sub.imp.date\" , prefix \"(\" , suffix \")\" , form user { printfunc \"StdDatePrint\" } } ,\n" \
5915 "{ asn1 \"Cit-sub.authors\" , prefix \"\\n\" , form use-template \"StdAuthList\" } } } } } ,\n" \
5916 "{ name \"StdMedlineEntry\" ,\n" \
5917 "format { asn1 \"Medline-entry\" , form block {\n" \
5918 "separator \"\\n\" ,\n" \
5919 "components {\n" \
5920 "{ asn1 \"Medline-entry\" , form block {\n" \
5921 "separator \"   \" ,\n" \
5922 "components {\n" \
5923 "{ asn1 \"Medline-entry.uid\" , label \"uid\" , prefix \": \" , form text { } } ,\n" \
5924 "{ asn1 \"Medline-entry.em\" , label \"entry month\" , prefix \": \" , form user { printfunc \"StdDatePrint\" } } } } } ,\n" \
5925 "{ asn1 \"Medline-entry.cit\" , form use-template \"StdCitArt\" } ,\n" \
5926 "{ asn1 \"Medline-entry.abstract\" , label \"abstract\" , prefix \": \" , form text { } } ,\n" \
5927 "{ asn1 \"Medline-entry.mesh\" , label \"Mesh Terms\" , prefix \"\\n\" , form block {\n" \
5928 "separator \"\\n\" ,\n" \
5929 "components {\n" \
5930 "{ asn1 \"Medline-entry.mesh.E\" , form block {\n" \
5931 "components {\n" \
5932 "{ asn1 \"Medline-mesh.term\" , form text { } } ,\n" \
5933 "{ asn1 \"Medline-mesh.mp\" , form boolean {\n" \
5934 "true \" (Main Point)\" } } ,\n" \
5935 "{ asn1 \"Medline-mesh.qual\" , form block {\n" \
5936 "separator \"\\n\" ,\n" \
5937 "components {\n" \
5938 "{ asn1 \"Medline-mesh.qual.E\" , form block {\n" \
5939 "components {\n" \
5940 "{ asn1 \"Medline-qual.subh\" , form text { } } ,\n" \
5941 "{ asn1 \"Medline-qual.mp\" , form boolean {\n" \
5942 "true \" (Main Point)\" } } } } } } } } } } } } } } ,\n" \
5943 "{ asn1 \"Medline-entry.substance\" , label \"Substance\" , prefix \"\\n\" , form block {\n" \
5944 "separator \"\\n\" ,\n" \
5945 "components {\n" \
5946 "{ asn1 \"Medline-entry.substance.E\" , form block {\n" \
5947 "components {\n" \
5948 "{ asn1 \"Medline-rn.name\" , form text { } } ,\n" \
5949 "{ asn1 \"Medline-rn.type\" , form enum {\n" \
5950 "values {\n" \
5951 "\"\" ,\n" \
5952 "\" CAS: \" ,\n" \
5953 "\"EC \" } } } ,\n" \
5954 "{ asn1 \"Medline-rn.cit\" , form text { } } } } } } } } ,\n" \
5955 "{ asn1 \"Medline-entry.xref\" , label \"Cross Reference\" , prefix \"\\n\" , form block {\n" \
5956 "separator \"\\n\" ,\n" \
5957 "components {\n" \
5958 "{ asn1 \"Medline-entry.xref.E\" , form block {\n" \
5959 "separator \": \" ,\n" \
5960 "components {\n" \
5961 "{ asn1 \"Medline-si.type\" , form enum { } } ,\n" \
5962 "{ asn1 \"Medline-si.cit\" , form text { } } } } } } } } ,\n" \
5963 "{ asn1 \"Medline-entry.gene\" , label \"Possible Gene Symbols\" , prefix \": \" , form block {\n" \
5964 "separator \", \" ,\n" \
5965 "components {\n" \
5966 "{ asn1 \"Medline-entry.gene.E\" , form text { } } } } } ,\n" \
5967 "{ asn1 \"Medline-entry.idnum\" , label \"Support\" , prefix \": \" , form block {\n" \
5968 "separator \", \" ,\n" \
5969 "components {\n" \
5970 "{ asn1 \"Medline-entry.idnum.E\" , form text { } } } } } } } } } ,\n" \
5971 "{ name \"StdCitArt\" ,\n" \
5972 "format { asn1 \"Cit-art\" , form block {\n" \
5973 "separator \"\\n\" ,\n" \
5974 "components {\n" \
5975 "{ asn1 \"Cit-art.title\" , form use-template \"StdTitle\" } ,\n" \
5976 "{ asn1 \"Cit-art.authors\" , form use-template \"StdAuthList\" } ,\n" \
5977 "{ asn1 \"Cit-art.from.journal\" , form use-template \"StdCitJour\" } ,\n" \
5978 "{ asn1 \"Cit-art.from.book\" , prefix \"(in) \" , form use-template \"StdCitBook\" } ,\n" \
5979 "{ asn1 \"Cit-art.from.proc\" , prefix \"(in) \" , form use-template \"StdCitProc\" } } } } } ,\n" \
5980 "{ name \"StdCitJour\" ,\n" \
5981 "format { asn1 \"Cit-jour\" , form block {\n" \
5982 "separator \" \" ,\n" \
5983 "components {\n" \
5984 "{ asn1 \"Cit-jour.title\" , form use-template \"StdTitle\" } ,\n" \
5985 "{ asn1 \"Cit-jour.imp\" , form use-template \"StdImprint\" } } } } } ,\n" \
5986 "{ name \"StdCitBook\" ,\n" \
5987 "format { asn1 \"Cit-book\" , form block {\n" \
5988 "separator \"\\n\" ,\n" \
5989 "components {\n" \
5990 "{ asn1 \"Cit-book.title\" , form use-template \"StdTitle\" } ,\n" \
5991 "{ asn1 \"Cit-book.coll\" , prefix \"Collection: \" , form use-template \"StdTitle\" } ,\n" \
5992 "{ asn1 \"Cit-book.authors\" , form use-template \"StdAuthList\" } ,\n" \
5993 "{ asn1 \"Cit-book.imp\" , form use-template \"StdImprint\" } } } } } ,\n" \
5994 "{ name \"StdCitProc\" ,\n" \
5995 "format { asn1 \"Cit-proc\" , form block {\n" \
5996 "separator \"\\n\" ,\n" \
5997 "components {\n" \
5998 "{ asn1 \"Cit-proc.book\" , form use-template \"StdCitBook\" } ,\n" \
5999 "{ asn1 \"Cit-proc.meet\" , label \"Meeting \" , form block {\n" \
6000 "separator \", \" ,\n" \
6001 "components {\n" \
6002 "{ asn1 \"Meeting.number\" , form text { } } ,\n" \
6003 "{ asn1 \"Meeting.date\" , form user { printfunc \"StdDatePrint\" } } ,\n" \
6004 "{ asn1 \"Meeting.place\" , form use-template \"StdAffil\" } } } } } } } } ,\n" \
6005 "{ name \"StdCitPat\" ,\n" \
6006 "format { asn1 \"Cit-pat\" , form block {\n" \
6007 "separator \"\\n\" ,\n" \
6008 "components {\n" \
6009 "{ asn1 \"Cit-pat.title\" , form text { } } ,\n" \
6010 "{ asn1 \"Cit-pat.authors\" , form use-template \"StdAuthList\" } ,\n" \
6011 "{ asn1 \"Cit-pat\" , form block {\n" \
6012 "components {\n" \
6013 "{ asn1 \"Cit-pat.country\" , suffix \" \" , form text { } } ,\n" \
6014 "{ asn1 \"Cit-pat.doc-type\" , form text { } } ,\n" \
6015 "{ asn1 \"Cit-pat.number\" , form text { } } ,\n" \
6016 "{ asn1 \"Cit-pat.date-issue\" , prefix \" (\" , suffix \")\" , form user { printfunc \"StdDatePrint\" } } ,\n" \
6017 "{ asn1 \"Cit-pat.app-number\" , prefix \" Appl: \" , form text { } } ,\n" \
6018 "{ asn1 \"Cit-pat.app-date\" , prefix \" (\" , suffix \")\" , form user { printfunc \"StdDatePrint\" } } } } } } } } } ,\n" \
6019 "{ name \"StdIdPat\" ,\n" \
6020 "format { asn1 \"Id-pat\" , form block {\n" \
6021 "components {\n" \
6022 "{ asn1 \"Id-pat.country\" , suffix \" \" , form text { } } ,\n" \
6023 "{ asn1 \"Id-pat.id.number\" , form text { } } ,\n" \
6024 "{ asn1 \"Id-pat.id.app-number\" , prefix \"Appl: \" , form text { } } } } } } ,\n" \
6025 "{ name \"StdCitLet\" ,\n" \
6026 "format { asn1 \"Cit-let\" , form block {\n" \
6027 "separator \"\\n\" ,\n" \
6028 "components {\n" \
6029 "{ asn1 \"Cit-let.type\" , prefix \"[\" , suffix \"]\" , form enum { } } ,\n" \
6030 "{ asn1 \"Cit-let.man-id\" , form text { } } ,\n" \
6031 "{ asn1 \"Cit-let.cit\" , form use-template \"StdCitBook\" } } } } } ,\n" \
6032 "{ name \"StdPubEquiv\" ,\n" \
6033 "format { asn1 \"Pub-equiv\" , form block {\n" \
6034 "separator \"\\n\" ,\n" \
6035 "components {\n" \
6036 "{ asn1 \"Pub-equiv.E\" , form use-template \"StdPub\" } } } } } ,\n" \
6037 "{ name \"StdTitle\" ,\n" \
6038 "format { asn1 \"Title\" , form block {\n" \
6039 "separator \", \" ,\n" \
6040 "components {\n" \
6041 "{ asn1 \"Title.E.trans\" , prefix \"[\" , suffix \"]\" , form text { } } ,\n" \
6042 "{ asn1 \"Title.E.name\" , form text { } } ,\n" \
6043 "{ asn1 \"Title.E.tsub\" , form text { } } ,\n" \
6044 "{ asn1 \"Title.E.abr\" , form text { } } ,\n" \
6045 "{ asn1 \"Title.E.iso-jta\" , form text { } } ,\n" \
6046 "{ asn1 \"Title.E.ml-jta\" , label \"MEDLINE\" , prefix \": \" , form text { } } ,\n" \
6047 "{ asn1 \"Title.E.jta\" , label \"jta\" , prefix \": \" , form text { } } ,\n" \
6048 "{ asn1 \"Title.E.issn\" , label \"ISSN\" , prefix \": \" , form text { } } ,\n" \
6049 "{ asn1 \"Title.E.coden\" , label \"CODEN\" , prefix \": \" , form text { } } ,\n" \
6050 "{ asn1 \"Title.E.isbn\" , label \"ISBN\" , prefix \": \" , form text { } } } } } } ,\n" \
6051 "{ name \"StdAuthList\" ,\n" \
6052 "format { asn1 \"Auth-list\" , form block {\n" \
6053 "separator \"\\n\" ,\n" \
6054 "components {\n" \
6055 "{ asn1 \"Auth-list\" , form user { printfunc \"StdAuthListNamesPrint\" } } ,\n" \
6056 "{ asn1 \"Auth-list.affil\" , form use-template \"StdAffil\" } } } } } ,\n" \
6057 "{ name \"StdAffil\" ,\n" \
6058 "format { asn1 \"Affil\" , form block {\n" \
6059 "separator \"\\n\" ,\n" \
6060 "components {\n" \
6061 "{ asn1 \"Affil.str\" , form text { } } ,\n" \
6062 "{ asn1 \"Affil.std.affil\" , form text { } } ,\n" \
6063 "{ asn1 \"Affil.std.div\" , form text { } } ,\n" \
6064 "{ asn1 \"Affil.std.street\" , form text { } } ,\n" \
6065 "{ asn1 \"Affil.std\" , form block {\n" \
6066 "separator \" \" ,\n" \
6067 "components {\n" \
6068 "{ asn1 \"Affil.std.city\" , form text { } } ,\n" \
6069 "{ asn1 \"Affil.std.sub\" , form text { } } ,\n" \
6070 "{ asn1 \"Affil.std.country\" , form text { } } } } } } } } } ,\n" \
6071 "{ name \"StdImprint\" ,\n" \
6072 "format { asn1 \"Imprint\" , form block {\n" \
6073 "components {\n" \
6074 "{ asn1 \"Imprint.date\" , prefix \"(\" , suffix \") \" , form user { printfunc \"StdDatePrint\" } } ,\n" \
6075 "{ asn1 \"Imprint.volume\" , form text { } } ,\n" \
6076 "{ asn1 \"Imprint.issue\" , prefix \" (\" , suffix \")\" , form text { } } ,\n" \
6077 "{ asn1 \"Imprint.section\" , prefix \" (\" , suffix \")\" , form text { } } ,\n" \
6078 "{ asn1 \"Imprint.part-sup\" , prefix \" (\" , suffix \")\" , form text { } } ,\n" \
6079 "{ asn1 \"Imprint.pages\" , prefix \": \" , form text { } } ,\n" \
6080 "{ asn1 \"Imprint.prepub\" , prefix \" (\" , suffix \")\" , form enum { } } ,\n" \
6081 "{ asn1 \"Imprint.pub\" , label \"\nPublisher: \" , form use-template \"StdAffil\" } ,\n" \
6082 "{ asn1 \"Imprint.cprt\" , label \" Copyright: \" , form user { printfunc \"StdDatePrint\" } } } } } } ,\n" \
6083 "{ name \"StdSeqFeatXref\" ,\n" \
6084 "format { asn1 \"SeqFeatXref\" , form block {\n" \
6085 "separator \"\\n\" ,\n" \
6086 "components {\n" \
6087 "{ asn1 \"SeqFeatXref.id\" , label \"Id=\" , form use-template \"StdFeatId\" } ,\n" \
6088 "{ asn1 \"SeqFeatXref.data\" , form use-template \"StdSeqFeatData\" } } } } } ,\n" \
6089 "{ name \"StdOrgRef\" ,\n" \
6090 "format { asn1 \"Org-ref\" , label \"Org-ref\" , prefix \"\\n\" , form block {\n" \
6091 "separator \"\\n\" ,\n" \
6092 "components {\n" \
6093 "{ asn1 \"Org-ref\" , form block {\n" \
6094 "separator \" \" ,\n" \
6095 "components {\n" \
6096 "{ asn1 \"Org-ref.taxname\" , form text { } } ,\n" \
6097 "{ asn1 \"Org-ref.common\" , prefix \"(\" , suffix \")\" , form text { } } } } } ,\n" \
6098 "{ asn1 \"Org-ref.mod\" , label \"Modifiers\" , prefix \" (\" , suffix \")\" , form block {\n" \
6099 "separator \", \" ,\n" \
6100 "components {\n" \
6101 "{ asn1 \"Org-ref.mod.E\" , form text { } } } } } ,\n" \
6102 "{ asn1 \"Org-ref.db\" , label \"Cross Reference\" , prefix \" \" , form block {\n" \
6103 "separator \", \" ,\n" \
6104 "components {\n" \
6105 "{ asn1 \"Org-ref.db.E\" , prefix \"(\" , suffix \")\" , form use-template \"StdDbtag\" } } } } ,\n" \
6106 "{ asn1 \"Org-ref.syn\" , label \"Synonyms\" , prefix \" (\" , suffix \")\" , form block {\n" \
6107 "separator \", \" ,\n" \
6108 "components {\n" \
6109 "{ asn1 \"Org-ref.syn.E\" , form text { } } } } } } } } } ,\n" \
6110 "{ name \"StdBioSource\" ,\n" \
6111 "format { asn1 \"BioSource\" , label \"BioSource\" , form block {\n" \
6112 "separator \"\\n\" ,\n" \
6113 "components {\n" \
6114 "{ asn1 \"BioSource.genome\" , form enum { } } ,\n" \
6115 "{ asn1 \"BioSource.org\" , label \"Organism\" , form use-template \"StdOrgRef\" } } } } } ,\n" \
6116 "{ name \"StdCdRegion\" ,\n" \
6117 "format { asn1 \"Cdregion\" , label \"Cdregion\" , form block {\n" \
6118 "separator \"\\n\" ,\n" \
6119 "components {\n" \
6120 "{ asn1 \"Cdregion.orf\" , form boolean {\n" \
6121 "true \"Uncharacterized Open Reading Frame\" } } ,\n" \
6122 "{ asn1 \"Cdregion.frame\" , label \"Reading Frame = \" , form enum { } } ,\n" \
6123 "{ asn1 \"Cdregion.code\" , label \"Genetic Code: \" , suffix \";\" , form block {\n" \
6124 "separator \", \" ,\n" \
6125 "components {\n" \
6126 "{ asn1 \"Genetic-code.E.name\" , form text { } } ,\n" \
6127 "{ asn1 \"Genetic-code.E.id\" , label \"id= \" , form text { } } } } } ,\n" \
6128 "{ asn1 \"Cdregion.conflict\" , form boolean {\n" \
6129 "true \"Translation conflicts with protein sequence\" } } ,\n" \
6130 "{ asn1 \"Cdregion.stops\" , prefix \"Translation contains \" , suffix \" stop codons\" , form text { } } ,\n" \
6131 "{ asn1 \"Cdregion.gaps\" , prefix \"Translation contains \" , suffix \" gaps when aligned to protein\" , form text { } } ,\n" \
6132 "{ asn1 \"Cdregion.mismatch\" , prefix \"Translation contains \" , suffix \" mismatches when aligned to protein\" , form text { } } } } } } ,\n" \
6133 "{ name \"StdProtRef\" ,\n" \
6134 "format { asn1 \"Prot-ref\" , label \"Prot-ref\" , form block {\n" \
6135 "separator \"\\n\" ,\n" \
6136 "components {\n" \
6137 "{ asn1 \"Prot-ref.name\" , form block {\n" \
6138 "separator \", \" ,\n" \
6139 "components {\n" \
6140 "{ asn1 \"Prot-ref.name.E\" , form text { } } } } } ,\n" \
6141 "{ asn1 \"Prot-ref.desc\" , prefix \"[\" , suffix \"]\" , form text { } } ,\n" \
6142 "{ asn1 \"Prot-ref.processed\" , form enum { } } ,\n" \
6143 "{ asn1 \"Prot-ref.ec\" , label \"ec\" , prefix \": \" , form block {\n" \
6144 "separator \", \" ,\n" \
6145 "components {\n" \
6146 "{ asn1 \"Prot-ref.ec.E\" , form text { } } } } } ,\n" \
6147 "{ asn1 \"Prot-ref.activity\" , label \"activity\" , prefix \": \" , form block {\n" \
6148 "separator \", \" ,\n" \
6149 "components {\n" \
6150 "{ asn1 \"Prot-ref.activity.E\" , form text { } } } } } ,\n" \
6151 "{ asn1 \"Prot-ref.db\" , label \"Cross Reference\" , prefix \" \" , form block {\n" \
6152 "separator \", \" ,\n" \
6153 "components {\n" \
6154 "{ asn1 \"Prot-ref.db.E\" , prefix \"(\" , suffix \")\" , form use-template \"StdDbtag\" } } } } } } } } ,\n" \
6155 "{ name \"StdRNARef\" ,\n" \
6156 "format { asn1 \"RNA-ref\" , label \"RNA-ref\" , form block {\n" \
6157 "separator \"\\n\" ,\n" \
6158 "components {\n" \
6159 "{ asn1 \"RNA-ref.type\" , form enum { } } ,\n" \
6160 "{ asn1 \"RNA-ref.pseudo\" , form boolean {\n" \
6161 "true \"This is an RNA pseudogene.\" } } ,\n" \
6162 "{ asn1 \"RNA-ref.ext.name\" , form text { } } } } } } ,\n" \
6163 "{ name \"StdPubdesc\" ,\n" \
6164 "format { asn1 \"Pubdesc\" , label \"Pubdesc\" , form block {\n" \
6165 "separator \"\\n\" ,\n" \
6166 "components {\n" \
6167 "{ asn1 \"Pubdesc.pub\" , form use-template \"StdPubEquiv\" } ,\n" \
6168 "{ asn1 \"Pubdesc\" , prefix \"In this article:\n\" , form block {\n" \
6169 "separator \"\\n\" ,\n" \
6170 "components {\n" \
6171 "{ asn1 \"Pubdesc.name\" , label \"name=\" , form text { } } ,\n" \
6172 "{ asn1 \"Pubdesc.fig\" , label \"figure=\" , form text { } } ,\n" \
6173 "{ asn1 \"Pubdesc.poly-a\" , form boolean {\n" \
6174 "true \"poly(A) shown\" } } ,\n" \
6175 "{ asn1 \"Pubdesc.maploc\" , label \"map location=\" , form text { } } ,\n" \
6176 "{ asn1 \"Pubdesc.num\" , form use-template \"StdNumbering\" } ,\n" \
6177 "{ asn1 \"Pubdesc.numexc\" , form boolean {\n" \
6178 "true \"numbering inconsistent\" } } } } } ,\n" \
6179 "{ asn1 \"Pubdesc.comment\" , form text { } } } } } } ,\n" \
6180 "{ name \"StdImpFeat\" ,\n" \
6181 "format { asn1 \"Imp-feat.key\" , label \"Imp-feat\" , form text { } } } ,\n" \
6182 "{ name \"StdRsiteRef\" ,\n" \
6183 "format { asn1 \"Rsite-ref\" , label \"Rsite-ref\" , form block {\n" \
6184 "components {\n" \
6185 "{ asn1 \"Rsite-ref.str\" , form text { } } ,\n" \
6186 "{ asn1 \"Rsite-ref.std\" , form use-template \"StdDbtag\" } } } } } ,\n" \
6187 "{ name \"StdTxInit\" ,\n" \
6188 "format { asn1 \"Txinit\" , label \"TxInit\" , form block {\n" \
6189 "components {\n" \
6190 "{ asn1 \"Txinit.name\" , form text { } } } } } } ,\n" \
6191 "{ name \"StdNumbering\" ,\n" \
6192 "format { asn1 \"Numbering\" , label \"Numbering\" , form null NULL } } ,\n" \
6193 "{ name \"StdGBBlock\" ,\n" \
6194 "format { asn1 \"GB-block\" , label \"GenBank-block\" , form block {\n" \
6195 "separator \"\\n\" ,\n" \
6196 "components {\n" \
6197 "{ asn1 \"GB-block.extra-accessions\" , label \"Extra accessions\" , prefix \" (\" , suffix \")\" , form block {\n" \
6198 "separator \", \" ,\n" \
6199 "components {\n" \
6200 "{ asn1 \"GB-block.extra-accessions.E\" , form text { } } } } } ,\n" \
6201 "{ asn1 \"GB-block.keywords\" , label \"Keywords\" , prefix \" (\" , suffix \")\" , form block {\n" \
6202 "separator \", \" ,\n" \
6203 "components {\n" \
6204 "{ asn1 \"GB-block.keywords.E\" , form text { } } } } } ,\n" \
6205 "{ asn1 \"GB-block.source\" , label \"Source: \" , form text { } } ,\n" \
6206 "{ asn1 \"GB-block.origin\" , label \"Origin: \" , form text { } } ,\n" \
6207 "{ asn1 \"GB-block.div\" , label \"Division: \" , form text { } } ,\n" \
6208 "{ asn1 \"GB-block.taxonomy\" , label \"Taxonomy: \" , form text { } } ,\n" \
6209 "{ asn1 \"GB-block.date\" , label \"Date: \" , form text { } } ,\n" \
6210 "{ asn1 \"GB-block.entry-date\" , label \"Entry date: \" , form user { printfunc \"StdDatePrint\" } } } } } } ,\n" \
6211 "{ name \"StdFeatId\" ,\n" \
6212 "format { asn1 \"Feat-id\" , form block {\n" \
6213 "components {\n" \
6214 "{ asn1 \"Feat-id.gibb\" , label \"GenInfo Backbone: \" , form text { } } ,\n" \
6215 "{ asn1 \"Feat-id.giim.id\" , label \"GenInfo Import Id: \" , form text { } } ,\n" \
6216 "{ asn1 \"Feat-id.local\" , label \"Local: \" , form use-template \"StdObjectId\" } ,\n" \
6217 "{ asn1 \"Feat-id.general\" , form use-template \"StdDbtag\" } } } } } ,\n" \
6218 "{ name \"StdSeqFeatCommon\" ,\n" \
6219 "format { asn1 \"Seq-feat\" , form block {\n" \
6220 "separator \"\\n\" ,\n" \
6221 "components {\n" \
6222 "{ asn1 \"Seq-feat.id\" , label \"Id=\" , form use-template \"StdFeatId\" } ,\n" \
6223 "{ asn1 \"Seq-feat.title\" , form text { } } ,\n" \
6224 "{ asn1 \"Seq-feat\" , suffix \";\" , form block {\n" \
6225 "separator \", \" ,\n" \
6226 "components {\n" \
6227 "{ asn1 \"Seq-feat.partial\" , form boolean {\n" \
6228 "true \"Partial\" } } ,\n" \
6229 "{ asn1 \"Seq-feat.except\" , form boolean {\n" \
6230 "true \"Biological Exception\" } } ,\n" \
6231 "{ asn1 \"Seq-feat.exp-ev\" , label \"Evidence\" , prefix \" is \" , form enum { } } } } } ,\n" \
6232 "{ asn1 \"Seq-feat.comment\" , form text { } } ,\n" \
6233 "{ asn1 \"Seq-feat.ext\" , form use-template \"StdUserObj\" } ,\n" \
6234 "{ asn1 \"Seq-feat.qual\" , label \"Qualifiers\" , prefix \"\\n\" , form block {\n" \
6235 "separator \"\\n\" ,\n" \
6236 "components {\n" \
6237 "{ asn1 \"Seq-feat.qual.E\" , prefix \"/\" , form block {\n" \
6238 "separator \"= \" ,\n" \
6239 "components {\n" \
6240 "{ asn1 \"Gb-qual.qual\" , form text { } } ,\n" \
6241 "{ asn1 \"Gb-qual.val\" , form text { } } } } } } } } } } } } ,\n" \
6242 "{ name \"StdDbtag\" ,\n" \
6243 "format { asn1 \"Dbtag\" , form block {\n" \
6244 "components {\n" \
6245 "{ asn1 \"Dbtag.db\" , suffix \": \" , form text { } } ,\n" \
6246 "{ asn1 \"Dbtag.tag\" , form use-template \"StdObjectId\" } } } } } ,\n" \
6247 "{ name \"StdObjectId\" ,\n" \
6248 "format { asn1 \"Object-id\" , form block {\n" \
6249 "components {\n" \
6250 "{ asn1 \"Object-id.id\" , form text { } } ,\n" \
6251 "{ asn1 \"Object-id.str\" , form text { } } } } } } };\n";
6252 #else
6253 CharPtr objPrtMemStr = "";
6254 #endif
6255 
6256 typedef Boolean (*MatchBioseqToTableData) PROTO ((BioseqPtr, ValNodePtr, Int4));
6257 typedef Boolean (*BioseqAlreadyHasTableData) PROTO ((BioseqPtr, ValNodePtr, Int4));
6258 
6259 static CharPtr GetMatchString (ValNodePtr columns, Int4 match_pos) 
6260 {
6261   ValNodePtr vnp;
6262 
6263   vnp = columns;
6264   while (match_pos > 0 && vnp != NULL) {
6265     vnp = vnp->next;
6266     match_pos--;
6267   }
6268   if (vnp == NULL) {
6269     return NULL;
6270   } else {
6271     return vnp->data.ptrvalue;
6272   }
6273 }
6274 
6275 static Boolean MatchBioseqToTableDataByID (BioseqPtr bsp, ValNodePtr columns, Int4 match_pos)
6276 {
6277   Char       seqid[100];
6278   Int4       seqid_len;
6279   SeqIdPtr   sip;
6280   CharPtr    match_string;
6281   Boolean    rval = FALSE;
6282 
6283   if (bsp == NULL || columns == NULL || match_pos < 0) return rval;
6284 
6285   match_string = GetMatchString (columns, match_pos);
6286   if (match_string == NULL) return rval;
6287 
6288   sprintf (seqid, "gb|");
6289   seqid_len = StringLen (match_string);
6290   if (seqid_len > 96) {
6291     seqid_len = 96;
6292   }
6293   StringNCpy (seqid + 3, match_string, seqid_len);
6294   seqid [seqid_len + 3] = 0;
6295   sip = MakeSeqID (seqid);
6296   if (SeqIdIn (sip, bsp->id)) {
6297     rval = TRUE;
6298   }
6299   return rval;
6300 }
6301 
6302 static Boolean MatchBioseqToTableDataByOrgname (BioseqPtr bsp, ValNodePtr columns, Int4 match_pos)
6303 {
6304   CharPtr           match_string;
6305   Boolean           rval = FALSE;
6306   SeqDescrPtr       sdp;
6307   SeqMgrDescContext dcontext;
6308   BioSourcePtr      biop;
6309 
6310   if (bsp == NULL || columns == NULL || match_pos < 0) return rval;
6311 
6312   match_string = GetMatchString (columns, match_pos);
6313   if (match_string == NULL) return rval;
6314 
6315   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_source, &dcontext);
6316   while (sdp != NULL && !rval) {
6317     biop = (BioSourcePtr) sdp->data.ptrvalue;
6318     if (biop != NULL && biop->org != NULL && StringCmp (biop->org->taxname, match_string) == 0) {
6319       rval = TRUE;
6320     }
6321     sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_source, &dcontext);
6322   }
6323 
6324   return rval;
6325 }
6326 
6327 
6328 typedef struct bioseqtabledataassoc {
6329   BioseqPtr    bsp;
6330   TableLinePtr tlp;
6331 } BioseqTableDataAssocData, PNTR BioseqTableDataAssocPtr;
6332 
6333 typedef struct buildtabledataassoc {
6334   MatchBioseqToTableData match_func;
6335   Int4                   match_pos;
6336   ValNodePtr             table_data;
6337   ValNodePtr             assoc_list;
6338 } BuildBioseqTableDataAssocData, PNTR BuildBioseqTableDataAssocPtr;
6339 
6340 static void BuildTableDataAssociationCallback (BioseqPtr bsp, Pointer userdata)
6341 {
6342   BuildBioseqTableDataAssocPtr bp;
6343   ValNodePtr                   vnp;
6344   TableLinePtr                 tlp;
6345   BioseqTableDataAssocPtr      bap;
6346 
6347   bp = (BuildBioseqTableDataAssocPtr) userdata;
6348   if (bsp == NULL || bp == NULL || bp->match_func == NULL || bp->table_data == NULL) return;
6349   for (vnp = bp->table_data; vnp != NULL; vnp = vnp->next) {
6350     if (vnp->data.ptrvalue == NULL) continue;
6351     tlp = (TableLinePtr) vnp->data.ptrvalue;
6352     if (bp->match_func(bsp, tlp->parts, bp->match_pos)) {
6353       bap = (BioseqTableDataAssocPtr) MemNew (sizeof (BioseqTableDataAssocData));
6354       bap->bsp = bsp;
6355       bap->tlp = tlp;
6356       ValNodeAddPointer (&(bp->assoc_list), 0, bap);
6357     }
6358   }
6359 }
6360 
6361 static ValNodePtr BuildTableDataAssociation (SeqEntryPtr sep, ValNodePtr table_data, MatchBioseqToTableData match_func, Int4 match_pos)
6362 {
6363   BuildBioseqTableDataAssocData bad;
6364 
6365   if (sep == NULL || table_data == NULL || match_func == NULL) return NULL;
6366   bad.assoc_list = NULL;
6367   bad.match_func = match_func;
6368   bad.match_pos = match_pos;
6369   bad.table_data = table_data;
6370 
6371   VisitBioseqsInSep (sep, &bad, BuildTableDataAssociationCallback);
6372   return bad.assoc_list;
6373 }
6374 
6375 static ValNodePtr 
6376 CheckTableDataAssociation 
6377 (ValNodePtr assoc_list,
6378  BaseFormPtr bfp,
6379  ValNodePtr table_data,
6380  Int4 match_pos,
6381  BioseqAlreadyHasTableData already_func,
6382  CharPtr already_fmt,
6383  CharPtr more_than_one_fmt,
6384  BoolPtr data_needed,
6385  Int4    num_columns)
6386 {
6387   ValNodePtr vnp, vnp_match;
6388   BioseqTableDataAssocPtr bap1, bap2;
6389   ValNodePtr duplicated_bioseqs = NULL, already_has_list = NULL, err_list = NULL;
6390   ValNodePtr blanks = NULL;
6391   ClickableItemPtr cip;
6392   TableLinePtr     tlp;
6393   Boolean          found;
6394   CharPtr          no_match_fmt = "No match for %s";
6395   CharPtr          match_string;
6396   Int4             pos;
6397 
6398   if (assoc_list == NULL) {
6399     Message (MSG_ERROR, "No matches found!");
6400     return NULL;
6401   }
6402   for (vnp = assoc_list; vnp != NULL && vnp->next != NULL; vnp = vnp->next) {
6403     bap1 = (BioseqTableDataAssocPtr) vnp->data.ptrvalue;
6404     for (vnp_match = vnp->next; vnp_match != NULL; vnp_match = vnp_match->next) {
6405       bap2 = (BioseqTableDataAssocPtr) vnp_match->data.ptrvalue;
6406       if (bap1->bsp == bap2->bsp) {
6407         for (vnp_match = duplicated_bioseqs;
6408              vnp_match != NULL && bap1->bsp != vnp_match->data.ptrvalue;
6409              vnp_match = vnp_match->next) {}
6410         if (vnp_match == NULL) {
6411           ValNodeAddPointer (&(duplicated_bioseqs), OBJ_BIOSEQ, bap1->bsp);
6412         }
6413         break;
6414       }
6415     }
6416   }
6417   for (vnp = assoc_list; vnp != NULL; vnp = vnp->next) {
6418     bap1 = (BioseqTableDataAssocPtr) vnp->data.ptrvalue;
6419     if (already_func != NULL && already_func (bap1->bsp, NULL, 0)) {
6420       ValNodeAddPointer (&already_has_list, OBJ_BIOSEQ, bap1->bsp);
6421     }
6422     if (data_needed != NULL) {
6423       for (vnp_match = bap1->tlp->parts, pos = 0;
6424            vnp_match != NULL && pos < num_columns;
6425            vnp_match = vnp_match->next, pos++) {
6426         if (data_needed[pos] && StringHasNoText (vnp_match->data.ptrvalue)) {
6427           break;
6428         }
6429       }
6430       if (pos < num_columns) {
6431         ValNodeAddPointer (&blanks, OBJ_BIOSEQ, bap1->bsp);
6432       }
6433     }
6434   }
6435 
6436   if (duplicated_bioseqs != NULL) {
6437     if (more_than_one_fmt == NULL) {
6438       cip = NewClickableItem (TABLE_DATA_MULTIPLE_VALUES, "%d sequences will receive data from more than one line.", duplicated_bioseqs);
6439     } else {
6440       cip = NewClickableItem (TABLE_DATA_MULTIPLE_VALUES, more_than_one_fmt, duplicated_bioseqs);
6441     }
6442     ValNodeAddPointer (&err_list, 0, cip);
6443   }
6444 
6445   if (already_has_list != NULL) {
6446     if (already_fmt == NULL) {
6447       cip = NewClickableItem (TABLE_DATA_ALREADY_HAS, "%d sequences already have data", already_has_list);
6448     } else {
6449       cip = NewClickableItem (TABLE_DATA_ALREADY_HAS, already_fmt, already_has_list);
6450     }
6451     ValNodeAddPointer (&err_list, 0, cip);
6452   }
6453 
6454   if (blanks != NULL) {
6455     cip = NewClickableItem (TABLE_DATA_CELL_BLANK, "%d sequences have blank values in the table", blanks);
6456     ValNodeAddPointer (&err_list, 0, cip);
6457   }
6458 
6459   for (vnp = table_data; vnp != NULL; vnp = vnp->next) {
6460     tlp = vnp->data.ptrvalue;
6461     found = FALSE;
6462     for (vnp_match = assoc_list; vnp_match != NULL && !found; vnp_match = vnp_match->next) {
6463       bap1 = (BioseqTableDataAssocPtr) vnp_match->data.ptrvalue;
6464       if (bap1->tlp == tlp) {
6465         found = TRUE;
6466       }
6467     }
6468     if (!found) {
6469       match_string = GetMatchString (tlp->parts, match_pos);
6470       if (match_string != NULL) {
6471         cip = (ClickableItemPtr) MemNew (sizeof (ClickableItemData));
6472         MemSet (cip, 0, sizeof (ClickableItemData));
6473         cip->clickable_item_type = TABLE_DATA_NOT_FOUND;
6474         cip->description = MemNew ((StringLen (no_match_fmt) + StringLen (match_string)) * sizeof (Char));
6475         sprintf (cip->description, no_match_fmt, match_string);
6476         ValNodeAddPointer (&err_list, 0, cip);
6477       }
6478     }
6479   }
6480 
6481   return err_list;
6482 }
6483 
6484 static Boolean BioseqHasGenomeProjectID (BioseqPtr bsp, ValNodePtr columns, Int4 match_pos)
6485 {
6486   Boolean     rval = FALSE;
6487   SeqDescrPtr sdp;
6488   SeqMgrDescContext context;
6489  
6490   if (bsp == NULL) return rval;
6491   
6492   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_user, &context);
6493   while (sdp != NULL && !rval) {
6494     rval = IsGenomeProjectIDDescriptor(sdp);
6495     sdp = SeqMgrGetNextDescriptor (bsp, sdp, Seq_descr_user, &context);
6496   }
6497   return rval;
6498 }
6499 
6500 static void ApplyGenomeProjectIDByTableDataAssociationList (ValNodePtr assoc_list, Int4 project_id_col, Boolean do_replace, Boolean blanks_erase, Uint2 entityID)
6501 {
6502   BioseqTableDataAssocPtr bap;
6503   ValNodePtr              vnp;
6504   Int4                    projectID;
6505   SeqDescrPtr             sdp;
6506   UserObjectPtr           uop;
6507   ObjectIdPtr             oip;
6508   UserFieldPtr            ufp, ufp_last, ufp_next;
6509   CharPtr                 match_string;
6510   ObjValNodePtr           ovn;
6511    
6512   for (vnp = assoc_list; vnp != NULL; vnp = vnp->next) {
6513     bap = (BioseqTableDataAssocPtr) vnp->data.ptrvalue;
6514     sdp = NULL;
6515     if (BioseqHasGenomeProjectID (bap->bsp, NULL, 0)) {
6516       if (!do_replace) {
6517         continue;
6518       } else {
6519         sdp = GetGenomeProjectIDDescriptor(bap->bsp);
6520       }
6521     }
6522     match_string = GetMatchString (bap->tlp->parts, project_id_col);
6523     if (StringHasNoText (match_string)) {
6524       if (blanks_erase) {
6525         if (sdp != NULL && sdp->extended != 0) {
6526           ovn = (ObjValNodePtr) sdp;
6527           ovn->idx.deleteme = TRUE;
6528         }
6529       }
6530     } else {
6531       projectID = atoi (match_string);
6532       if (sdp == NULL) {
6533         sdp = SeqDescrNew (bap->bsp->descr);
6534         if (bap->bsp->descr == NULL) bap->bsp->descr = sdp;
6535         sdp->choice = Seq_descr_user;          
6536         uop = CreateGenomeProjectsDBUserObject ();
6537         AddIDsToGenomeProjectsDBUserObject (uop, projectID, 0);
6538         sdp->data.ptrvalue = uop;
6539       } else {
6540         uop = sdp->data.ptrvalue;
6541         if (uop == NULL) {
6542           uop = CreateGenomeProjectsDBUserObject ();
6543           sdp->data.ptrvalue = uop;
6544         }
6545         ufp_last = NULL;
6546         ufp = uop->data;
6547         while (ufp != NULL) {
6548           oip = ufp->label;
6549           if (oip != NULL && StringCmp (oip->str, "ProjectID") == 0) {
6550             break;
6551           } else {
6552             ufp_last = ufp;
6553             ufp = ufp->next;
6554           }
6555         }
6556         if (ufp == NULL) {
6557           ufp_next = NULL;
6558         } else {
6559           ufp_next = ufp->next;
6560         }
6561 
6562         if (ufp->choice != 2) {
6563           ufp_next = ufp->next;
6564           ufp = UserFieldFree(ufp);
6565         }
6566         if (ufp == NULL) {
6567           ufp = UserFieldNew ();
6568           oip = ObjectIdNew ();
6569           oip->str = StringSave ("ProjectID");
6570           ufp->label = oip;
6571           ufp->choice = 2; /* integer */
6572           if (ufp_last == NULL) {
6573             uop->data = ufp;
6574           } else {
6575             ufp_last->next = ufp;
6576           }
6577         }
6578         ufp->data.intvalue = projectID;
6579         ufp->next = ufp_next;
6580       }
6581     }
6582   }
6583   DeleteMarkedObjects (entityID, 0, NULL);
6584 }
6585 
6586 typedef struct genomeprojectid {
6587   FORM_MESSAGE_BLOCK
6588   PopuP id_column;
6589   PopuP match_column;
6590   PopuP gpid_column;
6591 
6592   ValNodePtr table_data;
6593   BaseFormPtr bfp;
6594 } GenomeProjectIdData, PNTR GenomeProjectIdPtr;
6595 
6596 static void CleanupGenomeProjectIDForm (GraphiC g, VoidPtr data)
6597 
6598 {
6599   GenomeProjectIdPtr gpip;
6600 
6601   gpip = (GenomeProjectIdPtr) data;
6602   if (gpip != NULL)
6603   {
6604     CleanUpTableData (gpip->table_data);
6605   }
6606   StdCleanupFormProc (g, data);
6607 }
6608 
6609 static void ApplyGenomeProjectIDs (ButtoN b)
6610 {
6611   GenomeProjectIdPtr gpip;
6612   ValNodePtr         assoc_list = NULL;
6613   SeqEntryPtr        sep;
6614   MatchBioseqToTableData match_func = NULL;
6615   Int4                   match_pos, project_id_col, col_num;
6616   Boolean                ok = FALSE;
6617   Boolean                skip_already_has = FALSE, blanks_erase = FALSE;
6618   ValNodePtr             err_list = NULL;
6619   SeqEntryPtr            oldscope;
6620   TableLinePtr           tlp;
6621   BoolPtr                data_needed = NULL;
6622 
6623   gpip = (GenomeProjectIdPtr) GetObjectExtra (b);
6624   if (gpip == NULL) return;
6625 
6626   match_pos = GetValue (gpip->match_column);
6627   if (match_pos < 1) return;
6628   match_pos--;
6629   project_id_col = GetValue (gpip->gpid_column);
6630   if (project_id_col < 1) return;
6631   project_id_col--;
6632   if (GetValue (gpip->id_column) == 1) {
6633     match_func = MatchBioseqToTableDataByID;
6634   } else {
6635     match_func = MatchBioseqToTableDataByOrgname;
6636   }
6637 
6638   tlp = gpip->table_data->data.ptrvalue;
6639   if (tlp != NULL) {
6640     data_needed = (BoolPtr) MemNew (sizeof (Boolean) * tlp->num_parts);
6641     for (col_num = 0; col_num < tlp->num_parts; col_num++) {
6642       if (col_num == project_id_col) {
6643         data_needed[col_num] = TRUE;
6644       } else {
6645         data_needed[col_num] = FALSE;
6646       }
6647     }
6648   }
6649 
6650   sep = GetTopSeqEntryForEntityID (gpip->input_entityID);
6651   oldscope = SeqEntrySetScope (sep);
6652   assoc_list = BuildTableDataAssociation (sep, gpip->table_data, match_func, match_pos);
6653   err_list = CheckTableDataAssociation (assoc_list, gpip->bfp, gpip->table_data, match_pos, 
6654                                  BioseqHasGenomeProjectID,
6655                                  "%d sequences already have a Genome Project ID.",
6656                                  "%d sequences will get more than one Genome Project ID from the table.",
6657                                  data_needed, tlp->num_parts);
6658 
6659 
6660 
6661   if (err_list == NULL || GetTableOptions (gpip->bfp, err_list, "Errors Matching Sequences from File", "", "",
6662                        "Skip sequences that already have Genome Project IDs",
6663                        "Erase Genome Project IDs when table cell is blank",
6664                        &skip_already_has, &blanks_erase)) {
6665     ApplyGenomeProjectIDByTableDataAssociationList (assoc_list, project_id_col, !skip_already_has, blanks_erase, gpip->input_entityID);
6666     ok = TRUE;
6667   }
6668   assoc_list = ValNodeFree (assoc_list);
6669   if (ok) {
6670     ObjMgrSetDirtyFlag (gpip->input_entityID, TRUE);
6671     ObjMgrSendMsg (OM_MSG_UPDATE, gpip->input_entityID, 0, 0);
6672     ArrowCursor ();
6673     Update ();
6674     Remove (gpip->form);
6675   }
6676   SeqEntrySetScope (oldscope);
6677 }
6678 
6679 
6680 extern void LoadGenomeProjectIDsFromFile (IteM i)
6681 {
6682   BaseFormPtr   bfp;
6683   WindoW        w;
6684   GenomeProjectIdPtr gpip;
6685   GrouP              h, g, c;
6686   ButtoN             b;
6687 
6688 #ifdef WIN_MAC
6689   bfp = currentFormDataPtr;
6690 #else
6691   bfp = GetObjectExtra (i);
6692 #endif
6693   if (bfp == NULL) return;
6694 
6695   gpip = (GenomeProjectIdPtr) MemNew (sizeof(GenomeProjectIdData));
6696   gpip->table_data = ReadTableData ();
6697   if (gpip->table_data == NULL) {
6698     gpip = MemFree (gpip);
6699     return;
6700   }
6701   gpip->bfp = bfp;
6702 
6703   w = FixedWindow (-50, -33, -10, -10, "Add Genome Project IDs", StdCloseWindowProc);
6704   gpip->form = (ForM) w;
6705   SetObjectExtra (w, gpip, CleanupGenomeProjectIDForm);
6706   gpip->input_entityID = bfp->input_entityID;
6707   
6708   h = HiddenGroup (w, -1, 0, NULL);
6709 
6710   g = HiddenGroup (h, 6, 0, NULL);
6711   SetGroupSpacing (g, 10, 10);
6712   StaticPrompt (g, "Match", 0, dialogTextHeight, systemFont, 'c');
6713   gpip->match_column = PopupList (g, TRUE, NULL);
6714   FormatPopupWithTableDataColumns (gpip->match_column, gpip->table_data);
6715   SetValue (gpip->match_column, 1);
6716 
6717   StaticPrompt (g, "To", 0, dialogTextHeight, systemFont, 'c');
6718   gpip->id_column = PopupList (g, TRUE, NULL);
6719   PopupItem (gpip->id_column, "Accession");
6720   PopupItem (gpip->id_column, "Tax Name");
6721   SetValue (gpip->id_column, 1);
6722   StaticPrompt (g, "Use Project ID from", 0, dialogTextHeight, systemFont, 'c');
6723   gpip->gpid_column = PopupList (g, TRUE, NULL);
6724   FormatPopupWithTableDataColumns (gpip->gpid_column, gpip->table_data);
6725   SetValue (gpip->gpid_column, 1);
6726 
6727   c = HiddenGroup (h, 4, 0, NULL);
6728   b = DefaultButton (c, "Accept", ApplyGenomeProjectIDs);
6729   SetObjectExtra (b, gpip, NULL);
6730   b = PushButton (c, "Cancel", StdCancelButtonProc); 
6731   SetObjectExtra (b, gpip, NULL);
6732   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL);
6733   RealizeWindow (w);
6734   Show (w);
6735   Update ();
6736 }
6737 
6738 
6739 static void SuppressGenesOnFeaturesInsideMobileElementsCallback (BioseqPtr bsp, Pointer data)
6740 {
6741   SeqFeatPtr        mobile_element, sfp, gene;
6742   SeqMgrFeatContext fcontext_m, fcontext_s, fcontext_g;
6743   GeneRefPtr        grp;
6744   SeqFeatXrefPtr    xref;
6745 
6746   if (bsp == NULL) return;
6747 
6748   for (mobile_element = SeqMgrGetNextFeature (bsp, NULL, SEQFEAT_IMP, FEATDEF_repeat_region, &fcontext_m);
6749        mobile_element != NULL;
6750        mobile_element = SeqMgrGetNextFeature (bsp, mobile_element, SEQFEAT_IMP, FEATDEF_repeat_region, &fcontext_m)) {
6751     if (!IsMobileElement (mobile_element)) continue;
6752     for (sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &fcontext_s);
6753          sfp != NULL && fcontext_s.left <= fcontext_m.right;
6754          sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &fcontext_s)) {
6755       if (SeqLocCompare (sfp->location, mobile_element->location) == SLC_A_IN_B
6756           && SeqMgrGetGeneXref (sfp) == NULL) {
6757         /* suppress gene if gene not contained in mobile_element */
6758         gene = SeqMgrGetOverlappingGene (sfp->location, &fcontext_g);          
6759         if (gene != NULL && (fcontext_g.left <= fcontext_m.left || fcontext_g.right >= fcontext_m.right)) {
6760           grp = GeneRefNew ();
6761           if (grp != NULL) {
6762                   xref = SeqFeatXrefNew ();
6763                   xref->data.choice = SEQFEAT_GENE;
6764                   xref->data.value.ptrvalue = grp;
6765                   xref->next = sfp->xref;
6766                   sfp->xref = xref;
6767           }
6768         }
6769       }
6770     }
6771   }
6772 }
6773 
6774 
6775 extern void SuppressGenesOnFeaturesInsideMobileElements (IteM i)
6776 {
6777   BaseFormPtr       bfp;
6778   SeqEntryPtr       sep;
6779 
6780 #ifdef WIN_MAC
6781   bfp = currentFormDataPtr;
6782 #else
6783   bfp = GetObjectExtra (i);
6784 #endif
6785   if (bfp == NULL || bfp->input_entityID == 0) return;
6786 
6787   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
6788 
6789   VisitBioseqsInSep (sep, NULL, SuppressGenesOnFeaturesInsideMobileElementsCallback);
6790 
6791   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
6792   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
6793   Update ();
6794 }
6795 
6796 
6797 /* Importing Protein ID Table */
6798 static ValNodePtr GetNthValNode (ValNodePtr list, Int4 nth)
6799 {
6800   if (nth < 0)
6801   {
6802     return NULL;
6803   }
6804   
6805   while (nth > 0 && list != NULL)
6806   {
6807     list = list->next;
6808     nth --;
6809   }
6810   return list;
6811 }
6812 
6813 
6814 typedef struct featurefieldcolumnchoice {
6815   Int4            match_type;
6816   ValNodePtr      field_choice;
6817   Boolean         change_mrna;
6818   Boolean         erase_when_blank;
6819   ExistingTextPtr etp;
6820 } FeatureFieldColumnChoiceData, PNTR FeatureFieldColumnChoicePtr;
6821 
6822 static FeatureFieldColumnChoicePtr FeatureFieldColumnChoiceFree (FeatureFieldColumnChoicePtr f)
6823 {
6824   if (f != NULL) {
6825     f->field_choice = ValNodeFree (f->field_choice);
6826     f->etp = MemFree (f->etp);
6827     f = MemFree (f);
6828   }
6829   return f;
6830 }
6831 
6832 
6833 static ValNodePtr GetFeaturesForGene (SeqFeatPtr gene, Uint1 featdef)
6834 {
6835   BioseqPtr bsp;
6836   SeqFeatPtr sfp;
6837   ValNodePtr feat_list = NULL;
6838   SeqMgrFeatContext fcontext;
6839   Int4              start, stop, swap;
6840 
6841   if (gene == NULL) return NULL;
6842 
6843   bsp = BioseqFindFromSeqLoc (gene->location);
6844   start = SeqLocStart (gene->location);
6845   stop = SeqLocStop (gene->location);
6846   if (stop < start) 
6847   {
6848     swap = start;
6849     start = stop;
6850     stop = swap;
6851   }
6852   for (sfp = SeqMgrGetNextFeature (bsp, NULL, 0, featdef, &fcontext);
6853        sfp != NULL && fcontext.left < stop;
6854        sfp = SeqMgrGetNextFeature (bsp, sfp, 0, featdef, &fcontext))
6855   {
6856     if (fcontext.right >= start && gene == GetGeneForFeature (sfp))
6857     {
6858       ValNodeAddPointer (&feat_list, OBJ_SEQFEAT, sfp);
6859     }
6860   }
6861   return feat_list;
6862 }
6863 
6864 static ValNodePtr GetFeatureListForProteinBioseq (Uint1 featdef, BioseqPtr bsp)
6865 {
6866   ValNodePtr feat_list = NULL;
6867   SeqFeatPtr sfp, cds;
6868   SeqMgrFeatContext fcontext;
6869 
6870   if (bsp == NULL || !ISA_aa (bsp->mol)) 
6871   {
6872     return NULL;
6873   }
6874 
6875   if (featdef == FEATDEF_PROT || featdef == FEATDEF_mat_peptide_aa)
6876   {
6877     for (sfp = SeqMgrGetNextFeature (bsp, NULL, 0, featdef, &fcontext);
6878          sfp != NULL;
6879          sfp = SeqMgrGetNextFeature (bsp, sfp, 0, featdef, &fcontext))
6880     {
6881       ValNodeAddPointer (&feat_list, OBJ_SEQFEAT, sfp);
6882     }
6883   }
6884   else
6885   {
6886     cds = SeqMgrGetCDSgivenProduct (bsp, NULL);
6887     if (cds != NULL) 
6888     {
6889       sfp = NULL;
6890       if (featdef == FEATDEF_CDS)
6891       {
6892         sfp = cds;
6893       }
6894       else if (featdef == FEATDEF_GENE)
6895       {
6896         sfp = GetGeneForFeature (cds);
6897       }
6898       else if (featdef == FEATDEF_mRNA)
6899       {
6900         sfp = SeqMgrGetOverlappingmRNA (cds->location, &fcontext);
6901       }
6902       if (sfp != NULL)
6903       {
6904         ValNodeAddPointer (&feat_list, OBJ_SEQFEAT, sfp);
6905       }
6906     }
6907   }
6908   return feat_list;
6909 }
6910 
6911 
6912 static ValNodePtr GetFeatureListForGene (Uint1 featdef, SeqFeatPtr gene)
6913 {
6914   ValNodePtr feat_list = NULL, cds_list, vnp;
6915   SeqFeatPtr sfp, cds;
6916   SeqMgrFeatContext fcontext;
6917   BioseqPtr         protbsp;
6918 
6919   if (gene == NULL) 
6920   {
6921     return NULL;
6922   }
6923 
6924   if (featdef == FEATDEF_GENE)
6925   {
6926     ValNodeAddPointer (&feat_list, OBJ_SEQFEAT, gene);
6927   }
6928   else if (featdef == FEATDEF_mRNA || featdef == FEATDEF_CDS)
6929   {
6930     feat_list = GetFeaturesForGene (gene, featdef);
6931   }
6932   else if (featdef == FEATDEF_PROT || featdef == FEATDEF_mat_peptide_aa)
6933   {
6934     cds_list = GetFeaturesForGene (gene, FEATDEF_CDS);
6935     for (vnp = cds_list; vnp != NULL; vnp = vnp->next) 
6936     {
6937       cds = vnp->data.ptrvalue;
6938       if (cds != NULL)
6939       {
6940         protbsp = BioseqFindFromSeqLoc (cds->product);
6941         for (sfp = SeqMgrGetNextFeature (protbsp, NULL, 0, featdef, &fcontext);
6942              sfp != NULL;
6943              sfp = SeqMgrGetNextFeature (protbsp, sfp, 0, featdef, &fcontext))
6944         {
6945           ValNodeAddPointer (&feat_list, OBJ_SEQFEAT, sfp);
6946         }
6947       }
6948     }
6949     cds_list = ValNodeFree (cds_list);
6950   }
6951 
6952   return feat_list;
6953 }
6954 
6955 
6956 static SeqFeatPtr GetFeatureForFieldByMatchList (ValNodePtr field, ValNodePtr match_list, ValNodePtr PNTR errors)
6957 {
6958   Uint1 featdef;
6959   ValNodePtr vnp;
6960   ValNodePtr tmp;
6961   CharPtr    msg;
6962   CharPtr    no_match_fmt = "No feature found for %s";
6963   CharPtr    too_many_fmt = "%d features found for %s (only one allowed!)";
6964   CharPtr    bad_comb_fmt = "Multiple match columns specify different features (%s, %s)!";
6965   SeqFeatPtr sfp = NULL;
6966 
6967   if (field == NULL || match_list == NULL || errors == NULL) return NULL;
6968 
6969   featdef = (Uint1)FeatDefTypeFromFieldList (field);
6970   if (featdef == FEATDEF_BAD || featdef == FEATDEF_ANY) 
6971   { 
6972     return NULL;
6973   }
6974 
6975   for (vnp = match_list; vnp != NULL; vnp = vnp->next)
6976   {
6977     tmp = NULL;
6978     if (vnp->choice == OBJ_BIOSEQ) 
6979     {
6980       tmp = GetFeatureListForProteinBioseq (featdef, vnp->data.ptrvalue);
6981     }
6982     else
6983     {
6984       tmp = GetFeatureListForGene (featdef, vnp->data.ptrvalue);
6985     }
6986     if (tmp == NULL)      
6987     {
6988       msg = (CharPtr) MemNew (sizeof (Char) * (StringLen (no_match_fmt) + StringLen (vnp->data.ptrvalue)));
6989       sprintf (msg, no_match_fmt, vnp->data.ptrvalue);
6990       ValNodeAddPointer (errors, 0, msg);
6991     }
6992     else if (tmp->next != NULL)
6993     {
6994       msg = (CharPtr) MemNew (sizeof (Char) * (StringLen (too_many_fmt) + StringLen (vnp->data.ptrvalue) + 15));
6995       sprintf (msg, too_many_fmt, ValNodeLen (tmp), vnp->data.ptrvalue);
6996       ValNodeAddPointer (errors, 0, msg);
6997     }
6998     else if (sfp != NULL && sfp != tmp->data.ptrvalue)
6999     {
7000       msg = (CharPtr) MemNew (sizeof (Char) * (StringLen (bad_comb_fmt) + StringLen (vnp->data.ptrvalue) + StringLen (match_list->data.ptrvalue)));
7001       sprintf (msg, too_many_fmt, match_list->data.ptrvalue, vnp->data.ptrvalue);
7002       ValNodeAddPointer (errors, 0, msg);
7003     }
7004     else
7005     {
7006       sfp = tmp->data.ptrvalue;
7007     }
7008     tmp = ValNodeFree (tmp);
7009   }
7010   return sfp;
7011 }
7012 
7013 
7014 static void 
7015 GetExistingValueCounts 
7016 (TableLinePtr                     tlp,
7017  FeatureFieldColumnChoicePtr PNTR f_list,
7018  Int4                             num_columns,
7019  ValNodePtr                       match_list,
7020  Int4Ptr                          existing_text,
7021  BoolPtr                          has_mrna,
7022  BoolPtr                          missing_mrna,
7023  ValNodePtr PNTR                  errors)
7024 {
7025   Int4       i;
7026   ValNodePtr vnp;
7027   SeqFeatPtr sfp, mrna;
7028   CharPtr    val;
7029 
7030   if (tlp == NULL || f_list == NULL || existing_text == NULL) return;
7031 
7032   vnp = tlp->parts;
7033   for (i = 0; i < num_columns; i++)
7034   {
7035     if (f_list[i]->field_choice != NULL) 
7036     {
7037       sfp = GetFeatureForFieldByMatchList (f_list[i]->field_choice, match_list, errors);
7038       if (sfp != NULL) 
7039       {
7040         val = GetCDSGeneProtField (sfp, f_list[i]->field_choice, NULL);
7041         if (!StringHasNoText (val)) 
7042         {
7043           existing_text[i]++;
7044         }
7045         val = MemFree (val);
7046         if (IsCDSetProteinProductChoice (f_list[i]->field_choice) && f_list[i]->change_mrna)
7047         {
7048           mrna = GetmRNAForFeature (sfp);
7049           if (mrna == NULL)
7050           {
7051             *missing_mrna = TRUE;
7052           }
7053           else
7054           {
7055             *has_mrna = TRUE;
7056           }
7057         }
7058       }
7059     }
7060     if (vnp != NULL) 
7061     {
7062       vnp = vnp->next;
7063     }
7064   }
7065 }
7066 
7067 
7068 static Int4 
7069 ApplyProteinIDTableLine 
7070 (TableLinePtr                     tlp,
7071  FeatureFieldColumnChoicePtr PNTR f_list,
7072  Int4                             num_columns,
7073  ValNodePtr                       match_list)
7074 {
7075   Int4       index;
7076   ValNodePtr vnp;
7077   SeqFeatPtr sfp;
7078   ApplyValueData avd;
7079   ValNodePtr     errors = NULL;
7080   Int4           fields_affected = 0;
7081 
7082   if (tlp == NULL || f_list == NULL || match_list == NULL) return 0;
7083 
7084   index = 0;
7085   vnp = tlp->parts;
7086   while (index < num_columns)
7087   {
7088     if (f_list[index]->field_choice != NULL) 
7089     {
7090       sfp = GetFeatureForFieldByMatchList (f_list[index]->field_choice, match_list, &errors);
7091       if (sfp != NULL)
7092       {
7093         if (vnp == NULL || StringHasNoText (vnp->data.ptrvalue)) 
7094         {
7095           if (f_list[index]->erase_when_blank)
7096           {
7097             RemoveCDSGeneProtField (sfp, f_list[index]->field_choice, NULL);
7098             fields_affected++;
7099           }
7100         }
7101         else
7102         {
7103           avd.etp = f_list[index]->etp;
7104           avd.field_list = f_list[index]->field_choice;
7105           avd.new_text = vnp->data.ptrvalue;
7106           avd.text_to_replace = NULL;
7107           avd.where_to_replace = EditApplyFindLocation_anywhere;
7108           SetCDSGeneProtField (sfp, f_list[index]->field_choice, &avd, NULL);
7109           fields_affected ++;
7110         }
7111         /* note - need special case to change mRNA product if CDS product changes */
7112         if (IsCDSetProteinProductChoice (f_list[index]->field_choice) && f_list[index]->change_mrna)
7113         {
7114           if (AdjustmRNAProductToMatchProteinProduct (sfp))
7115           {
7116             fields_affected++;
7117           }
7118         }
7119       }
7120     }
7121     index++;
7122     if (vnp != NULL) 
7123     {
7124       vnp = vnp->next;
7125     }
7126   }
7127   errors = ValNodeFreeData (errors);
7128   return fields_affected;
7129 }
7130 
7131 
7132 typedef struct featurefieldcolumnchoicedlg {
7133   DIALOG_MESSAGE_BLOCK
7134   GrouP                    match_or_field;
7135   PopuP                    match_type;
7136   DialoG                   field_choice;
7137   ButtoN                   change_mrna;
7138   /* for existing text options */
7139   GrouP                    apply_options;
7140   ButtoN                   erase_when_blank;
7141   GrouP                    existing_text_action_grp;
7142   GrouP                    existing_text_delim_grp;
7143 
7144   Nlm_ChangeNotifyProc     change_notify;
7145   Pointer                  change_userdata;
7146 } FeatureFieldColumnChoiceDlgData, PNTR FeatureFieldColumnChoiceDlgPtr;
7147 
7148 static void FeatureFieldColumnChoicePopupChange (PopuP p)
7149 {
7150   FeatureFieldColumnChoiceDlgPtr dlg;
7151 
7152   dlg = (FeatureFieldColumnChoiceDlgPtr) GetObjectExtra (p);
7153   if (dlg != NULL && dlg->change_notify != NULL) {
7154     (dlg->change_notify) (dlg->change_userdata);
7155   }
7156 }
7157 
7158 
7159 static void FeatureFieldColumnChoiceFieldChange (Pointer data)
7160 {
7161   FeatureFieldColumnChoiceDlgPtr dlg;
7162   ValNodePtr                     vnp;
7163 
7164   dlg = (FeatureFieldColumnChoiceDlgPtr) data;
7165   if (dlg != NULL) {
7166     vnp = DialogToPointer (dlg->field_choice);
7167     if (IsCDSetProteinProductChoice (vnp)) {
7168       Enable (dlg->change_mrna);
7169     } else {
7170       Disable (dlg->change_mrna);
7171     }
7172     vnp = ValNodeFree (vnp);
7173     if (dlg->change_notify != NULL) {
7174       (dlg->change_notify) (dlg->change_userdata);
7175     }
7176   }
7177 }
7178 
7179 
7180 static void FeatureFieldColumnChoiceGroupChange (GrouP p)
7181 {
7182   FeatureFieldColumnChoiceDlgPtr dlg;
7183 
7184   dlg = (FeatureFieldColumnChoiceDlgPtr) GetObjectExtra (p);
7185   if (dlg != NULL) {
7186     if (GetValue (dlg->match_or_field) == 1) {
7187       Enable (dlg->match_type);
7188       Disable (dlg->field_choice);
7189       Disable (dlg->apply_options);
7190       Disable (dlg->change_mrna);
7191     } else {
7192       Disable (dlg->match_type);
7193       Enable (dlg->field_choice);
7194       Enable (dlg->apply_options);
7195       FeatureFieldColumnChoiceFieldChange (dlg);
7196     }
7197     if (dlg->change_notify != NULL) {
7198       (dlg->change_notify) (dlg->change_userdata);
7199     }
7200   }
7201 }
7202 
7203 
7204 static Pointer FeatureFieldColumnDialogToChoice (DialoG d)
7205 {
7206   FeatureFieldColumnChoiceDlgPtr dlg;
7207   FeatureFieldColumnChoicePtr    f;
7208   Int4                           existing_text_action;
7209   Int4                           existing_text_delimiter;
7210 
7211   dlg = (FeatureFieldColumnChoiceDlgPtr) GetObjectExtra (d);
7212   if (dlg == NULL) return NULL;
7213 
7214   f = (FeatureFieldColumnChoicePtr) MemNew (sizeof (FeatureFieldColumnChoiceData));
7215   f->change_mrna = FALSE;
7216   if (GetValue (dlg->match_or_field) == 1) {
7217     f->match_type = GetValue (dlg->match_type);
7218     f->etp = NULL;
7219     f->erase_when_blank = FALSE;
7220   } else {
7221     f->field_choice = DialogToPointer (dlg->field_choice);
7222     if (dlg->erase_when_blank == NULL) {
7223       f->erase_when_blank = FALSE;
7224     } else {
7225       f->erase_when_blank = GetStatus (dlg->erase_when_blank);
7226     }
7227     if (IsCDSetProteinProductChoice (f->field_choice)) {
7228       f->change_mrna = GetStatus (dlg->change_mrna);
7229     }
7230     f->etp = (ExistingTextPtr) MemNew (sizeof (ExistingTextData));
7231     existing_text_action = GetValue (dlg->existing_text_action_grp);
7232     if (existing_text_action == 1) {
7233       f->etp->existing_text_choice = eExistingTextChoiceReplaceOld;
7234     } else if (existing_text_action == 4) {
7235       f->etp->existing_text_choice = eExistingTextChoiceLeaveOld;
7236     } else {
7237       existing_text_delimiter = GetValue (dlg->existing_text_delim_grp);
7238       if (existing_text_action == 2) {
7239         f->etp->existing_text_choice = eExistingTextChoiceAppendSemi + existing_text_delimiter - 1;
7240       } else if (existing_text_action == 3) {
7241         f->etp->existing_text_choice = eExistingTextChoicePrefixSemi + existing_text_delimiter - 1;
7242       } else {
7243         f->etp->existing_text_choice = eExistingTextChoiceCancel;
7244       }
7245     }       
7246   }
7247   return f;
7248 
7249 }
7250 
7251 
7252 static void ChangeExistingTextActionChoice (GrouP g)
7253 {
7254   FeatureFieldColumnChoiceDlgPtr dlg;
7255   Int4                           action_choice;
7256 
7257   dlg = (FeatureFieldColumnChoiceDlgPtr) GetObjectExtra (g);
7258   if (dlg == NULL) return;
7259   
7260   action_choice = GetValue (dlg->existing_text_action_grp);
7261   if (action_choice == 2 || action_choice == 3) {
7262     Enable (dlg->existing_text_delim_grp);
7263   } else {
7264     Disable (dlg->existing_text_delim_grp);
7265   }
7266 }
7267 
7268 
7269 static DialoG FeatureFieldColumnChoiceDialog 
7270 (GrouP                    h,
7271  CharPtr                  title,
7272  Int4                     num_blank,
7273  Nlm_ChangeNotifyProc     change_notify,
7274  Pointer                  change_userdata)
7275 {
7276   FeatureFieldColumnChoiceDlgPtr dlg;
7277   GrouP p, g1, g;
7278   ButtoN b1, b2;
7279   PrompT ppt;
7280   CharPtr real_title;
7281   CharPtr title_fmt = "(%d are blank)%s";
7282 
7283   dlg = (FeatureFieldColumnChoiceDlgPtr) MemNew (sizeof (FeatureFieldColumnChoiceDlgData));
7284 
7285   if (num_blank > 0) {
7286     real_title = (CharPtr) MemNew (sizeof (Char) * (StringLen (title_fmt) + StringLen (title) + 15));
7287     sprintf (real_title, title_fmt, num_blank, title);
7288   } else {
7289     real_title = title;
7290   }
7291 
7292   p = NormalGroup (h, -1, 0, real_title, programFont, NULL);
7293   SetObjectExtra (p, dlg, StdCleanupExtraProc);
7294 
7295   if (real_title != title) {
7296     real_title = MemFree (real_title);
7297   }
7298   dlg->dialog = (DialoG) p;
7299   dlg->fromdialog = FeatureFieldColumnDialogToChoice;
7300   dlg->change_notify = change_notify;
7301   dlg->change_userdata = change_userdata;
7302 
7303   g1 = HiddenGroup (p, 2, 0, NULL);
7304   dlg->match_or_field = HiddenGroup (g1, 0, 2, FeatureFieldColumnChoiceGroupChange);
7305   SetObjectExtra (dlg->match_or_field, dlg, NULL);
7306   b1 = RadioButton (dlg->match_or_field, "Match to");
7307   b2 = RadioButton (dlg->match_or_field, "Apply to");
7308   SetValue (dlg->match_or_field, 1);
7309 
7310   g = HiddenGroup (g1, 0, 2, NULL);
7311   dlg->match_type = PopupList (g, TRUE, FeatureFieldColumnChoicePopupChange);
7312   SetObjectExtra (dlg->match_type, dlg, NULL);
7313   PopupItem (dlg->match_type, "None");
7314   PopupItem (dlg->match_type, "ID");
7315   PopupItem (dlg->match_type, "Gene locus tag");
7316   SetValue (dlg->match_type, 1);
7317 
7318   dlg->field_choice = CDSGeneProtFieldSelectionDialog (g, FALSE, FeatureFieldColumnChoiceFieldChange, dlg);
7319   Disable (dlg->field_choice);
7320   AlignObjects (ALIGN_MIDDLE, (HANDLE) b1, (HANDLE) dlg->match_type, NULL);
7321   AlignObjects (ALIGN_MIDDLE, (HANDLE) b2, (HANDLE) dlg->field_choice, NULL);
7322 
7323   dlg->change_mrna = CheckBox (p, "Also change mRNA product name", NULL);
7324   Disable (dlg->change_mrna);
7325 
7326   dlg->apply_options = HiddenGroup (p, -1, 0, NULL);
7327   if (num_blank > 0) {
7328     dlg->erase_when_blank = CheckBox (dlg->apply_options, "Erase field when table cell is blank", NULL);
7329   } else {
7330     dlg->erase_when_blank = NULL;
7331   }
7332   dlg->existing_text_action_grp = HiddenGroup (dlg->apply_options, 4, 0, ChangeExistingTextActionChoice);
7333   SetGroupSpacing (dlg->existing_text_action_grp, 10, 10);
7334   SetObjectExtra (dlg->existing_text_action_grp, dlg, NULL);
7335   RadioButton (dlg->existing_text_action_grp, "Overwrite existing text");
7336   RadioButton (dlg->existing_text_action_grp, "Append");
7337   RadioButton (dlg->existing_text_action_grp, "Prefix");
7338   RadioButton (dlg->existing_text_action_grp, "Ignore new text");
7339   SetValue (dlg->existing_text_action_grp, 1);
7340 
7341   ppt = StaticPrompt (dlg->apply_options, "Separate new text and old text with", 
7342                       0, dialogTextHeight, programFont, 'c');
7343   
7344   dlg->existing_text_delim_grp = HiddenGroup (dlg->apply_options, 4, 0, NULL);
7345   SetGroupSpacing (dlg->existing_text_delim_grp, 10, 10);
7346   RadioButton (dlg->existing_text_delim_grp, "Semicolon");
7347   RadioButton (dlg->existing_text_delim_grp, "Space");
7348   RadioButton (dlg->existing_text_delim_grp, "Colon");
7349   RadioButton (dlg->existing_text_delim_grp, "Do not separate");
7350   SetValue (dlg->existing_text_delim_grp, 1);
7351   Disable (dlg->existing_text_delim_grp);
7352 
7353   Disable (dlg->apply_options);
7354 
7355   AlignObjects (ALIGN_CENTER, (HANDLE) dlg->existing_text_action_grp,
7356                               (HANDLE) ppt,
7357                               (HANDLE) dlg->existing_text_delim_grp,
7358                               (HANDLE) dlg->erase_when_blank, 
7359                               NULL);
7360 
7361   AlignObjects (ALIGN_CENTER, (HANDLE) g1, (HANDLE) dlg->change_mrna, (HANDLE) dlg->apply_options, NULL);
7362 
7363   return (DialoG) p;
7364 }
7365 
7366 typedef struct featurefieldtable {
7367   FEATURE_FORM_BLOCK
7368   ValNodePtr header_line;
7369   Int4       num_columns;
7370   DialoG PNTR columns;
7371   ButtoN      accept_button;
7372 } FeatureFieldTableData, PNTR FeatureFieldTablePtr;
7373 
7374 
7375 static void CleanupFeatureFieldTableForm (GraphiC g, VoidPtr data)
7376 {
7377   FeatureFieldTablePtr  form;
7378 
7379   form = (FeatureFieldTablePtr) data;
7380   if (form != NULL) {
7381     CleanUpTableData (form->header_line);
7382     form->columns = MemFree (form->columns);
7383   }
7384   StdCleanupFormProc (g, data);
7385 }
7386 
7387 
7388 typedef struct findgenelocustag {
7389   CharPtr locus_tag;
7390   ValNodePtr gene_list;
7391 } FindGeneLocusTagData, PNTR FindGeneLocusTagPtr;
7392 
7393 static void FindGeneByLocusTagBioseqCallback (BioseqPtr bsp, Pointer userdata)
7394 {
7395   FindGeneLocusTagPtr p;
7396   SeqFeatPtr          gene;
7397   SeqMgrFeatContext   fcontext;
7398 
7399   if (bsp == NULL || userdata == NULL || !ISA_na (bsp->mol)) {
7400     return;
7401   }
7402 
7403   p = (FindGeneLocusTagPtr) userdata;
7404 
7405   gene = SeqMgrGetGeneByLocusTag (bsp, p->locus_tag, &fcontext);
7406   if (gene != NULL) {
7407     ValNodeAddPointer (&p->gene_list, OBJ_SEQFEAT, gene);
7408   }
7409 }
7410 
7411 
7412 static ValNodePtr 
7413 FindMatchListForRow 
7414 (FeatureFieldColumnChoicePtr PNTR f_list,
7415  Int4                             num_columns,
7416  SeqEntryPtr                      sep,
7417  TableLinePtr                     tlp,
7418  ValNodePtr PNTR                  missing_ids,
7419  ValNodePtr PNTR                  missing_genes)
7420 {
7421   Int4       index;
7422   ValNodePtr match_list = NULL, vnp_match;
7423   SeqIdPtr   sip;
7424   BioseqPtr  bsp;
7425   FindGeneLocusTagData fd;
7426 
7427   if (f_list == NULL || tlp == NULL || tlp->parts == NULL || sep == NULL) return NULL;
7428   for (index = 0, vnp_match = tlp->parts;
7429        index < num_columns && vnp_match != NULL;
7430        index++, vnp_match = vnp_match->next) 
7431   {
7432     if (f_list[index]->match_type == 2) 
7433     {
7434       sip = CreateSeqIdFromText (vnp_match->data.ptrvalue, sep);
7435       bsp = BioseqFind (sip);
7436       sip = SeqIdFree (sip);
7437       if (bsp == NULL) 
7438       {
7439         if (missing_ids != NULL) 
7440         {
7441           ValNodeAddPointer (missing_ids, 0, StringSave (vnp_match->data.ptrvalue));
7442         }
7443       }
7444       else
7445       {
7446         ValNodeAddPointer (&match_list, OBJ_BIOSEQ, bsp);
7447       }
7448     }        
7449     else if (f_list[index]->match_type == 3)
7450     {
7451       fd.locus_tag = vnp_match->data.ptrvalue;
7452       fd.gene_list = NULL;
7453       VisitBioseqsInSep (sep, &fd, FindGeneByLocusTagBioseqCallback);
7454       if (fd.gene_list == NULL) 
7455       {
7456         if (missing_genes != NULL) 
7457         {
7458           ValNodeAddPointer (missing_genes, 0, StringSave (vnp_match->data.ptrvalue));
7459         }
7460       }
7461       else
7462       {
7463         ValNodeLink (&match_list, fd.gene_list);
7464         fd.gene_list = NULL;
7465       }
7466     }
7467   }
7468   return match_list;
7469 }
7470 
7471 
7472 static void DoLoadFeatureFieldTable (ButtoN b)
7473 {
7474   FeatureFieldTablePtr  form;
7475   SeqEntryPtr           sep, oldscope;
7476   ValNodePtr            vnp;
7477   FeatureFieldColumnChoicePtr PNTR f_list;  
7478   Int4                             index;
7479   Int4                             num_rows;
7480   ValNodePtr PNTR                  match_lists;
7481   ValNodePtr                       missing_ids = NULL, missing_genes = NULL;
7482   CharPtr                          msg;
7483   Int4Ptr                          existing_text;
7484   Boolean                          has_mrna = FALSE;
7485   Boolean                          missing_mrna = FALSE;
7486   ValNodePtr                       errors = NULL;
7487   LogInfoPtr                       lip;
7488   Int4                             fields_affected = 0;
7489   CharPtr                          label;
7490 
7491   form = (FeatureFieldTablePtr) GetObjectExtra (b);
7492   if (form == NULL) return;
7493   
7494   sep = GetTopSeqEntryForEntityID (form->input_entityID);
7495 
7496   f_list = (FeatureFieldColumnChoicePtr PNTR) MemNew (form->num_columns * sizeof (FeatureFieldColumnChoicePtr));
7497   for (index = 0; index < form->num_columns; index++) {
7498     f_list[index] = DialogToPointer (form->columns[index]);
7499   }
7500 
7501   /* find match items (either protein IDs or genes) for each row */
7502   /* make sure all IDs and gene locus_tags in table are in record */
7503   num_rows = ValNodeLen (form->header_line);
7504   match_lists = (ValNodePtr PNTR) MemNew (num_rows * sizeof (ValNodePtr));
7505   for (index = 0, vnp = form->header_line; index < num_rows && vnp != NULL; index++, vnp = vnp->next) {
7506     match_lists[index] = FindMatchListForRow (f_list, form->num_columns, sep, vnp->data.ptrvalue, &missing_ids, &missing_genes);
7507   }
7508 
7509   if (missing_ids != NULL) {
7510     msg = CreateListMessage ("ID", 
7511                                  missing_ids->next == NULL 
7512                                  ? " is not found in this record." 
7513                                  : " not found in this record.",
7514                                  missing_ids);
7515     ValNodeAddPointer (&errors, 0, msg);
7516     missing_ids = ValNodeFreeData (missing_ids);
7517   }
7518   if (missing_genes != NULL) {
7519     msg = CreateListMessage ("Gene", 
7520                                  missing_genes->next == NULL 
7521                                  ? " is not found in this record." 
7522                                  : " not found in this record.",
7523                                  missing_genes);
7524     ValNodeAddPointer (&errors, 0, msg);
7525     missing_genes = ValNodeFreeData (missing_genes);
7526   }
7527 
7528   existing_text = (Int4Ptr) MemNew (form->num_columns * sizeof (Int4));
7529 
7530   for (vnp = form->header_line, index = 0; vnp != NULL; vnp = vnp->next, index++) {
7531     if (vnp->data.ptrvalue == NULL) continue;
7532     GetExistingValueCounts (vnp->data.ptrvalue, f_list, form->num_columns, match_lists[index], existing_text, &has_mrna, &missing_mrna, &errors);
7533   }
7534   
7535   lip = OpenLog ("Table Problems");
7536   for (vnp = errors; vnp != NULL; vnp = vnp->next) {
7537     fprintf (lip->fp, "%s\n", vnp->data.ptrvalue);
7538     lip->data_in_log = TRUE;
7539   }
7540   errors = ValNodeFreeData (errors);
7541   
7542   if (has_mrna && missing_mrna) {
7543     fprintf (lip->fp, "Some coding regions for which product names will be set have overlapping mRNA features, but some do not!\n");
7544     lip->data_in_log = TRUE;
7545   }
7546   for (index = 0; index < form->num_columns; index++) {
7547     if (f_list[index]->field_choice != NULL) {
7548       if (existing_text[index] > 0) {
7549         label = GetCDSGeneProtFieldName (f_list[index]->field_choice);
7550         fprintf (lip->fp, "%d features affected by column %d contain existing text in field %s.\n", existing_text[index], index + 1, label);
7551         label = MemFree (label);
7552         lip->data_in_log = TRUE;
7553       }
7554     }
7555   }
7556   CloseLog (lip);
7557   if (lip->data_in_log) {
7558     if (ANS_CANCEL == Message (MSG_OKC, "Continue with errors?")) {
7559       existing_text = MemFree (existing_text);
7560       /* free match lists */
7561       for (index = 0; index < num_rows; index++) {
7562         match_lists[index] = ValNodeFree (match_lists[index]);
7563       }
7564       /* free choices */
7565       for (index = 0; index < form->num_columns; index++) {
7566         f_list[index] = FeatureFieldColumnChoiceFree (f_list[index]);
7567       }
7568       return;
7569     }
7570   }
7571 
7572   oldscope = SeqEntrySetScope (sep);
7573 
7574   for (vnp = form->header_line, index = 0; vnp != NULL; vnp = vnp->next, index++) {
7575     if (vnp->data.ptrvalue == NULL) continue;
7576     fields_affected += ApplyProteinIDTableLine (vnp->data.ptrvalue, f_list, form->num_columns, match_lists[index]);
7577   }
7578 
7579   SeqEntrySetScope (oldscope);
7580 
7581   /* free match lists */
7582   for (index = 0; index < num_rows; index++) {
7583     match_lists[index] = ValNodeFree (match_lists[index]);
7584   }
7585   /* free choices */
7586   for (index = 0; index < form->num_columns; index++) {
7587     f_list[index] = FeatureFieldColumnChoiceFree (f_list[index]);
7588   }
7589 
7590   ObjMgrSetDirtyFlag (form->input_entityID, TRUE);
7591   ObjMgrSendMsg (OM_MSG_UPDATE, form->input_entityID, 0, 0);
7592   Remove (form->form);
7593   Message (MSG_OK, "%d fields were affected", fields_affected);
7594 }
7595 
7596 static void SetFeatureFieldTableAccept (Pointer data)
7597 {
7598   FeatureFieldTablePtr form;
7599   Int4                 index;
7600   FeatureFieldColumnChoicePtr f;
7601   Boolean                     have_match = FALSE, have_apply = FALSE;
7602 
7603   form = (FeatureFieldTablePtr) data;
7604   if (form == NULL) return;
7605 
7606   for (index = 0; index < form->num_columns && (!have_match || !have_apply); index++)
7607   {
7608     f = DialogToPointer (form->columns[index]);
7609     if (f != NULL) 
7610     {
7611       if (f->match_type > 1)
7612       {
7613         have_match = TRUE;
7614       }
7615       else if (f->field_choice != NULL)
7616       {
7617         have_apply = TRUE;
7618       }
7619       f = FeatureFieldColumnChoiceFree (f);
7620     }
7621   }
7622   if (have_match && have_apply) 
7623   {
7624     Enable (form->accept_button);
7625   } 
7626   else
7627   {
7628     Disable (form->accept_button);
7629   }
7630 }
7631 
7632 
7633 extern void LoadFeatureFieldTable (IteM i)
7634 {
7635   BaseFormPtr          bfp;
7636   SeqEntryPtr          sep;
7637   ValNodePtr           header_line;
7638   Int4                 index;
7639   FeatureFieldTablePtr form;
7640   WindoW               w;
7641   GrouP                h, g, c;
7642   TableLinePtr         tlp;
7643   ValNodePtr           vnp;
7644   Int4Ptr              blank_list = NULL;
7645 
7646 #ifdef WIN_MAC
7647   bfp = currentFormDataPtr;
7648 #else
7649   bfp = GetObjectExtra (i);
7650 #endif
7651   if (bfp == NULL || bfp->input_entityID == 0) return;
7652 
7653   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
7654 
7655 
7656   header_line = ReadTableData ();
7657   if (header_line == NULL || header_line->data.ptrvalue == NULL) {
7658     CleanUpTableData (header_line);
7659     return;
7660   }
7661 
7662   /* use form to pick columns for IDs, values */
7663 
7664   form = (FeatureFieldTablePtr) MemNew (sizeof (FeatureFieldTableData));
7665   if (form == NULL) return;
7666   form->input_entityID = bfp->input_entityID;
7667   form->header_line = header_line;
7668   tlp = (TableLinePtr) header_line->data.ptrvalue;
7669   form->num_columns = ValNodeLen (tlp->parts);
7670   form->columns = (DialoG PNTR) MemNew (form->num_columns * sizeof (DialoG));
7671 
7672   /* now create a dialog to display values */
7673   w = FixedWindow (-50, -33, -10, -10, "Feature Field Table", StdCloseWindowProc);
7674   SetObjectExtra (w, form, CleanupFeatureFieldTableForm);
7675   form->form = (ForM) w;
7676 
7677   h = HiddenGroup (w, -1, 0, NULL);
7678   SetGroupSpacing (h, 10, 10);
7679   g = HiddenGroup (h, 3, 0, NULL);
7680 
7681   /* pre-analyze table for blanks, so we can display the information in the column dialogs */
7682   blank_list = GetColumnBlankCounts (header_line, form->num_columns);
7683 
7684   for (vnp = tlp->parts, index = 0; vnp != NULL; vnp = vnp->next, index++)
7685   {
7686     form->columns[index] = FeatureFieldColumnChoiceDialog (g, vnp->data.ptrvalue, 
7687                                                            blank_list == NULL ? 0 : blank_list[index], 
7688                                                            SetFeatureFieldTableAccept, form);
7689   }
7690   blank_list = MemFree (blank_list);
7691 
7692   c = HiddenGroup (h, 4, 0, NULL);
7693   form->accept_button = DefaultButton (c, "Accept", DoLoadFeatureFieldTable);
7694   SetObjectExtra (form->accept_button, form, NULL);
7695   Disable (form->accept_button);
7696   PushButton (c, "Cancel", StdCancelButtonProc);
7697 
7698   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL);
7699   RealizeWindow (w);
7700   Show (w);
7701   Update ();
7702 }
7703 
7704 static Pointer GetRevSectionSequence (Uint1 data_choice, Pointer data, Pointer metadata)
7705 {
7706   BioseqPtr bsp;
7707   Char        id_str[45];
7708 
7709   if (data == NULL)
7710   {
7711     return NULL;
7712   } 
7713   else
7714   {
7715     bsp = (BioseqPtr) data;
7716     SeqIdWrite (SeqIdFindBest (bsp->id, SEQID_GENBANK), id_str, PRINTID_REPORT, 39);
7717     return StringSave (id_str);
7718   }
7719 }
7720 
7721 
7722 static Pointer GetRevSectionInterval (Uint1 data_choice, Pointer data, Pointer metadata)
7723 {
7724   BioseqPtr bsp;
7725   DeltaSeqPtr dsp;
7726   Uint1       seg_num = 0;
7727   Int4        pos = 0;
7728   SeqLocPtr   loc;
7729   SeqLitPtr   slip;
7730   Char        buf[50];
7731 
7732   if ((bsp = (BioseqPtr)data) == NULL || bsp->repr != Seq_repr_delta || bsp->seq_ext == NULL)
7733   {
7734     return NULL;
7735   } 
7736 
7737   for (dsp = (DeltaSeqPtr)(bsp->seq_ext); dsp != NULL; dsp = dsp->next) {
7738     switch (dsp->choice)
7739     {
7740       case 1:      /* SeqLocPtr */
7741         if ((loc = (SeqLocPtr)dsp->data.ptrvalue) != NULL) {
7742           if (loc->choice != SEQLOC_NULL) {
7743             seg_num++;
7744             pos += SeqLocLen (loc);
7745           }
7746         }
7747         break;
7748       case 2:   /* SeqLitPtr */
7749         slip = (SeqLitPtr)(dsp->data.ptrvalue);
7750         if (slip != NULL) {
7751           if (slip->seq_data != NULL) {
7752             if (seg_num == data_choice) {
7753               sprintf (buf, "%d-%d", pos + 1, pos + 1 + slip->length);
7754               return StringSave (buf);
7755             } else {
7756               seg_num++;
7757             }
7758             pos += slip->length;
7759           }
7760         }
7761         break;
7762     }
7763   }
7764   return NULL;
7765 }
7766 
7767 
7768 /*
7769 static BulkEdFieldData revsection_fields[] = {
7770   { "Sequence", NULL, NULL, GetRevSectionSequence, BulkDisplaySimpleText, BulkFreeSimpleText, NULL, BulkFormatSimpleText, NULL, NULL, BulkSimpleTextCopy },
7771   { "Interval", NULL, NULL, GetRevSectionInterval, BulkDisplaySimpleText, BulkFreeSimpleText, NULL, BulkFormatSimpleText, NULL, NULL, BulkSimpleTextCopy },
7772   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}};
7773 */
7774 
7775 
7776 typedef struct deltaseqint {
7777   BioseqPtr bsp;
7778   Int4      start;
7779   Int4      stop;
7780   SeqLitPtr slip;
7781 } DeltaSeqIntData, PNTR DeltaSeqIntPtr;
7782 
7783 
7784 static DeltaSeqIntPtr DeltaSeqIntNew (BioseqPtr bsp, Int4 start, Int4 stop, SeqLitPtr slip)
7785 {
7786   DeltaSeqIntPtr dsip;
7787 
7788   dsip = (DeltaSeqIntPtr) MemNew (sizeof (DeltaSeqIntData));
7789   dsip->bsp = bsp;
7790   dsip->start = start;
7791   dsip->stop = stop;
7792   dsip->slip = slip;
7793   return dsip;
7794 }
7795 
7796 
7797 static void ListDeltaSeqIntervalsCallback (BioseqPtr bsp, Pointer userdata)
7798 {
7799   ValNodePtr PNTR interval_list;
7800   DeltaSeqPtr dsp;
7801   Uint1       seg_num = 0;
7802   Int4        pos = 0;
7803   SeqLocPtr   loc;
7804   SeqLitPtr   slip;
7805   Char        id_str[45];
7806   ClickableItemPtr cip;
7807   
7808   if (bsp == NULL || bsp->repr != Seq_repr_delta || bsp->seq_ext == NULL || (interval_list = (ValNodePtr PNTR)userdata) == NULL) {
7809     return;
7810   }
7811 
7812   SeqIdWrite (SeqIdFindBest (bsp->id, SEQID_GENBANK), id_str, PRINTID_REPORT, sizeof (id_str) - 1);
7813 
7814   for (dsp = (DeltaSeqPtr)(bsp->seq_ext); dsp != NULL; dsp = dsp->next) {
7815     switch (dsp->choice)
7816     {
7817       case 1:      /* SeqLocPtr */
7818         if ((loc = (SeqLocPtr)dsp->data.ptrvalue) != NULL) {
7819           if (loc->choice != SEQLOC_NULL) {
7820             seg_num++;
7821             pos += SeqLocLen (loc);
7822           }
7823         }
7824         break;
7825       case 2:   /* SeqLitPtr */
7826         slip = (SeqLitPtr)(dsp->data.ptrvalue);
7827         if (slip != NULL) {
7828           if (slip->seq_data != NULL) {
7829             cip = (ClickableItemPtr) MemNew (sizeof (ClickableItemData));
7830             cip->description = (CharPtr) MemNew (sizeof (Char) * (StringLen (id_str) + 65));
7831             sprintf (cip->description, "%s:%d-%d", id_str, pos + 1, pos + slip->length);
7832             cip->clickable_item_type = seg_num;
7833             ValNodeAddPointer (&cip->item_list, 0, DeltaSeqIntNew (bsp, pos, pos + slip->length - 1, slip));
7834             ValNodeAddPointer (interval_list, 0, cip);
7835             seg_num++;
7836           }
7837           pos += slip->length;
7838         }
7839         break;
7840     }
7841   }
7842 }
7843 
7844 
7845 static Int4 GetHighestInterval (ValNodePtr int_list)
7846 {
7847   Int4 max = 0;
7848   ClickableItemPtr cip;
7849 
7850   while (int_list != NULL) {
7851     cip = (ClickableItemPtr) int_list->data.ptrvalue;
7852     if (cip != NULL && cip->clickable_item_type > max) {
7853       max = cip->clickable_item_type;
7854     }
7855     int_list = int_list->next;
7856   }
7857   return max;
7858 }
7859 
7860 
7861 typedef struct revseqintform {
7862   FORM_MESSAGE_BLOCK
7863   DialoG          clickable_list; 
7864   PopuP           interval_choice;
7865   ButtoN          also_reverse_feats;
7866   ValNodePtr      delta_list;
7867 } RevSeqIntFormData, PNTR RevSeqIntFormPtr;
7868 
7869 static void CleanupRevSeqIntForm (GraphiC g, VoidPtr data)
7870 {
7871   RevSeqIntFormPtr f;
7872   ValNodePtr       vnp;
7873   ClickableItemPtr cip;
7874 
7875   f = (RevSeqIntFormPtr) data;
7876   if (f != NULL) {
7877     for (vnp = f->delta_list; vnp != NULL; vnp = vnp->next) {
7878       /* note - the rest of the ClickableItem will be freed by the clickableItemlist */
7879       cip = (ClickableItemPtr) vnp->data.ptrvalue;
7880       if (cip != NULL && cip->item_list != NULL) {
7881         cip->item_list->data.ptrvalue = MemFree (cip->item_list->data.ptrvalue);
7882       }
7883     }
7884   }
7885   StdCleanupFormProc (g, data);
7886 }
7887 
7888 
7889 static void CheckIntervals (ButtoN b)
7890 {
7891   RevSeqIntFormPtr f;
7892   ValNodePtr       vnp;
7893   ClickableItemPtr cip;
7894   Int4             val;
7895 
7896   f = (RevSeqIntFormPtr) GetObjectExtra (b);
7897   if (f == NULL) return;
7898 
7899   val = GetValue (f->interval_choice);
7900   for (vnp = f->delta_list; vnp != NULL; vnp = vnp->next) {
7901     cip = (ClickableItemPtr) vnp->data.ptrvalue;
7902     if (cip != NULL && cip->clickable_item_type == val - 1) {
7903       cip->chosen = TRUE;
7904     }
7905   }
7906   PointerToDialog (f->clickable_list, f->delta_list);
7907 }
7908 
7909 
7910 static Int4 RevCompCoordInInterval (Int4 coord, Int4 start, Int4 stop)
7911 {
7912   Int4 offset;
7913 
7914   if (coord < start || coord > stop) return coord;
7915 
7916   offset = coord - start;
7917   coord = stop - offset;
7918   return coord;
7919 }
7920 
7921 
7922 static void RevCompIntFuzz (IntFuzzPtr ifp, Int4 start, Int4 stop)
7923 {
7924   Int4 tmp;
7925 
7926   if (ifp == NULL) return;
7927 
7928         switch (ifp->choice)
7929         {
7930                 case 1:      /* plus/minus - no changes */
7931                 case 3:      /* percent - no changes */
7932                         break;
7933                 case 2:      /* range */
7934       tmp = RevCompCoordInInterval (ifp->a, start, stop);
7935       ifp->a = RevCompCoordInInterval (ifp->b, start, stop);
7936       ifp->b = tmp;
7937                         break;
7938                 case 4:     /* lim */
7939                         switch (ifp->a)
7940                         {
7941                                 case 1:    /* greater than */
7942                                         ifp->a = 2;
7943                                         break;
7944                                 case 2:    /* less than */
7945                                         ifp->a = 1;
7946                                         break;
7947                                 case 3:    /* to right of residue */
7948                                         ifp->a = 4;
7949                                         break;
7950                                 case 4:    /* to left of residue */
7951                                         ifp->a = 3;
7952                                         break;
7953                                 default:
7954                                         break;
7955                         }
7956                         break;
7957         }
7958 }
7959 
7960 static Uint1 RevStrand (Uint1 strand)
7961 {
7962   if (strand == Seq_strand_minus) {
7963     strand = Seq_strand_plus;
7964   } else {
7965     strand = Seq_strand_minus;
7966   }
7967   return strand;
7968 }
7969 
7970 
7971 static void RevCompSeqPntForFlippedInterval (SeqPntPtr spp, BioseqPtr bsp, Int4 start, Int4 stop)
7972 {
7973 
7974   if (spp == NULL || bsp == NULL) return;
7975   if (!SeqIdIn (spp->id, bsp->id)) return;
7976   if (spp->point < start || spp->point > stop) return;
7977 
7978   /* flip */
7979   spp->point = RevCompCoordInInterval (spp->point, start, stop);
7980   spp->strand = RevStrand (spp->strand);
7981   RevCompIntFuzz (spp->fuzz, start, stop);
7982 }
7983 
7984 
7985 static void RevCompLocationForFlippedInterval (SeqLocPtr head, BioseqPtr bsp, Int4 start, Int4 stop)
7986 {
7987         SeqLocPtr slp;
7988         SeqIntPtr sip;
7989         SeqPntPtr spp;
7990         PackSeqPntPtr pspp, pspp2;
7991         SeqBondPtr sbp;
7992         SeqIdPtr oldids;
7993         Int4 numpnt, i, tpos, tmp;
7994         Boolean do_rev;
7995         IntFuzzPtr ifp;
7996         
7997         if ((head == NULL) || (bsp == NULL)) return;
7998 
7999         oldids = bsp->id;
8000         switch (head->choice)
8001         {    
8002     case SEQLOC_BOND:   /* bond -- 2 seqs */
8003                         sbp = (SeqBondPtr)(head->data.ptrvalue);
8004       RevCompSeqPntForFlippedInterval (sbp->a, bsp, start, stop);
8005       RevCompSeqPntForFlippedInterval (sbp->b, bsp, start, stop);
8006                         break;
8007     case SEQLOC_FEAT:   /* feat -- can't track yet */
8008     case SEQLOC_NULL:    /* NULL */
8009     case SEQLOC_EMPTY:    /* empty */
8010                         break;
8011     case SEQLOC_WHOLE:    /* whole */
8012       /* nothing to reverse */
8013                         break;
8014     case SEQLOC_EQUIV:    /* does it stay equiv? */
8015     case SEQLOC_MIX:    /* mix -- more than one seq */
8016     case SEQLOC_PACKED_INT:    /* packed int */
8017                         for (slp = (SeqLocPtr)(head->data.ptrvalue); slp != NULL; slp = slp->next)
8018                         {
8019         RevCompLocationForFlippedInterval (slp, bsp, start, stop);
8020       }
8021       break;
8022     case SEQLOC_INT:    /* int */
8023                         sip = (SeqIntPtr)(head->data.ptrvalue);
8024                         if (SeqIdIn(sip->id, oldids))
8025                         {
8026         if (sip->from < start || sip->to > stop) {
8027           /* not contained in interval */
8028           break;
8029         }
8030         tmp = RevCompCoordInInterval (sip->from, start, stop);
8031         sip->from = RevCompCoordInInterval (sip->to, start, stop);
8032         sip->to = tmp;
8033         sip->strand = RevStrand (sip->strand);
8034         RevCompIntFuzz (sip->if_to, start, stop);
8035         RevCompIntFuzz (sip->if_from, start, stop);
8036         ifp = sip->if_to;
8037         sip->if_to = sip->if_from;
8038         sip->if_from = ifp;
8039       }
8040       break;
8041     case SEQLOC_PNT:    /* pnt */
8042                         spp = (SeqPntPtr)(head->data.ptrvalue);
8043       RevCompSeqPntForFlippedInterval (spp, bsp, start, stop);
8044       break;
8045     case SEQLOC_PACKED_PNT:    /* packed pnt */
8046                         pspp = (PackSeqPntPtr)(head->data.ptrvalue);
8047       do_rev = FALSE;
8048                         if (SeqIdIn(pspp->id, oldids))
8049                         {
8050         do_rev = TRUE;
8051                                 numpnt = PackSeqPntNum(pspp);
8052         /* can only reverse set if all are in interval */
8053                                 for (i = 0; i < numpnt && do_rev; i++)
8054                                 {
8055                                         tpos = PackSeqPntGet(pspp, i);
8056           if (tpos < start || tpos > stop) {
8057             do_rev = FALSE;
8058           }
8059         }
8060         if (do_rev) {
8061                                   pspp2 = PackSeqPntNew();
8062                                 pspp2->id = pspp->id;
8063           pspp2->fuzz = pspp->fuzz;
8064           pspp->fuzz = NULL;
8065           RevCompIntFuzz (pspp2->fuzz, start, stop);
8066                                   for (i = 0; i < numpnt && do_rev; i++)
8067                                   {
8068                                           tpos = PackSeqPntGet(pspp, i);
8069             tpos = RevCompCoordInInterval (tpos, start, stop);
8070             PackSeqPntPut (pspp2, tpos);
8071           }
8072           pspp2->strand = RevStrand (pspp->strand);
8073           pspp = PackSeqPntFree (pspp);
8074           head->data.ptrvalue = pspp2;
8075                           }
8076       }
8077       break;
8078     default:
8079       break;
8080         }
8081 }
8082 
8083 
8084 static void RevCompOneFeatForBioseqInterval (SeqFeatPtr sfp, BioseqPtr bsp, Int4 start, Int4 stop)
8085 {
8086   CodeBreakPtr cbp;
8087   CdRegionPtr  crp;
8088   RnaRefPtr    rrp;
8089   tRNAPtr      trp;
8090 
8091   if (sfp == NULL || bsp == NULL) return;
8092 
8093   RevCompLocationForFlippedInterval (sfp->location, bsp, start, stop);
8094   switch (sfp->data.choice) {
8095     case SEQFEAT_CDREGION :
8096       crp = (CdRegionPtr) sfp->data.value.ptrvalue;
8097       if (crp != NULL) {
8098         for (cbp = crp->code_break; cbp != NULL; cbp = cbp->next) {
8099           RevCompLocationForFlippedInterval (cbp->loc, bsp, start, stop);
8100         }
8101       }
8102       break;
8103     case SEQFEAT_RNA :
8104       rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
8105       if (rrp != NULL && rrp->ext.choice == 2) {
8106         trp = (tRNAPtr) rrp->ext.value.ptrvalue;
8107         if (trp != NULL && trp->anticodon != NULL) {
8108           RevCompLocationForFlippedInterval (trp->anticodon, bsp, start, stop);
8109         }
8110       }
8111       break;
8112     default :
8113       break;
8114   }
8115 }
8116 
8117 
8118 static void FlipSelectedSequenceIntervals (ButtoN b)
8119 {
8120   RevSeqIntFormPtr f;
8121   ValNodePtr       vnp;
8122   ClickableItemPtr cip;
8123   Int4             num_disc;
8124   DeltaSeqIntPtr   dsip;
8125   Boolean          rev_feats;
8126   SeqFeatPtr        sfp;
8127   SeqMgrFeatContext fcontext;
8128 
8129   f = (RevSeqIntFormPtr) GetObjectExtra (b);
8130   if (f == NULL) return;
8131   num_disc = CountChosenDiscrepancies (f->delta_list, FALSE);
8132   if (num_disc == 0) {
8133     Message (MSG_ERROR, "No intervals selected");
8134     return;
8135   }
8136 
8137   rev_feats = GetStatus (f->also_reverse_feats);
8138 
8139   for (vnp = f->delta_list; vnp != NULL; vnp = vnp->next) {
8140     cip = (ClickableItemPtr) vnp->data.ptrvalue;
8141     if (cip != NULL && cip->chosen && cip->item_list != NULL) {
8142       dsip = (DeltaSeqIntPtr) cip->item_list->data.ptrvalue;
8143       if (dsip != NULL && dsip->slip != NULL) {
8144         ReverseSeqData (dsip->slip->seq_data_type, dsip->slip->length, dsip->slip->seq_data);
8145         ComplementSeqData (dsip->slip->seq_data_type, dsip->slip->length, dsip->slip->seq_data);
8146         if (rev_feats) {
8147           for (sfp = SeqMgrGetNextFeature (dsip->bsp, NULL, 0, 0, &fcontext);
8148                sfp != NULL && fcontext.left <= dsip->stop;
8149                sfp = SeqMgrGetNextFeature (dsip->bsp, sfp, 0, 0, &fcontext)) {
8150             if (fcontext.left >= dsip->start && fcontext.right <= dsip->stop) {
8151               RevCompOneFeatForBioseqInterval (sfp, dsip->bsp, dsip->start, dsip->stop);
8152             }
8153           }
8154         }
8155       }
8156     }
8157   }
8158   Update ();
8159   ObjMgrSetDirtyFlag (f->input_entityID, TRUE);
8160   ObjMgrSendMsg (OM_MSG_UPDATE, f->input_entityID, 0, 0);
8161   Remove (f->form);
8162 }
8163 
8164 NLM_EXTERN void FlipSequenceIntervals (IteM i)
8165 {
8166   BaseFormPtr         bfp;
8167   RevSeqIntFormPtr    f;
8168   SeqEntryPtr         sep;
8169   WindoW              w;
8170   GrouP               h, g, c;
8171   ButtoN              b;
8172   ValNodePtr          delta_list = NULL;
8173   Int4                max, n;
8174   Char                buf[15];
8175 
8176 #ifdef WIN_MAC
8177   bfp = currentFormDataPtr;
8178 #else
8179   bfp = GetObjectExtra (i);
8180 #endif
8181   if (bfp == NULL || bfp->input_entityID == 0) return;
8182 
8183   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
8184 
8185   VisitBioseqsInSep (sep, &delta_list, ListDeltaSeqIntervalsCallback);
8186 
8187   if (delta_list == NULL)
8188   {
8189     Message (MSG_OK, "No sequence intervals");
8190     return;
8191   }
8192 
8193 
8194   f = (RevSeqIntFormPtr) MemNew (sizeof (RevSeqIntFormData));
8195   if (f == NULL)
8196   {
8197     return;
8198   }
8199   f->delta_list = delta_list;
8200   
8201   f->input_entityID = bfp->input_entityID;
8202   w = FixedWindow (-50, -33, -10, -10, "Reverse Sequence Intervals", StdCloseWindowProc);
8203   SetObjectExtra (w, f, CleanupRevSeqIntForm);
8204   f->form = (ForM) w;
8205 
8206   h = HiddenGroup (w, -1, 0, NULL);
8207   SetGroupSpacing (h, 10, 10);
8208   
8209   f->clickable_list = CreateClickableListDialog (h, "Intervals", "",
8210                                                  NULL, NULL, NULL, NULL);
8211   PointerToDialog (f->clickable_list, f->delta_list);
8212 
8213   max = GetHighestInterval (f->delta_list);
8214   
8215   g = HiddenGroup (h, 4, 0, NULL);
8216   StaticPrompt (g, "Check Interval ", 0, popupMenuHeight, programFont, 'l');
8217   f->interval_choice = PopupList (g, TRUE, NULL);
8218   for (n = 0; n <= max; n++) {
8219     sprintf (buf, "%d", n + 1);
8220     PopupItem (f->interval_choice, buf);
8221   }
8222   SetValue (f->interval_choice, 1);
8223   StaticPrompt (g, " for every sequence", 0, popupMenuHeight, programFont, 'l');
8224   b = PushButton (g, "Check", CheckIntervals);
8225   SetObjectExtra (b, f, NULL);
8226 
8227   f->also_reverse_feats = CheckBox (h, "Also reverse features", NULL);
8228 
8229   c = HiddenGroup (h, 4, 0, NULL);
8230   SetGroupSpacing (c, 10, 10);
8231 
8232   b = PushButton (c, "Flip Checked Intervals", FlipSelectedSequenceIntervals);
8233   SetObjectExtra (b, f, NULL);
8234     
8235   PushButton (c, "Dismiss", StdCancelButtonProc);
8236 
8237   AlignObjects (ALIGN_CENTER, (HANDLE) f->clickable_list, (HANDLE) g, (HANDLE) f->also_reverse_feats, (HANDLE) c, NULL);
8238 
8239   RealizeWindow (w);
8240   
8241   Show (w);
8242 }
8243 
8244 
8245 #ifdef OS_MSWIN
8246 #include <undefwin.h>
8247 #include <windows.h>
8248 
8249 NLM_EXTERN Int4 RunSilent(const char *cmdline) {
8250     int status = -1;
8251 
8252     STARTUPINFO         StartupInfo;
8253     PROCESS_INFORMATION ProcessInfo;
8254 
8255     DWORD dwCreateFlags;
8256 
8257 #ifndef COMP_METRO
8258     /* code warrior headers do not have this, so comment out to allow compilation */
8259     _flushall();
8260 #endif
8261 
8262     /* Set startup info */
8263     memset(&StartupInfo, 0, sizeof(StartupInfo));
8264     StartupInfo.cb          = sizeof(STARTUPINFO);
8265     StartupInfo.dwFlags     = STARTF_USESHOWWINDOW;
8266     StartupInfo.wShowWindow = SW_HIDE;
8267     dwCreateFlags           = CREATE_NEW_CONSOLE;
8268 
8269     /* Run program */
8270     if (CreateProcess(NULL, (LPSTR)cmdline, NULL, NULL, FALSE,
8271                       dwCreateFlags, NULL, NULL, &StartupInfo, &ProcessInfo))
8272     {
8273         /* wait running process */
8274         DWORD exitcode = -1;
8275         WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
8276         GetExitCodeProcess(ProcessInfo.hProcess, &exitcode);
8277         status = exitcode;
8278         CloseHandle(ProcessInfo.hProcess);
8279         CloseHandle(ProcessInfo.hThread);
8280     }
8281     else
8282     {
8283         DWORD dw = GetLastError();
8284         /* check for common errors first */
8285         if(dw == ERROR_FILE_NOT_FOUND)
8286             Message(MSG_ERROR, "CreateProcess() failed: file not found.");
8287         else
8288             /* generic error message */
8289             Message(MSG_ERROR, "CreateProcess() failed, error code %d.",
8290                     (int)dw);
8291     }
8292 
8293     return status;
8294 }
8295 #endif
8296 
8297 static void MacroAECRAction (IteM i, Boolean indexer_version, Uint1 action_type, Uint1 qual_type)
8298 {
8299   BaseFormPtr        bfp;
8300 
8301 #ifdef WIN_MAC
8302   bfp = currentFormDataPtr;
8303 #else
8304   bfp = GetObjectExtra (i);
8305 #endif
8306   if (bfp == NULL)
8307     return;
8308 
8309   SingleAECRMacroAction (bfp->input_entityID, indexer_version, action_type, qual_type);
8310 }
8311 
8312 extern void MacroApplyGBQual (IteM i)
8313 {
8314   MacroAECRAction (i, TRUE, ActionChoice_apply, FieldType_feature_field);
8315 }
8316 
8317 
8318 extern void MacroApplySourceQual (IteM i)
8319 {
8320   MacroAECRAction (i, TRUE, ActionChoice_apply, FieldType_source_qual);
8321 }
8322 
8323 
8324 extern void MacroApplyCDSGeneProt (IteM i)
8325 {
8326   MacroAECRAction (i, TRUE, ActionChoice_apply, FieldType_cds_gene_prot);
8327 }
8328 
8329 extern void PublicMacroApplyCDSGeneProt (IteM i)
8330 {
8331   MacroAECRAction (i, FALSE, ActionChoice_apply, FieldType_cds_gene_prot);
8332 }
8333 
8334 
8335 extern void MacroApplyRNAQual (IteM i)
8336 {
8337   MacroAECRAction (i, TRUE, ActionChoice_apply, FieldType_rna_field);
8338 }
8339 
8340 
8341 extern void MacroRemoveGBQual (IteM i)
8342 {
8343   MacroAECRAction (i, TRUE, ActionChoice_remove, FieldType_feature_field);
8344 }
8345 
8346 
8347 extern void MacroRemoveSourceQual (IteM i)
8348 {
8349   MacroAECRAction (i, TRUE, ActionChoice_remove, FieldType_source_qual);
8350 }
8351 
8352 
8353 extern void MacroRemoveCDSGeneProt (IteM i)
8354 {
8355   MacroAECRAction (i, TRUE, ActionChoice_remove, FieldType_cds_gene_prot);
8356 }
8357 
8358 
8359 extern void MacroRemoveRNAQual (IteM i)
8360 {
8361   MacroAECRAction (i, TRUE, ActionChoice_remove, FieldType_rna_field);
8362 }
8363 
8364 
8365 extern void MacroConvertGBQual (IteM i)
8366 {
8367   MacroAECRAction (i, TRUE, ActionChoice_convert, FieldType_feature_field);
8368 }
8369 
8370 
8371 extern void MacroConvertSourceQual (IteM i)
8372 {
8373   MacroAECRAction (i, TRUE, ActionChoice_convert, FieldType_source_qual);
8374 }
8375 
8376 
8377 extern void MacroConvertCDSGeneProt (IteM i)
8378 {
8379   MacroAECRAction (i, TRUE, ActionChoice_convert, FieldType_cds_gene_prot);
8380 }
8381 
8382 
8383 extern void MacroConvertRNAQual (IteM i)
8384 {
8385   MacroAECRAction (i, TRUE, ActionChoice_convert, FieldType_rna_field);
8386 }
8387 
8388 
8389 extern void MacroSwapGBQual (IteM i)
8390 {
8391   MacroAECRAction (i, TRUE, ActionChoice_swap, FieldType_feature_field);
8392 }
8393 
8394 
8395 extern void MacroSwapSourceQual (IteM i)
8396 {
8397   MacroAECRAction (i, TRUE, ActionChoice_swap, FieldType_source_qual);
8398 }
8399 
8400 
8401 extern void MacroSwapCDSGeneProt (IteM i)
8402 {
8403   MacroAECRAction (i, TRUE, ActionChoice_swap, FieldType_cds_gene_prot);
8404 }
8405 
8406 
8407 extern void MacroSwapRNAQual (IteM i)
8408 {
8409   MacroAECRAction (i, TRUE, ActionChoice_swap, FieldType_rna_field);
8410 }
8411 
8412 
8413 extern void MacroEditGBQual (IteM i)
8414 {
8415   MacroAECRAction (i, TRUE, ActionChoice_edit, FieldType_feature_field);
8416 }
8417 
8418 
8419 extern void MacroEditSourceQual (IteM i)
8420 {
8421   MacroAECRAction (i, TRUE, ActionChoice_edit, FieldType_source_qual);
8422 }
8423 
8424 
8425 extern void MacroEditCDSGeneProt (IteM i)
8426 {
8427   MacroAECRAction (i, TRUE, ActionChoice_edit, FieldType_cds_gene_prot);
8428 }
8429 
8430 
8431 extern void PublicMacroEditCDSGeneProt (IteM i)
8432 {
8433   MacroAECRAction (i, FALSE, ActionChoice_edit, FieldType_cds_gene_prot);
8434 }
8435 
8436 
8437 extern void MacroEditRNAQual (IteM i)
8438 {
8439   MacroAECRAction (i, TRUE, ActionChoice_edit, FieldType_rna_field);
8440 }
8441 
8442 
8443 extern void MacroApplyStructuredComment (IteM i)
8444 {
8445   MacroAECRAction (i, TRUE, ActionChoice_apply, FieldType_struc_comment_field);
8446 }
8447 
8448 extern void PublicMacroApplyStructuredComment (IteM i)
8449 {
8450   MacroAECRAction (i, FALSE, ActionChoice_apply, FieldType_struc_comment_field);
8451 }
8452 
8453 extern void MacroEditStructuredComment (IteM i)
8454 {
8455   MacroAECRAction (i, TRUE, ActionChoice_edit, FieldType_struc_comment_field);
8456 }
8457 
8458 extern void PublicMacroEditStructuredComment (IteM i)
8459 {
8460   MacroAECRAction (i, FALSE, ActionChoice_edit, FieldType_struc_comment_field);
8461 }
8462 
8463 extern void MacroRemoveStructuredComment (IteM i)
8464 {
8465   MacroAECRAction (i, TRUE, ActionChoice_remove, FieldType_struc_comment_field);
8466 }
8467 
8468 
8469 
8470 typedef struct convertboisourcedbxreftofeaturedbxref {
8471   FORM_MESSAGE_BLOCK
8472   DialoG feature_type;
8473 } ConvertBioSourceDbxrefToFeatureDbxrefData, PNTR ConvertBioSourceDbxrefToFeatureDbxrefPtr;
8474 
8475 
8476 static ValNodePtr DbxrefListFree (ValNodePtr vnp)
8477 
8478 {
8479   ValNodePtr  next;
8480 
8481   while (vnp != NULL) {
8482     next = vnp->next;
8483     DbtagFree ((DbtagPtr) vnp->data.ptrvalue);
8484     MemFree (vnp);
8485     vnp = next;
8486   }
8487   return NULL;
8488 }
8489 
8490 
8491 static ValNodePtr DbxrefListCopy (ValNodePtr vnp)
8492 
8493 {
8494   ValNodePtr copy = NULL;
8495   
8496   while (vnp != NULL) {
8497     ValNodeAddPointer (&copy, 0, AsnIoMemCopy (vnp->data.ptrvalue, (AsnReadFunc) DbtagAsnRead, (AsnWriteFunc) DbtagAsnWrite));
8498     vnp = vnp->next;
8499   }
8500   return copy;
8501 }
8502 
8503 
8504 static ValNodePtr ExtractNonTaxonDbxrefs (ValNodePtr PNTR list)
8505 {
8506   ValNodePtr prev = NULL, extracted = NULL, vnp, vnp_next;
8507   DbtagPtr dbtag;
8508 
8509   if (list == NULL || *list == NULL) return NULL;
8510   vnp = *list;
8511   while (vnp != NULL) {
8512     vnp_next = vnp->next;
8513     dbtag = (DbtagPtr) vnp->data.ptrvalue;
8514     if (dbtag != NULL && StringCmp (dbtag->db, "taxon") != 0) {
8515       if (prev == NULL) {
8516         *list = vnp_next;
8517       } else {
8518         prev->next = vnp_next;
8519       }
8520       vnp->next = NULL;
8521       ValNodeLink (&extracted, vnp);
8522     } else {
8523       prev = vnp;
8524     }
8525     vnp = vnp_next;
8526   }
8527   return extracted;
8528 }
8529 
8530 
8531 static void ConvertBioSourceDbxrefToFeatureDbxrefBioseqCallback (BioseqPtr bsp, Pointer userdata)
8532 {
8533   ValNodePtr        vnp;
8534   SeqFeatPtr        sfp;
8535   SeqMgrFeatContext fcontext;
8536   SeqDescrPtr       sdp;
8537   SeqMgrDescContext dcontext;
8538   BioSourcePtr      biop;
8539   ValNodePtr        dbxref_list = NULL;
8540   Int4              featdef;
8541   Boolean           any_feat = FALSE;
8542 
8543   if (bsp == NULL || userdata == NULL) {
8544     return;
8545   }
8546 
8547   vnp = (ValNodePtr) userdata;
8548   featdef = GetFeatdefFromFeatureType (vnp->choice);
8549 
8550   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_source, &dcontext);
8551   if (sdp == NULL || sdp->data.ptrvalue == NULL) return;
8552   biop = (BioSourcePtr) sdp->data.ptrvalue;
8553   if (biop->org == NULL || biop->org->db == NULL) return;
8554   dbxref_list = ExtractNonTaxonDbxrefs (&(biop->org->db));
8555   if (dbxref_list == NULL) return;
8556 
8557   for (sfp = SeqMgrGetNextFeature (bsp, NULL, 0, featdef, &fcontext);
8558        sfp != NULL;
8559        sfp = SeqMgrGetNextFeature (bsp, sfp, 0, featdef, &fcontext)) {
8560     ValNodeLink (&(sfp->dbxref), DbxrefListCopy(dbxref_list));
8561     any_feat = TRUE;
8562   }
8563   if (any_feat) {
8564     dbxref_list = DbxrefListFree(dbxref_list);
8565   } else {
8566     ValNodeLink (&(biop->org->db), dbxref_list);
8567   }
8568 }
8569 
8570 
8571 static void AcceptConvertBioSourceDbxrefToFeatureDbxref (ButtoN b)
8572 {
8573   ConvertBioSourceDbxrefToFeatureDbxrefPtr dlg;
8574   ValNodePtr vnp;
8575   SeqEntryPtr sep;
8576 
8577   dlg = (ConvertBioSourceDbxrefToFeatureDbxrefPtr) GetObjectExtra (b);
8578   if (dlg == NULL) return;
8579 
8580   vnp = DialogToPointer (dlg->feature_type);
8581   if (vnp == NULL) {
8582     Message (MSG_ERROR, "Please choose feature type");
8583     return;
8584   }
8585 
8586   sep = GetTopSeqEntryForEntityID (dlg->input_entityID);
8587 
8588   VisitBioseqsInSep (sep, vnp, ConvertBioSourceDbxrefToFeatureDbxrefBioseqCallback);
8589   vnp = ValNodeFree (vnp);
8590 
8591   ObjMgrSetDirtyFlag (dlg->input_entityID, TRUE);
8592   ObjMgrSendMsg (OM_MSG_UPDATE, dlg->input_entityID, 0, 0);
8593   Remove (dlg->form);
8594 }
8595   
8596   
8597 extern void ConvertBioSourceDbxrefToFeatureDbxref (IteM i)
8598 {
8599   BaseFormPtr         bfp;
8600   ConvertBioSourceDbxrefToFeatureDbxrefPtr dlg;
8601   WindoW              w;
8602   GrouP               h, c;
8603   ButtoN              b;
8604   PrompT              ppt;
8605 
8606 #ifdef WIN_MAC
8607   bfp = currentFormDataPtr;
8608 #else
8609   bfp = GetObjectExtra (i);
8610 #endif
8611   if (bfp == NULL || bfp->input_entityID == 0) return;
8612 
8613   dlg = (ConvertBioSourceDbxrefToFeatureDbxrefPtr) MemNew (sizeof (ConvertBioSourceDbxrefToFeatureDbxrefData));
8614 
8615   w = FixedWindow (-50, -33, -10, -10, "Convert BioSource Dbxrefs to Feature Dbxrefs", StdCloseWindowProc);
8616   SetObjectExtra (w, dlg, StdCleanupExtraProc);
8617   dlg->form = (ForM) w;
8618   dlg->input_entityID = bfp->input_entityID;
8619 
8620   h = HiddenGroup (w, -1, 0, NULL);
8621   SetGroupSpacing (h, 10, 10);
8622 
8623   ppt = StaticPrompt (h, "Choose feature type to receive BioSource dbxrefs", 0, dialogTextHeight, programFont, 'l');
8624   dlg->feature_type = FeatureTypeDialog (h, NULL, NULL);
8625   c = HiddenGroup (h, 2, 0, NULL);
8626   b = PushButton (c, "Accept", AcceptConvertBioSourceDbxrefToFeatureDbxref);
8627   SetObjectExtra (b, dlg, NULL);
8628   PushButton (c, "Cancel", StdCancelButtonProc);
8629   AlignObjects (ALIGN_CENTER, (HANDLE) ppt, (HANDLE) dlg->feature_type, (HANDLE) c, NULL);
8630   Show (w);
8631   Select (w);
8632 }
8633 
8634 
8635 typedef struct structuredcommentsform {
8636   FORM_MESSAGE_BLOCK
8637   PopuP match_column;
8638   DialoG match_type;
8639   TexT   database_name;
8640 
8641   ValNodePtr table;
8642 } StructuredCommentsFormData, PNTR StructuredCommentsFormPtr;
8643 
8644 static void CleanupStructuredCommentsForm (GraphiC g, VoidPtr data)
8645 
8646 {
8647   StructuredCommentsFormPtr  frm;
8648 
8649   frm = (StructuredCommentsFormPtr) data;
8650   if (frm != NULL) {
8651     frm->table = FreeTabTable(frm->table);
8652   }
8653   StdCleanupFormProc (g, data);
8654 }
8655 
8656 
8657 static UserObjectPtr UserObjectFromRow (ValNodePtr header, ValNodePtr line, Int4 col, CharPtr dbname, ValNodePtr PNTR err_list)
8658 {
8659   ValNodePtr vnp_h, vnp_l;
8660   CharPtr    id_str = NULL;
8661   Int4       num;
8662   CharPtr    extra_data_fmt = "Too many fields in line for %s";
8663   CharPtr    msg;
8664   UserObjectPtr uop;
8665   CharPtr       prefix = NULL, suffix = NULL;
8666   CharPtr       prefix_fmt = "##%sData-START##";
8667   CharPtr       suffix_fmt = "##%sData-END##";
8668 
8669   if (header == NULL || line == NULL) {
8670     return NULL;
8671   }
8672 
8673   /* find id_str */
8674   vnp_l = line->data.ptrvalue;
8675   if (vnp_l == NULL) {
8676     return NULL;
8677   }
8678   num = 0;
8679   while (vnp_l != NULL && num < col) {
8680     num++;
8681     vnp_l = vnp_l->next;
8682   }
8683   if (vnp_l == NULL || StringHasNoText (vnp_l->data.ptrvalue)) {
8684     return NULL;
8685   } else {
8686     id_str = vnp_l->data.ptrvalue;
8687   }
8688 
8689   /* build user object */
8690   vnp_h = header;
8691   vnp_l = line->data.ptrvalue;
8692   num = 0;
8693 
8694   if (StringHasNoText (dbname)) {
8695     dbname = "Meta";
8696   }
8697 
8698   prefix = (CharPtr) MemNew (sizeof (Char) * (StringLen (prefix_fmt) + StringLen (dbname)));
8699   sprintf (prefix, prefix_fmt, dbname);
8700   suffix = (CharPtr) MemNew (sizeof (Char) * (StringLen (suffix_fmt) + StringLen (dbname)));
8701   sprintf (suffix, suffix_fmt, dbname);
8702 
8703   uop = CreateStructuredCommentUserObject (prefix, suffix);
8704 
8705   prefix = MemFree (prefix);
8706   suffix = MemFree (suffix);
8707