NCBI C Toolkit Cross Reference

C/sequin/sequin3.c


  1 /*   sequin3.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:  sequin3.c
 27 *
 28 * Author:  Jonathan Kans
 29 *
 30 * Version Creation Date:   1/22/95
 31 *
 32 * $Revision: 6.1002 $
 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 <document.h>
 47 #include <sequtil.h>
 48 #include <biosrc.h>
 49 #include <import.h>
 50 #include <gather.h>
 51 #include <asn2gnbk.h>
 52 #include <asn2gnbp.h>
 53 #include <edutil.h>
 54 #include <gbfeat.h>
 55 #include <gbftdef.h>
 56 #include <subutil.h>    /* TOPOLOGY_xxx definitions */
 57 #include <salutil.h>
 58 #include <valid.h>
 59 #include <vsm.h>
 60 #include <bspview.h>
 61 #include <toasn3.h>
 62 #include <salstruc.h>
 63 #include <explore.h>
 64 #include <utilpub.h>
 65 #include <tofasta.h>
 66 #include <rpsutil.h>
 67 #include <findrepl.h>
 68 #include <explore.h>
 69 #include <seqpanel.h>
 70 #include <tax3api.h>
 71 #include <saledit.h>
 72 #include <alignmgr2.h>
 73 #include <suggslp.h>
 74 #include <asn2gnbi.h>
 75 #include <alignval.h>
 76 #include <cdrgn.h>
 77 #define NLM_GENERATED_CODE_PROTO
 78 #include <objmacro.h>
 79 #include <macrodlg.h>
 80 #include <macroapi.h>
 81 #include <valdlg.h>
 82 
 83 /* For converting primer names to primer seqs and vice versa */
 84 static void PrimerSeqToPrimerNameCallback (BioSourcePtr biop, Pointer userdata)
 85 {
 86   SubSourcePtr ssp;
 87 
 88   if (biop == NULL) return;
 89   for (ssp = biop->subtype; ssp != NULL; ssp = ssp->next) {
 90     if (ssp->subtype == SUBSRC_fwd_primer_seq) {
 91       ssp->subtype = SUBSRC_fwd_primer_name;
 92     } else if (ssp->subtype == SUBSRC_rev_primer_seq) {
 93       ssp->subtype = SUBSRC_rev_primer_name;
 94     }
 95   }
 96 }
 97 
 98 
 99 static void PrimerNameToPrimerSeqCallback (BioSourcePtr biop, Pointer userdata)
100 {
101   SubSourcePtr ssp;
102 
103   if (biop == NULL) return;
104   for (ssp = biop->subtype; ssp != NULL; ssp = ssp->next) {
105     if (ssp->subtype == SUBSRC_fwd_primer_name) {
106       ssp->subtype = SUBSRC_fwd_primer_seq;
107     } else if (ssp->subtype == SUBSRC_rev_primer_name) {
108       ssp->subtype = SUBSRC_rev_primer_seq;
109     }
110   }
111 }
112 
113 
114 static void SwapPrimerNamesAndSeq (IteM i, Boolean seq_to_name)
115 {
116   BaseFormPtr  bfp;
117   SeqEntryPtr  sep;
118 
119 #ifdef WIN_MAC
120   bfp = currentFormDataPtr;
121 #else
122   bfp = GetObjectExtra (i);
123 #endif
124   if (bfp == NULL) return;
125   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
126   if (sep == NULL) return;
127   if (seq_to_name) {
128     VisitBioSourcesInSep (sep, NULL, PrimerSeqToPrimerNameCallback);
129   } else {
130     VisitBioSourcesInSep (sep, NULL, PrimerNameToPrimerSeqCallback);
131   }
132   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
133   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
134 }
135 
136 
137 static void ConvertPrimerSeqToName (IteM i)
138 {
139   SwapPrimerNamesAndSeq (i, TRUE);
140 }
141 
142 
143 static void ConvertPrimerNameToSeq (IteM i)
144 {
145   SwapPrimerNamesAndSeq (i, FALSE);
146 }
147 
148 
149 static void TSATableCallback (Pointer data)
150 {
151   ProcessExternalEvent ();
152 }
153 
154 static ValNodePtr ApplyTranscriptomeIdListWithProgress (ValNodePtr ids_list, LocalAlignFunc aln_func)
155 {
156   WindoW     w;
157   GrouP      h;
158   PrompT     ppt;
159   CharPtr    prompt_fmt = "%d out of %d";
160   Char       prompt_str[40];
161   Int4       max, num = 1;
162   ValNodePtr err_list = NULL, vnp;
163 
164   if (ids_list == NULL || aln_func == NULL) return NULL;
165 
166   WatchCursor();
167   Update();
168   w = ModalWindow(-20, -13, -10, -10, NULL);
169   h = HiddenGroup (w, -1, 0, NULL);
170   SetGroupSpacing (h, 10, 10);
171 
172   max = ValNodeLen (ids_list);
173   sprintf (prompt_str, prompt_fmt, max, max);
174   ppt = StaticPrompt (h, prompt_str, 0, dialogTextHeight, programFont, 'c');
175   sprintf (prompt_str, prompt_fmt, 1, max);
176   SetTitle (ppt, prompt_str);  
177   
178   Show(w); 
179   Select (w);
180   for (num = 1, vnp = ids_list; vnp != NULL; vnp = vnp->next, num++) {
181     sprintf (prompt_str, prompt_fmt, num, max);
182     SetTitle (ppt, prompt_str);  
183     ValNodeLink (&err_list, MakeTranscriptomeAssemblySeqHist (vnp->data.ptrvalue, aln_func, TSATableCallback, NULL));
184   }
185 
186   Remove (w);
187   ArrowCursor();
188   Update();
189   return err_list;
190 }
191 
192 
193 NLM_EXTERN void ReportNonTSABioseqs (BioseqPtr bsp, Pointer userdata)
194 {
195   LogInfoPtr lip;
196   Char id_str[255];
197 
198   if (bsp == NULL || (lip = (LogInfoPtr) userdata) == NULL || lip->fp == NULL || ISA_aa (bsp->mol)) {
199     return;
200   }
201   if (bsp->hist == NULL || bsp->hist->assembly == NULL) {
202     SeqIdWrite (SeqIdFindBest (bsp->id, SEQID_GENBANK), id_str, PRINTID_REPORT, sizeof (id_str) - 1);
203     fprintf (lip->fp, "%s has no TSA table\n", id_str);
204     lip->data_in_log = TRUE;
205   }
206 }
207 
208 
209 static void AddTSATableToBioseq (IteM i)
210 {
211   BaseFormPtr  bfp;
212   SeqEntryPtr  sep;
213   ValNodePtr   err_list = NULL, ids_list, vnp;
214   LogInfoPtr   lip;
215   Char         path [PATH_MAX];
216   FILE        *fp;
217   MsgAnswer    ans;
218   ValNodePtr   coverage_report;
219 
220 #ifdef WIN_MAC
221   bfp = currentFormDataPtr;
222 #else
223   bfp = GetObjectExtra (i);
224 #endif
225   if (bfp == NULL) return;
226   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
227   if (sep == NULL) return;
228 
229   if (! GetInputFileName (path, sizeof (path), "", "TEXT")) return;
230   fp = FileOpen (path, "r");
231   if (fp == NULL) {
232     Message (MSG_ERROR, "Unable to open %s", path);
233     return;
234   }
235 
236   ids_list = GetTranscriptomeIdsList (fp, sep, &err_list);
237   FileClose (fp);
238 
239   if (err_list != NULL) {
240     lip = OpenLog ("Problems Reading TSA Table File");
241     for (vnp = err_list; vnp != NULL; vnp = vnp->next) {
242       fprintf (lip->fp, "%s\n", vnp->data.ptrvalue);
243     }
244     lip->data_in_log = TRUE;
245     CloseLog (lip);
246     lip = FreeLog (lip);
247     err_list = ValNodeFreeData (err_list);
248     if (ANS_NO == Message (MSG_YN, "Problems reading input file - continue creating TSA tables?")) {
249       ids_list = TranscriptomeIdsListFree (ids_list);
250       return;
251     }
252   }
253 
254   if (HasExistingSeqHistAssembly(ids_list)) {
255     ans = Message (MSG_YNC, "Some of the bioseqs listed in the file already have Seq-Hist assemblies.  Should these be replaced?");
256     if (ans == ANS_YES) {
257       DeleteSeqHistAssembliesForList(ids_list);
258     } else if (ans == ANS_CANCEL) {
259       ids_list = TranscriptomeIdsListFree (ids_list);
260       return;
261     }
262   }
263 
264   
265   ValNodeLink (&err_list, ApplyTranscriptomeIdListWithProgress (ids_list, GetSeqAlignTSA));
266 
267   coverage_report = ReportCoverageForTranscriptomeIdsListSeqHist (ids_list);
268   ValNodeLink (&coverage_report, ReportGapsInSeqHistAlignmentsForIdsList (ids_list));
269 
270   ids_list = TranscriptomeIdsListFree (ids_list);
271 
272   ValNodeLink (&coverage_report, err_list);
273   err_list = coverage_report;
274 
275   lip = OpenLog ("TSA Table Problems");
276   if (err_list != NULL) {
277     for (vnp = err_list; vnp != NULL; vnp = vnp->next) {
278       fprintf (lip->fp, "%s\n", vnp->data.ptrvalue);
279     }
280     lip->data_in_log = TRUE;
281     err_list = ValNodeFreeData (err_list);
282   }
283   VisitBioseqsInSep (sep, lip, ReportNonTSABioseqs);
284   CloseLog (lip);
285   lip = FreeLog (lip);
286 
287   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
288   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
289 }
290 
291 
292 static void RefreshTSATables (IteM i)
293 {
294   BaseFormPtr  bfp;
295   SeqEntryPtr  sep;
296   ValNodePtr   err_list = NULL, ids_list, vnp;
297   LogInfoPtr   lip;
298   ValNodePtr   coverage_report;
299 
300 #ifdef WIN_MAC
301   bfp = currentFormDataPtr;
302 #else
303   bfp = GetObjectExtra (i);
304 #endif
305   if (bfp == NULL) return;
306   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
307   if (sep == NULL) return;
308 
309 
310   ids_list = GetExistingTSATableIds (sep);
311 
312   DeleteSeqHistAssembliesForList(ids_list);
313   
314   ValNodeLink (&err_list, ApplyTranscriptomeIdListWithProgress (ids_list, GetSeqAlignTSA));
315 
316   coverage_report = ReportCoverageForTranscriptomeIdsListSeqHist (ids_list);
317   ValNodeLink (&coverage_report, ReportGapsInSeqHistAlignmentsForIdsList (ids_list));
318 
319   ids_list = TranscriptomeIdsListFree (ids_list);
320 
321   ValNodeLink (&coverage_report, err_list);
322   err_list = coverage_report;
323 
324 
325   lip = OpenLog ("TSA Table Problems");
326   if (err_list != NULL) {
327     for (vnp = err_list; vnp != NULL; vnp = vnp->next) {
328       fprintf (lip->fp, "%s\n", vnp->data.ptrvalue);
329     }
330     lip->data_in_log = TRUE;
331     err_list = ValNodeFreeData (err_list);
332   }
333   VisitBioseqsInSep (sep, lip, ReportNonTSABioseqs);
334   CloseLog (lip);
335   lip = FreeLog (lip);
336 
337   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
338   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
339 }
340 
341 
342 static void CreateTSAIDsFromLocalIDs (IteM i)
343 {
344   BaseFormPtr  bfp;
345   SeqEntryPtr  sep;
346 
347 #ifdef WIN_MAC
348   bfp = currentFormDataPtr;
349 #else
350   bfp = GetObjectExtra (i);
351 #endif
352   if (bfp == NULL) return;
353   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
354   if (sep == NULL) return;
355 
356   ConvertLocalIdsToTSAIds (sep, NULL);
357 
358   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
359   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
360 }
361 
362 
363 typedef struct createtsaidswithsuffixform {
364   FORM_MESSAGE_BLOCK
365   TexT suffix;
366 } CreateTsaIDsWithSuffixFormData, PNTR CreateTsaIDsWithSuffixFormPtr;
367 
368 static void DoCreateTSAIDsFromLocalIDsWithSuffix (ButtoN b)
369 {
370   CreateTsaIDsWithSuffixFormPtr t;
371   SeqEntryPtr                   sep;
372   CharPtr                       suffix = NULL;
373 
374   t = (CreateTsaIDsWithSuffixFormPtr) GetObjectExtra (b);
375   if (b == NULL) {
376     return;
377   }
378 
379   sep = GetTopSeqEntryForEntityID (t->input_entityID);
380   if (sep == NULL) return;
381 
382   if (!TextHasNoText (t->suffix)) {
383     suffix = SaveStringFromText (t->suffix);
384   }
385   ConvertLocalIdsToTSAIds (sep, suffix);
386   suffix = MemFree (suffix);
387 
388   ObjMgrSetDirtyFlag (t->input_entityID, TRUE);
389   ObjMgrSendMsg (OM_MSG_UPDATE, t->input_entityID, 0, 0);
390   Remove (t->form);
391   Update();
392 }
393 
394 static void CreateTSAIDsFromLocalIDsWithSuffix (IteM i)
395 {
396   BaseFormPtr  bfp;
397   CreateTsaIDsWithSuffixFormPtr t;
398   WindoW       w;
399   GrouP        h, g, c;
400   ButtoN       b;
401 
402 #ifdef WIN_MAC
403   bfp = currentFormDataPtr;
404 #else
405   bfp = GetObjectExtra (i);
406 #endif
407   if (bfp == NULL) return;
408 
409   t = (CreateTsaIDsWithSuffixFormPtr) MemNew (sizeof (CreateTsaIDsWithSuffixFormData));
410 
411   w = FixedWindow (-50, -33, -10, -10, "Create TSA IDs With Suffix", StdCloseWindowProc);
412   h = HiddenGroup (w, -1, 0, NULL);
413   SetGroupSpacing (h, 10, 10);
414   t->form = (ForM) w;
415   t->input_entityID = bfp->input_entityID;
416 
417   g = HiddenGroup (h, 2, 0, NULL);
418   StaticPrompt (g, "Suffix", 0, dialogTextHeight, programFont, 'c');
419   t->suffix = DialogText (g, "", 14, NULL);
420 
421   c = HiddenGroup (h, 2, 0, NULL);
422   b = DefaultButton (c, "Accept", DoCreateTSAIDsFromLocalIDsWithSuffix);
423   SetObjectExtra (b, t, NULL);
424   PushButton (c, "Cancel", StdCancelButtonProc);
425   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL);
426 
427   Show (w);
428 
429 }
430 
431 
432 
433 static void CreateTSAIDsFromTable (IteM i)
434 {
435   BaseFormPtr  bfp;
436   SeqEntryPtr  sep;
437   Char         path [PATH_MAX];
438   FILE         *fp;
439   ValNodePtr   table, sequence_lists, err_list = NULL, vnp, vnp_rs, vnp_s, vnp_rt, vnp_t;
440   MatchTypeData match;
441   LogInfoPtr   lip;
442   BioseqPtr    bsp;
443   Int4         gpid = 0;
444   SeqIdPtr     sip_new;
445   DbtagPtr     dbtag;
446   CharPtr      id_fmt = "gpid:%d";
447 
448 #ifdef WIN_MAC
449   bfp = currentFormDataPtr;
450 #else
451   bfp = GetObjectExtra (i);
452 #endif
453   if (bfp == NULL) return;
454   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
455   if (sep == NULL) return;
456 
457   if (! GetInputFileName (path, sizeof (path), "", "TEXT")) return;
458   fp = FileOpen (path, "r");
459   if (fp == NULL) return;
460   table = ReadTabTableFromFile (fp);
461   FileClose (fp);
462 
463   match.choice = eTableMatchNucID;
464   match.data = NULL;
465   match.match_location = String_location_equals;
466 
467   sequence_lists = GetSequenceListsForMatchTypeInTabTable (sep, table, 0, &match, &err_list);
468 
469   if (err_list != NULL) {
470     lip = OpenLog ("Table Problems");
471     for (vnp = err_list; vnp != NULL; vnp = vnp->next) {
472       fprintf (lip->fp, "%s\n", vnp->data.ptrvalue);
473     }
474     lip->data_in_log = TRUE;
475     CloseLog (lip);
476     lip = FreeLog (lip);
477     err_list = ValNodeFreeData (err_list);
478     if (ANS_YES != Message (MSG_YN, "Continue with table problems")) {
479       sequence_lists = FreeSequenceLists(sequence_lists);
480       table = FreeTabTable (table);
481       return;
482     }
483   }
484 
485   WatchCursor();
486   Update();
487   for (vnp_rs = sequence_lists, vnp_rt = table;
488        vnp_rs != NULL && vnp_rt != NULL;
489        vnp_rs = vnp_rs->next, vnp_rt = vnp_rt->next) {
490     vnp_s = vnp_rs->data.ptrvalue;
491     vnp_t = vnp_rt->data.ptrvalue;
492     if (vnp_s == NULL || vnp_t == NULL) {
493       continue;
494     }
495     vnp_t = vnp_t->next;
496     if (vnp_t == NULL || StringHasNoText (vnp_t->data.ptrvalue)) {
497       continue;
498     }
499     while (vnp_s != NULL) {
500       bsp = (BioseqPtr) vnp_s->data.ptrvalue;
501       gpid = GetGenomeProjectID (bsp);
502       if (gpid > 0) {
503         dbtag = DbtagNew ();
504         dbtag->db = MemNew (sizeof (Char) * (StringLen (id_fmt) + 15));
505         sprintf (dbtag->db, id_fmt, gpid);
506         dbtag->tag = ObjectIdNew ();
507         dbtag->tag->str = StringSave (vnp_t->data.ptrvalue);
508         sip_new = ValNodeNew (NULL);
509         sip_new->choice = SEQID_GENERAL;
510         sip_new->data.ptrvalue = dbtag;
511         sip_new->next = bsp->id;
512         bsp->id = sip_new;
513         SeqMgrReplaceInBioseqIndex (bsp);
514       }
515       vnp_s = vnp_s->next;
516     }
517   }
518   sequence_lists = FreeSequenceLists(sequence_lists);
519   table = FreeTabTable (table);
520   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
521   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
522   ArrowCursor();
523   Update();
524 
525 }
526 
527 
528 static void CreateBarcodeIDsFromLocalIDs (IteM i)
529 {
530   BaseFormPtr  bfp;
531   SeqEntryPtr  sep;
532 
533 #ifdef WIN_MAC
534   bfp = currentFormDataPtr;
535 #else
536   bfp = GetObjectExtra (i);
537 #endif
538   if (bfp == NULL) return;
539   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
540   if (sep == NULL) return;
541 
542   ConvertLocalIdsToBarcodeIds (sep);
543 
544   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
545   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
546 }
547 
548 
549 static void AddmRNASequenceCallback (SeqDescrPtr sdp, Pointer data)
550 {
551   Int4 len, len_add;
552   CharPtr add = ", mRNA sequence.", tmp, title;
553 
554   if (sdp != NULL && sdp->choice == Seq_descr_title) {
555     title = (CharPtr) sdp->data.ptrvalue;
556     len_add = StringLen (add);
557     len = StringLen (title);
558     if (len < len_add || StringCmp (title + (len - len_add), add) != 0) {
559       /* remove trailing period if present */
560       if (title[len - 1] == '.') {
561         title[len - 1] = 0;
562       }
563       tmp = (CharPtr) MemNew (sizeof (Char) * (len + len_add + 1));
564       sprintf (tmp, "%s%s", title, add);
565       sdp->data.ptrvalue = MemFree (sdp->data.ptrvalue);
566       sdp->data.ptrvalue = tmp;
567     }
568   }
569 }
570 
571 
572 static void AddmRNASequenceToDeflines (IteM i)
573 {
574   BaseFormPtr  bfp;
575   SeqEntryPtr  sep;
576 
577 #ifdef WIN_MAC
578   bfp = currentFormDataPtr;
579 #else
580   bfp = GetObjectExtra (i);
581 #endif
582   if (bfp == NULL) return;
583   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
584   if (sep == NULL) return;
585 
586   WatchCursor ();
587   Update ();
588 
589   AutoDefId (bfp->input_entityID);
590   SeqEntrySetScope (NULL);
591   VisitDescriptorsInSep (sep, NULL, AddmRNASequenceCallback);
592   ArrowCursor();
593   Update();
594 
595   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
596   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
597 }
598 
599 
600 static void SplitPubsByTable (IteM i)
601 {
602   BaseFormPtr  bfp;
603   SeqEntryPtr  sep;
604   FILE *fp;
605   ValNodePtr   tab_table, split_list;
606   ValNodePtr   err_list = NULL;
607   Char         path [PATH_MAX];
608 
609 #ifdef WIN_MAC
610   bfp = currentFormDataPtr;
611 #else
612   bfp = GetObjectExtra (i);
613 #endif
614   if (bfp == NULL) return;
615   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
616   if (sep == NULL) return;
617 
618   if (! GetInputFileName (path, sizeof (path), "", "TEXT")) return;
619   fp = FileOpen (path, "r");
620   if (fp == NULL) return;
621   tab_table = ReadTabTableFromFile (fp);
622   FileClose (fp);
623   split_list = MakeSplitPubListFromTabList (&tab_table, sep, &err_list);
624   tab_table = FreeTabTable (tab_table);
625   SplitPubsByList (split_list);
626   SplitPubListFree (split_list);
627   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
628   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
629   Update();  
630 }
631 
632 
633 #define DDBUFFERMAX 32768
634 
635 typedef struct fndeldata {
636   CharPtr     buffer;
637   CharPtr     curr;
638   Int4        seqlen;
639   Int4        gap_count;
640   Int4        bsp_length;
641   Boolean     in_gap;
642   Boolean     unk_gap;
643   ValNodePtr  head;
644   ValNodePtr  last;
645 } DelData, PNTR DelDataPtr;
646 
647 static void AddNextBlock (
648   DelDataPtr ddp
649 )
650 
651 {
652   ByteStorePtr  bs;
653   IntFuzzPtr    ifp;
654   SeqLitPtr     slitp;
655   CharPtr       str;
656   ValNodePtr    vnp;
657 
658   if (ddp == NULL) return;
659   if (ddp->in_gap) {
660     slitp = (SeqLitPtr) MemNew (sizeof (SeqLit));
661     if (slitp != NULL) {
662       slitp->length = ddp->gap_count;
663       ddp->bsp_length += slitp->length;
664       if (ddp->unk_gap) {
665         ifp = IntFuzzNew ();
666         if (ifp != NULL) {
667           ifp->choice = 4;
668           slitp->fuzz = ifp;
669         }
670       }
671       vnp = ValNodeAddPointer (&(ddp->last), 2, (Pointer) slitp);
672       if (ddp->head == NULL) {
673         ddp->head = vnp;
674       }
675       ddp->last = vnp;
676     }
677   } else if (ddp->seqlen > 0) {
678     str = ddp->curr;
679     if (str != NULL) {
680       *str = '\0';
681     }
682     bs = BSNew (ddp->seqlen);
683     if (bs != NULL) {
684       BSWrite (bs, (VoidPtr) ddp->buffer, ddp->seqlen);
685       slitp = (SeqLitPtr) MemNew (sizeof (SeqLit));
686       if (slitp != NULL) {
687         slitp->length = ddp->seqlen;
688         slitp->seq_data_type = Seq_code_iupacna;
689         slitp->seq_data = (SeqDataPtr) bs;
690         ddp->bsp_length += slitp->length;
691         vnp = ValNodeAddPointer (&(ddp->last), 2, (Pointer) slitp);
692         if (ddp->head == NULL) {
693           ddp->head = vnp;
694         }
695         ddp->last = vnp;
696       }
697     }
698   }
699 }
700 
701 static void LIBCALLBACK FarToNearCallback (
702   CharPtr sequence,
703   Pointer userdata
704 )
705 
706 {
707   Char        ch;
708   DelDataPtr  ddp;
709   CharPtr     ptr;
710   CharPtr     str;
711 
712   if (sequence == NULL || userdata == NULL) return;
713   ddp = (DelDataPtr) userdata;
714 
715   ptr = sequence;
716   ch = *ptr;
717   str = ddp->curr;
718 
719   while (ch != '\0') {
720     if (ch != '-' && ch != '+') {
721       if (ddp->in_gap) {
722         AddNextBlock (ddp);
723         ddp->in_gap = FALSE;
724         ddp->unk_gap = FALSE;
725         ddp->gap_count = 0;
726         ddp->curr = ddp->buffer;
727         ddp->seqlen = 0;
728         str = ddp->curr;
729       }
730       *str = ch;
731       str++;
732       (ddp->seqlen)++;
733       if (ddp->seqlen >= DDBUFFERMAX) {
734         *str = '\0';
735         ddp->curr = str;
736         AddNextBlock (ddp);
737         ddp->curr = ddp->buffer;
738         ddp->seqlen = 0;
739         str = ddp->curr;
740       }
741     } else {
742       if (! ddp->in_gap) {
743         AddNextBlock (ddp);
744         ddp->in_gap = TRUE;
745         ddp->unk_gap = (Boolean) (ch == '-');
746         ddp->gap_count = 0;
747         ddp->curr = ddp->buffer;
748         ddp->seqlen = 0;
749         str = ddp->curr;
750       }
751       (ddp->gap_count)++;
752     }
753 
754     ptr++;
755     ch = *ptr;
756   }
757   ddp->curr = str;
758 }
759 
760 static void FarToNearProc (BioseqPtr bsp, Pointer userdata)
761 
762 {
763   DelData  dd;
764   Pointer  olddelta;
765 
766   if (bsp == NULL || bsp->repr != Seq_repr_delta || bsp->seq_ext_type != 4) return;
767   MemSet ((Pointer) &dd, 0, sizeof (DelData));
768   dd.buffer = MemNew (sizeof (Char) * (DDBUFFERMAX + 2));
769   if (dd.buffer == NULL) return;
770   dd.curr = dd.buffer;
771   dd.seqlen = 0;
772   SeqPortStream (bsp, EXPAND_GAPS_TO_DASHES | KNOWN_GAP_AS_PLUS, (Pointer) &dd, FarToNearCallback);
773   AddNextBlock (&dd);
774   MemFree (dd.buffer);
775   olddelta = bsp->seq_ext;
776   bsp->seq_ext = (Pointer) dd.head;
777   if (dd.bsp_length != bsp->length) {
778     Message (MSG_OK, "Old length %ld differs from new length %ld",
779              (long) bsp->length, (long) dd.bsp_length);
780   }
781 }
782 
783 static void FarDeltaToNear (IteM i)
784 
785 {
786   BaseFormPtr  bfp;
787   SeqEntryPtr  sep;
788 
789 #ifdef WIN_MAC
790   bfp = currentFormDataPtr;
791 #else
792   bfp = GetObjectExtra (i);
793 #endif
794   if (bfp == NULL) return;
795   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
796   if (sep == NULL) return;
797   VisitBioseqsInSep (sep, NULL, FarToNearProc);
798   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
799   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
800   Message (MSG_OK, "Some manual desktop manipulations remain");
801 }
802 
803 static CharPtr HIVDBStart = "##HIVDataBaseData-START##";
804 static CharPtr HIVDBEnd = "##HIVDataBaseData-END##";
805 
806 static CharPtr HIVStart = "##HIVData-START##";
807 static CharPtr HIVEnd = "##HIVData-END##";
808 
809 static CharPtr FluStart = "##FluData-START##";
810 static CharPtr FluEnd = "##FluData-END##";
811 
812 
813 static void RemoveStructuredCommentFromString (CharPtr str, CharPtr prefix, CharPtr suffix)
814 {
815   CharPtr pPrefix, pSuffix, pAfter;
816 
817   if (StringHasNoText (str) || StringHasNoText (prefix) || StringHasNoText (suffix)) return;
818 
819   pPrefix = StringSearch (str, prefix);
820   pSuffix = StringSearch (str, suffix);
821   if (pPrefix == NULL || pSuffix == NULL || pPrefix >= pSuffix) return;
822 
823   pAfter = pSuffix + StringLen (suffix);
824   StringCpy (pPrefix, pAfter);
825 }
826 
827 
828 static void FindStructComment (SeqDescrPtr sdp, Pointer userdata)
829 
830 {
831   CharPtr        str;
832   UserObjectPtr  uop = NULL;
833   UserObjectPtr  PNTR uopp;
834   CharPtr        prefix = "", suffix = "";
835 
836   if (sdp == NULL || sdp->choice != Seq_descr_comment) return;
837   str = (CharPtr) sdp->data.ptrvalue;
838   if (StringHasNoText (str)) return;
839   uopp = (UserObjectPtr PNTR) userdata;
840   if (uopp == NULL) return;
841 
842   if (StringStr (str, HIVDBStart) != NULL) {
843     prefix = HIVDBStart;
844     suffix = HIVDBEnd;
845   } else if (StringStr (str, HIVStart) != NULL) {
846     prefix = HIVStart;
847     suffix = HIVEnd;
848   } else if (StringStr (str, FluStart) != NULL) {
849     prefix = FluStart;
850     prefix = FluEnd;
851   }
852 
853   uop = ParseStringIntoStructuredComment (NULL, str, prefix, suffix);
854 
855   if (uop != NULL) {
856     *uopp = uop;
857     RemoveStructuredCommentFromString (str, prefix, suffix);
858     if (StringHasNoText (str) && sdp->extended != 0) {
859       ((ObjValNodePtr)sdp)->idx.deleteme = TRUE;
860     }
861   }
862 }
863 
864 static void DoStructCommentBsp (BioseqPtr bsp, Pointer userdata)
865 
866 {
867   SeqDescrPtr    sdp;
868   UserObjectPtr  uop = NULL;
869 
870   VisitDescriptorsOnBsp (bsp, (Pointer) &uop, FindStructComment);
871   if (uop == NULL) return;
872   sdp = CreateNewDescriptorOnBioseq (bsp, Seq_descr_user);
873   if (sdp == NULL) return;
874   sdp->data.ptrvalue = uop;
875 }
876 
877 static void ParseCommentIntoStructuredObject (IteM i)
878 
879 {
880   BaseFormPtr  bfp;
881   SeqEntryPtr  sep;
882 
883 #ifdef WIN_MAC
884   bfp = currentFormDataPtr;
885 #else
886   bfp = GetObjectExtra (i);
887 #endif
888   if (bfp == NULL) return;
889   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
890   if (sep == NULL) return;
891 
892   VisitBioseqsInSep (sep, NULL, DoStructCommentBsp);
893 
894   DeleteMarkedObjects (bfp->input_entityID, 0, NULL);
895   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
896   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
897   Update ();
898 }
899 
900 static void DoHivOrFluTag (SeqDescrPtr sdp, Pointer userdata, CharPtr prefix, CharPtr suffix)
901 
902 {
903   UserFieldPtr   curr;
904   Boolean        hasPrefix = FALSE;
905   Boolean        hasSuffix = FALSE;
906   ObjectIdPtr    oip;
907   UserObjectPtr  uop;
908 
909   if (sdp == NULL || sdp->choice != Seq_descr_user) return;
910   uop = (UserObjectPtr) sdp->data.ptrvalue;
911   if (uop == NULL) return;
912   oip = uop->type;
913   if (oip == NULL || StringICmp (oip->str, "StructuredComment") != 0) return;
914 
915   for (curr = uop->data; curr != NULL; curr = curr->next) {
916     oip = curr->label;
917     if (oip != NULL && StringICmp (oip->str, "StructuredCommentPrefix") == 0) {
918       hasPrefix = TRUE;
919       if (curr->choice == 1) {
920         MemFree (curr->data.ptrvalue);
921         curr->data.ptrvalue = (Pointer) StringSave (prefix);
922       }
923     }
924   }
925   if (! hasPrefix) {
926     AddItemStructuredCommentUserObject (uop, "StructuredCommentPrefix", prefix);
927   }
928 
929   for (curr = uop->data; curr != NULL; curr = curr->next) {
930     oip = curr->label;
931     if (oip != NULL && StringICmp (oip->str, "StructuredCommentSuffix") == 0) {
932       hasSuffix = TRUE;
933       if (curr->choice == 1) {
934         MemFree (curr->data.ptrvalue);
935         curr->data.ptrvalue = (Pointer) StringSave (suffix);
936       }
937     }
938   }
939   if (! hasSuffix) {
940     AddItemStructuredCommentUserObject (uop, "StructuredCommentSuffix", suffix);
941   }
942 }
943 
944 static void DoHivTag (SeqDescrPtr sdp, Pointer userdata)
945 
946 {
947   DoHivOrFluTag (sdp, userdata, "##HIVData-START##", "##HIVData-END##");
948 }
949 
950 static void DoFluTag (SeqDescrPtr sdp, Pointer userdata)
951 
952 {
953   DoHivOrFluTag (sdp, userdata, "##FluData-START##", "##FluData-END##");
954 }
955 
956 static void AddStructuredCommentHivTag (IteM i)
957 
958 {
959   BaseFormPtr  bfp;
960   SeqEntryPtr  sep;
961 
962 #ifdef WIN_MAC
963   bfp = currentFormDataPtr;
964 #else
965   bfp = GetObjectExtra (i);
966 #endif
967   if (bfp == NULL) return;
968   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
969   if (sep == NULL) return;
970 
971   VisitDescriptorsInSep (sep, NULL, DoHivTag);
972 
973   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
974   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
975   Update ();
976 }
977 
978 static void AddStructuredCommentFluTag (IteM i)
979 
980 {
981   BaseFormPtr  bfp;
982   SeqEntryPtr  sep;
983 
984 #ifdef WIN_MAC
985   bfp = currentFormDataPtr;
986 #else
987   bfp = GetObjectExtra (i);
988 #endif
989   if (bfp == NULL) return;
990   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
991   if (sep == NULL) return;
992 
993   VisitDescriptorsInSep (sep, NULL, DoFluTag);
994 
995   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
996   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
997   Update ();
998 }
999 
1000 static void ConvertBadInfProc (SeqFeatPtr sfp, Pointer userdata)
1001 
1002 {
1003   GBQualPtr  gbq;
1004   size_t     len;
1005   CharPtr    ptr, str;
1006 
1007   if (sfp == NULL) return;
1008   for (gbq = sfp->qual; gbq != NULL; gbq = gbq->next) {
1009     if (StringICmp (gbq->qual, "inference") != 0) continue;
1010     if (ValidateInferenceQualifier (gbq->val, FALSE) != VALID_INFERENCE) {
1011       if (StringNICmp (gbq->val, "similar to ", 11) == 0) {
1012         ptr = StringChr (gbq->val, ':');
1013         if (ptr != NULL) {
1014           ptr++;
1015           if (StringDoesHaveText (ptr)) {
1016             len = StringLen ("similar to ") + StringLen (ptr);
1017             str = MemNew (len + 5);
1018             if (str != NULL) {
1019               StringCpy (str, "similar to ");
1020               StringCat (str, ptr);
1021               gbq->val = MemFree (gbq->val);
1022               gbq->val = StringSave (str);
1023               MemFree (str);
1024             }
1025           }
1026         }
1027       }
1028       gbq->qual = MemFree (gbq->qual);
1029       gbq->qual = StringSave ("note");
1030     }
1031   }
1032 }
1033 
1034 static void ConvertBadInferenceToNote (IteM i)
1035 
1036 {
1037   BaseFormPtr  bfp;
1038   SeqEntryPtr  sep;
1039 
1040 #ifdef WIN_MAC
1041   bfp = currentFormDataPtr;
1042 #else
1043   bfp = GetObjectExtra (i);
1044 #endif
1045   if (bfp == NULL) return;
1046 
1047   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1048   
1049   VisitFeaturesInSep (sep, NULL, ConvertBadInfProc);
1050   
1051   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1052   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1053   Update (); 
1054 }
1055 
1056 typedef struct {
1057   Int2    level;
1058   Boolean prevWasModified;
1059 } VecToNData, PNTR VecToNDataPtr;
1060 
1061 typedef struct {
1062   Boolean dirtyFlag;
1063   Int2    number;
1064 } CdsDelStruct, PNTR CdsDelStructPtr;
1065 
1066 typedef struct {
1067   FORM_MESSAGE_BLOCK
1068   Int2  number;
1069 } CdsDelForm, PNTR CdsDelFormPtr;
1070 
1071 static void AddOrgNameToDefLines (IteM i)
1072 
1073 {
1074   CommonAddOrgOrModsToDefLines (i, 0, 0, NULL);
1075 }
1076 
1077 static void AddStrainToDefLines (IteM i)
1078 
1079 {
1080   CommonAddOrgOrModsToDefLines (i, ORGMOD_strain, 0, NULL);
1081 }
1082 
1083 static void AddCloneToDefLines (IteM i)
1084 
1085 {
1086   CommonAddOrgOrModsToDefLines (i, 0, SUBSRC_clone, NULL);
1087 }
1088 
1089 static void AddIsolateToDefLines (IteM i)
1090 
1091 {
1092   CommonAddOrgOrModsToDefLines (i, ORGMOD_isolate, 0, NULL);
1093 }
1094 
1095 static void AddHaplotypeToDefLines (IteM i)
1096 
1097 {
1098   CommonAddOrgOrModsToDefLines (i, 0, SUBSRC_haplotype, NULL);
1099 }
1100 
1101 static void AddCultivarToDefLines (IteM i)
1102 
1103 {
1104   CommonAddOrgOrModsToDefLines (i, ORGMOD_cultivar, 0, NULL);
1105 }
1106 
1107 static Boolean FindBestCitSubCallback (GatherContextPtr gcp)
1108 
1109 {
1110   CitSubPtr   best;
1111   CitSubPtr   PNTR bestp;
1112   CitSubPtr   csp;
1113   PubdescPtr  pdp;
1114   ValNodePtr  sdp;
1115   ValNodePtr  vnp;
1116 
1117   if (gcp == NULL) return TRUE;
1118   bestp = (CitSubPtr PNTR) gcp->userdata;
1119   if (bestp == NULL) return TRUE;
1120   if (gcp->thistype != OBJ_SEQDESC) return TRUE;
1121   sdp = (ValNodePtr) gcp->thisitem;
1122   if (sdp == NULL || sdp->choice != Seq_descr_pub) return TRUE;
1123   pdp = (PubdescPtr) sdp->data.ptrvalue;
1124   if (pdp == NULL) return TRUE;
1125   vnp = pdp->pub;
1126   if (vnp == NULL || vnp->choice != PUB_Sub) return TRUE;
1127   csp = (CitSubPtr) vnp->data.ptrvalue;
1128   if (csp == NULL) return TRUE;
1129   if (*bestp == NULL) {
1130     *bestp = csp;
1131     return TRUE;
1132   }
1133   best = *bestp;
1134   if (DateMatch (best->date, csp->date, FALSE) == -1) {
1135     *bestp = csp;
1136     return TRUE;
1137   }
1138   return TRUE;
1139 }
1140 
1141 CharPtr kSubmitterUpdateText = "Sequence update by submitter";
1142 CharPtr kIndexerUpdateVecScreenText = "Sequence update by database staff to remove vector contamination";
1143 
1144 extern Boolean CreateUpdateCitSubFromBestTemplate (
1145   SeqEntryPtr top_sep,
1146   SeqEntryPtr upd_sep,
1147   CharPtr     update_txt
1148 )
1149 {
1150   CitSubPtr    best;
1151   CitSubPtr    csp;
1152   DatePtr      dp;
1153   GatherScope  gs;
1154   PubdescPtr   pdp;
1155   ValNodePtr   sdp;
1156   ValNodePtr   vnp;
1157 
1158   best = NULL;
1159   MemSet ((Pointer) (&gs), 0, sizeof (GatherScope));
1160   gs.seglevels = 1;
1161   gs.get_feats_location = FALSE;
1162   MemSet ((Pointer) (gs.ignore), (int)(TRUE), (size_t) (OBJ_MAX * sizeof(Boolean)));
1163   gs.ignore[OBJ_BIOSEQ] = FALSE;
1164   gs.ignore[OBJ_BIOSEQ_SEG] = FALSE;
1165   gs.ignore[OBJ_SEQDESC] = FALSE;
1166   gs.scope = top_sep;
1167   GatherSeqEntry (top_sep, (Pointer) (&best), FindBestCitSubCallback, &gs);
1168   if (best == NULL) {
1169     Message (MSG_OK, "There is no earlier cit-sub template");
1170     return FALSE;
1171   }
1172   dp = DateCurr ();
1173   if (dp != NULL) {
1174     if (DateMatch (best->date, dp, FALSE) == 0) {
1175       DateFree (dp);
1176             dp = NULL;
1177       if (upd_sep == top_sep
1178           && StringICmp (best->descr, update_txt) == 0)
1179       {
1180         Message (MSG_OK, "There already exists an update on today's date");
1181         Update ();
1182         return FALSE;
1183       } else if (best->descr == NULL) {
1184         best->descr = StringSave (update_txt);
1185         Message (MSG_OK, "Adding update indication to existing cit-sub");
1186         return TRUE;
1187       }
1188     }
1189     DateFree (dp);
1190   }
1191   sdp = CreateNewDescriptor (upd_sep, Seq_descr_pub);
1192   if (sdp == NULL) return FALSE;
1193   pdp = PubdescNew ();
1194   if (pdp == NULL) return FALSE;
1195   sdp->data.ptrvalue = (Pointer) pdp;
1196   vnp = ValNodeNew (NULL);
1197   csp = AsnIoMemCopy ((Pointer) best,
1198                       (AsnReadFunc) CitSubAsnRead,
1199                       (AsnWriteFunc) CitSubAsnWrite);
1200   pdp->pub = vnp;
1201   vnp->choice = PUB_Sub;
1202   vnp->data.ptrvalue = csp;
1203   csp->date = DateFree (csp->date);
1204   csp->date = DateCurr ();
1205   if (!StringHasNoText (update_txt)) {
1206     csp->descr = MemFree (csp->descr);
1207     csp->descr = StringSave (update_txt);
1208   }
1209 
1210   if (top_sep == upd_sep)
1211   {
1212     Message (MSG_OK, "The update Cit-sub has been placed on the top Seq-entry");
1213   }
1214   return TRUE;
1215 }                               
1216 
1217 static void AddCitSubForUpdateProc (BaseFormPtr bfp)
1218 
1219 {
1220   SeqEntryPtr  sep;
1221 
1222   if (bfp == NULL) return;
1223   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1224   if (sep == NULL) return;
1225 
1226   if ( CreateUpdateCitSubFromBestTemplate (sep, sep, kSubmitterUpdateText))
1227   {
1228     ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1229     ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1230     Update ();
1231   }
1232   return;
1233 }
1234 
1235 static void AddCitSubForUpdate (IteM i)
1236 
1237 {
1238   BaseFormPtr  bfp;
1239 
1240 #ifdef WIN_MAC
1241   bfp = currentFormDataPtr;
1242 #else
1243   bfp = GetObjectExtra (i);
1244 #endif
1245   AddCitSubForUpdateProc (bfp);
1246 }
1247 
1248 /* FixLocus is copied from taxutil, then modified to remove embl_code use */
1249 static void FixLocus (SeqEntryPtr sep, Pointer data, Int4 index, Int2 indent)
1250 {
1251         BioseqPtr bsp;
1252         ValNodePtr vnp;
1253     TextSeqIdPtr tsip;
1254     Char tbuf[40];
1255         CharPtr ptr, embl_code;
1256 
1257         if (! IS_Bioseq(sep))
1258                 return;
1259 
1260         bsp = (BioseqPtr)(sep->data.ptrvalue);
1261     embl_code = (CharPtr) data;
1262         /* if (! embl_code) return; */
1263 
1264     for (vnp = bsp->id; vnp != NULL; vnp = vnp->next) {
1265                 if ((vnp->choice == SEQID_GENBANK || vnp->choice == SEQID_TPG) && vnp->data.ptrvalue != NULL) {
1266                         tsip = (TextSeqIdPtr) (vnp->data.ptrvalue);
1267                         if (tsip->accession != NULL)
1268                         {
1269                                 tsip->name = MemFree (tsip->name);
1270                                 if (bsp->repr != Seq_repr_seg) {
1271                                         /* ptr = StringMove (tbuf, embl_code); */
1272                                         ptr = tbuf;
1273                                         StringMove (ptr, tsip->accession);
1274                                         tsip->name = StringSave (tbuf);
1275                                         SeqMgrReplaceInBioseqIndex (bsp);
1276                                 }
1277                                 return;
1278                         }
1279                 }
1280         }
1281         
1282         return;
1283 }
1284 
1285 extern void DoFixupLocus (SeqEntryPtr sep);
1286 extern void DoFixupLocus (SeqEntryPtr sep)
1287 
1288 {
1289   BioSourcePtr  biop;
1290   BioseqSetPtr  bssp;
1291   CharPtr       embl_code;
1292   OrgRefPtr     orp;
1293   ValNodePtr    sdp;
1294 
1295   if (IS_Bioseq_set (sep)) {
1296     bssp = (BioseqSetPtr) sep->data.ptrvalue;
1297     if (bssp != NULL && (bssp->_class == 7 ||
1298                          (IsPopPhyEtcSet (bssp->_class)))) {
1299       for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
1300         DoFixupLocus (sep);
1301       }
1302       return;
1303     }
1304   }
1305   sdp = SeqEntryGetSeqDescr (sep, Seq_descr_source, NULL);
1306   if (sdp == NULL) return;
1307   biop = (BioSourcePtr) sdp->data.ptrvalue;
1308   if (biop == NULL) return;
1309   orp = biop->org;
1310   if (orp == NULL) return;
1311   /* embl_code = get_embl_code (orp); */
1312   embl_code = NULL;
1313   SeqEntryExplore (sep, (Pointer) embl_code, FixLocus);
1314   MemFree (embl_code);
1315 }
1316 
1317 static TextSeqIdPtr GetTSIPforBSP (BioseqPtr bsp)
1318 
1319 {
1320   SeqIdPtr      sip;
1321   TextSeqIdPtr  tsip = NULL;
1322 
1323   if (bsp == NULL) return NULL;
1324 
1325   for (sip = bsp->id; sip != NULL; sip = sip->next) {
1326     if (sip->choice == SEQID_GENBANK || sip->choice == SEQID_TPG) {
1327       tsip = (TextSeqIdPtr) sip->data.ptrvalue;
1328     }
1329   }
1330 
1331   return tsip;
1332 }
1333 
1334 static void DoFixPartLocus (SeqEntryPtr sep, CharPtr prefix, Int2 segment, Int2 digits)
1335 
1336 {
1337   BioseqPtr     bsp;
1338   Char          ch;
1339   Char          digs [16];
1340   CharPtr       ptr;
1341   Char          str [32];
1342   TextSeqIdPtr  tsip;
1343 
1344   if (sep == NULL || prefix == NULL) return;
1345   if (! IS_Bioseq (sep)) return;
1346   bsp = (BioseqPtr) sep->data.ptrvalue;
1347   if (bsp == NULL) return;
1348   if (bsp->repr != Seq_repr_raw && bsp->repr != Seq_repr_const) return;
1349   tsip = GetTSIPforBSP (bsp);
1350   if (tsip == NULL) return;
1351   tsip->name = MemFree (tsip->name);
1352   sprintf (digs, "%*d", (int) digits, (int) segment);
1353   ptr = digs;
1354   ch = *ptr;
1355   while (ch != '\0') {
1356     if (ch == ' ') {
1357       *ptr = '0';
1358     }
1359     ptr++;
1360     ch = *ptr;
1361   }
1362   sprintf (str, "%sS%s", prefix, digs);
1363   tsip->name = StringSave (str);
1364 }
1365 
1366 extern void DoFixupSegSet (SeqEntryPtr sep);
1367 extern void DoFixupSegSet (SeqEntryPtr sep)
1368 
1369 {
1370   CharPtr       accn;
1371   Uint1         chs;
1372   Int2          digits;
1373   BioseqPtr     nbsp;
1374   BioseqSetPtr  bssp;
1375   size_t        len;
1376   SeqEntryPtr   nsep;
1377   Int2          numsegs;
1378   BioseqSetPtr  pbssp;
1379   CharPtr       prefix;
1380   SeqEntryPtr   psep;
1381   BioseqPtr     sbsp;
1382   Int2          segment;
1383   SeqIdPtr      sip;
1384   Char          str [32];
1385   Char          tmp [128];
1386   TextSeqIdPtr  tsip;
1387 
1388   if (! IS_Bioseq_set (sep)) return;
1389   bssp = (BioseqSetPtr) sep->data.ptrvalue;
1390   if (bssp == NULL) return;
1391   if (bssp->_class != BioseqseqSet_class_segset) {
1392     for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
1393       DoFixupSegSet (sep);
1394     }
1395     return;
1396   }
1397   nsep = FindNucSeqEntry (sep);
1398   if (nsep == NULL) return;
1399   if (! IS_Bioseq (nsep)) return;
1400   nbsp = (BioseqPtr) nsep->data.ptrvalue;
1401   if (nbsp == NULL) return;
1402   if (nbsp->repr != Seq_repr_seg) return;
1403   sbsp = NULL;
1404   tsip = GetTSIPforBSP (nbsp);
1405   if (tsip == NULL || StringHasNoText (tsip->accession)) {
1406     sbsp = nbsp;
1407     nsep = FindNthSeqEntry (sep, 4);
1408     if (nsep == NULL) return;
1409     if (! IS_Bioseq (nsep)) return;
1410     nbsp = (BioseqPtr) nsep->data.ptrvalue;
1411     if (nbsp == NULL) return;
1412     if (nbsp->repr != Seq_repr_raw && nbsp->repr != Seq_repr_const) return;
1413     tsip = GetTSIPforBSP (nbsp);
1414   }
1415   if (tsip == NULL) return;
1416   chs = SEQID_GENBANK;
1417   for (sip = nbsp->id; sip != NULL; sip = sip->next) {
1418     if (sip->choice == SEQID_GENBANK || sip->choice == SEQID_TPG) {
1419       chs = sip->choice;
1420     }
1421   }
1422   accn = tsip->accession;
1423   if (StringHasNoText (accn)) return;
1424   psep = FindBioseqSetByClass (sep, BioseqseqSet_class_parts);
1425   if (psep == NULL) return;
1426   pbssp = (BioseqSetPtr) psep->data.ptrvalue;
1427   if (pbssp == NULL) return;
1428   for (sep = pbssp->seq_set, numsegs = 0; sep != NULL; sep = sep->next, numsegs++) continue;
1429   StringNCpy_0 (tmp, accn, sizeof (tmp));
1430   prefix = tmp;
1431   len = StringLen (prefix);
1432   if (numsegs > 999) {
1433     digits = 4;
1434   } else if (numsegs > 99) {
1435     digits = 3;
1436   } else if (numsegs > 9) {
1437     digits = 2;
1438   } else {
1439     digits = 1;
1440   }
1441   if (digits + 1 + len > 16) {
1442     prefix += digits + 1 + len - 16;
1443   }
1444   
1445   for (sep = pbssp->seq_set, segment = 1; sep != NULL; sep = sep->next, segment++) {
1446     DoFixPartLocus (sep, prefix, segment, digits);
1447   }
1448   
1449   if (sbsp == NULL) return;
1450   tsip = NULL;
1451   for (sip = sbsp->id; sip != NULL; sip = sip->next) {
1452     if (sip->choice == SEQID_GENBANK || sip->choice == SEQID_TPG) {
1453       tsip = (TextSeqIdPtr) sip->data.ptrvalue;
1454     }
1455   }
1456   if (tsip == NULL) {
1457     tsip = TextSeqIdNew ();
1458     if (tsip == NULL) return;
1459     ValNodeAddPointer (&(sbsp->id), chs, (Pointer) tsip);
1460   }
1461   tsip->name = MemFree (tsip->name);
1462   sprintf (str, "SEG_%sS", prefix);
1463   tsip->name = StringSave (str);
1464   SeqMgrReplaceInBioseqIndex (sbsp);
1465 }
1466 
1467 static void ForceLocusFixup (IteM i)
1468 
1469 {
1470   BaseFormPtr  bfp;
1471   SeqEntryPtr  sep;
1472   ErrSev       sev;
1473 
1474 #ifdef WIN_MAC
1475   bfp = currentFormDataPtr;
1476 #else
1477   bfp = GetObjectExtra (i);
1478 #endif
1479   if (bfp == NULL) return;
1480   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1481   if (sep == NULL) return;
1482   sev = ErrSetMessageLevel (SEV_FATAL);
1483   WatchCursor ();
1484   Update ();
1485   DoFixupLocus (sep);
1486   DoFixupSegSet (sep);
1487   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1488   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1489   ArrowCursor ();
1490   Update ();
1491   ErrSetMessageLevel (sev);
1492   ErrClear ();
1493   ErrShow ();
1494 }
1495 
1496 extern void GetRidOfRedundantSourceNotes (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent);
1497 
1498 static void CleanupGenbankBlockCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
1499 
1500 {
1501   BioseqPtr      bsp;
1502   BioseqSetPtr   bssp;
1503   Boolean        empty;
1504   GBBlockPtr     gbp;
1505   ValNodePtr     nextsdp;
1506   Pointer PNTR   prevsdp;
1507   ValNodePtr     sdp;
1508 
1509   if (sep == NULL || sep->data.ptrvalue == NULL) return;
1510   if (IS_Bioseq (sep)) {
1511     bsp = (BioseqPtr) sep->data.ptrvalue;
1512     sdp = bsp->descr;
1513     prevsdp = (Pointer PNTR) &(bsp->descr);
1514   } else if (IS_Bioseq_set (sep)) {
1515     bssp = (BioseqSetPtr) sep->data.ptrvalue;
1516     sdp = bssp->descr;
1517     prevsdp = (Pointer PNTR) &(bssp->descr);
1518   } else return;
1519   while (sdp != NULL) {
1520     nextsdp = sdp->next;
1521     empty = FALSE;
1522     if (sdp->choice == Seq_descr_genbank && sdp->data.ptrvalue == NULL) {
1523       empty = TRUE;
1524     } else if (sdp->choice == Seq_descr_genbank && sdp->data.ptrvalue != NULL) {
1525       gbp = (GBBlockPtr) sdp->data.ptrvalue;
1526       gbp->source = MemFree (gbp->source); /* remove within Sequin */
1527       gbp->origin = MemFree (gbp->origin);
1528       gbp->taxonomy = MemFree (gbp->taxonomy);
1529       if (gbp->extra_accessions == NULL && gbp->source == NULL &&
1530           gbp->keywords == NULL && gbp->origin == NULL &&
1531           gbp->date == NULL && gbp->entry_date == NULL &&
1532           gbp->div == NULL && gbp->taxonomy == NULL) {
1533         empty = TRUE;
1534       }
1535     }
1536     if (empty) {
1537       *(prevsdp) = sdp->next;
1538       sdp->next = NULL;
1539       SeqDescFree (sdp);
1540     } else {
1541       prevsdp = (Pointer PNTR) &(sdp->next);
1542     }
1543     sdp = nextsdp;
1544   }
1545 }
1546 
1547 static void CheckBioSourceForEnvironmentalSample (BioSourcePtr biop, Pointer userdata)
1548 {
1549   BoolPtr bp;
1550   
1551   if (biop == NULL || userdata == NULL) return;
1552   
1553   bp = (BoolPtr) userdata;
1554   if (! *bp) return;
1555   
1556   if (biop->org == NULL || biop->org->orgname == NULL)
1557   {
1558         *bp = FALSE;
1559         return;
1560   }
1561   if (StringSearch (biop->org->orgname->lineage, "environmental sample") == NULL)
1562   {
1563         *bp = FALSE;
1564   }
1565 }
1566 
1567 static Boolean CheckForEnvironmentalSample (BioseqSetPtr bssp)
1568 {
1569   Boolean all_enviro = TRUE;
1570   
1571   if (bssp == NULL) return FALSE;
1572   
1573   VisitBioSourcesInSet (bssp, (Pointer) &all_enviro, CheckBioSourceForEnvironmentalSample);
1574    
1575   return all_enviro; 
1576 }
1577 
1578 
1579 static void ConvertToEcoSets (SeqEntryPtr sep)
1580 {
1581   BioseqSetPtr bssp;
1582   SeqEntryPtr  sep_entry;
1583   
1584   if (sep == NULL) return;
1585   
1586   if (!IS_Bioseq_set (sep)) return;
1587   bssp = (BioseqSetPtr) sep->data.ptrvalue;
1588   if (bssp == NULL) return;
1589   
1590   if (bssp->_class == BioseqseqSet_class_mut_set
1591       || bssp->_class == BioseqseqSet_class_pop_set 
1592       || bssp->_class == BioseqseqSet_class_phy_set)
1593   {
1594         if (CheckForEnvironmentalSample (bssp))
1595         {
1596           bssp->_class = BioseqseqSet_class_eco_set;
1597         }
1598   }
1599   for (sep_entry = bssp->seq_set; sep_entry != NULL; sep_entry = sep_entry->next)
1600   {
1601         if (IS_Bioseq_set (sep_entry))
1602         {
1603           ConvertToEcoSets (sep_entry);
1604         }
1605   }
1606 }
1607 
1608 static void AddQualsFromLineageAndDiv (BioSourcePtr biop, Pointer userdata)
1609 {
1610   ValNode      vn;
1611   
1612   if (biop == NULL || biop->org == NULL || biop->org->orgname == NULL) return;
1613 
1614   if (StringISearch (biop->org->orgname->lineage, "environmental sample") != NULL
1615       || StringCmp (biop->org->orgname->div, "ENV") == 0)
1616   {
1617     vn.choice = SourceQualChoice_textqual;
1618     vn.data.intvalue = Source_qual_environmental_sample;
1619     vn.next = NULL;
1620     SetSourceQualInBioSource (biop, &vn, NULL, "", ExistingTextOption_replace_old);
1621   }
1622   if (StringISearch (biop->org->orgname->lineage, "metagenomes") != NULL) {
1623     vn.choice = SourceQualChoice_textqual;
1624     vn.data.intvalue = Source_qual_metagenomic;
1625     vn.next = NULL;
1626     SetSourceQualInBioSource (biop, &vn, NULL, "", ExistingTextOption_replace_old);
1627   }
1628 }
1629 
1630 extern void ForceCleanupEntityID (Uint2 entityID)
1631 
1632 {
1633   SeqEntryPtr   sep;
1634   ModTextFixPtr tfp;
1635 
1636   sep = GetTopSeqEntryForEntityID (entityID);
1637   if (sep == NULL) return;
1638   SeqMgrClearFeatureIndexes (entityID, NULL);
1639   SeqEntryExplore (sep, NULL, CleanupGenbankBlockCallback);
1640   SeqEntryExplore (sep, NULL, CleanupEmptyFeatCallback);
1641   SeqEntryExplore (sep, NULL, MergeAdjacentAnnotsCallback);
1642   MySeqEntryToAsn3 (sep, TRUE, FALSE, TRUE);
1643   CorrectGenCodes (sep, entityID);
1644   CleanUpPseudoProducts (entityID, sep);
1645   SeqEntryExplore (sep, NULL, GetRidOfRedundantSourceNotes);
1646   RenormalizeNucProtSets (sep, TRUE);
1647   CdCheck (sep, NULL);
1648   ConvertToEcoSets (sep);
1649   VisitBioSourcesInSep (sep, NULL, AddQualsFromLineageAndDiv);
1650   tfp = ModTextFixNew ();
1651   VisitBioSourcesInSep (sep, tfp, RemoveTextFromTextFreeSubSourceModifiers);
1652   MemFree (tfp);
1653   ObjMgrSetDirtyFlag (entityID, TRUE);
1654   ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
1655   ObjMgrDeSelect (0, 0, 0, 0, NULL);
1656 }
1657 
1658 static void ForceCleanupBtn (IteM i, ButtoN b, Boolean validate)
1659 
1660 {
1661   BaseFormPtr   bfp;
1662 
1663   if (b != NULL) {
1664     bfp = GetObjectExtra (b);
1665   } else {
1666 #ifdef WIN_MAC
1667     bfp = currentFormDataPtr;
1668 #else
1669     bfp = GetObjectExtra (i);
1670 #endif
1671   }
1672   if (bfp == NULL) return;
1673   ForceCleanupEntityID (bfp->input_entityID);
1674   if (validate) {
1675     ValSeqEntryForm (bfp->form);
1676   }
1677 }
1678 
1679 
1680 static void ForceCleanup (IteM i)
1681 
1682 {
1683   ForceCleanupBtn (i, NULL, TRUE);
1684 }
1685 
1686 static void MapWholeToInt (SeqFeatPtr sfp, Pointer userdata)
1687 
1688 {
1689   BioseqPtr  bsp;
1690   SeqLocPtr  location;
1691   SeqIntPtr  sint;
1692   SeqIdPtr   sip;
1693 
1694   if (sfp == NULL) return;
1695   location = sfp->location;
1696   if (location == NULL) return;
1697   if (location->choice != SEQLOC_WHOLE) return;
1698   sip = SeqLocId (location);
1699   if (sip == NULL) return;
1700   bsp = BioseqFind (sip);
1701   if (bsp == NULL) return;
1702   sint = SeqIntNew ();
1703   if (sint == NULL) return;
1704   sint->from = 0;
1705   sint->to = bsp->length - 1;
1706   sint->id = SeqIdDup (sip);
1707   location = ValNodeAddPointer (NULL, SEQLOC_INT, (Pointer) sint);
1708   sfp->location = SeqLocFree (sfp->location);
1709   sfp->location = location;
1710 }
1711 
1712 static void ConvertWholeToInterval (IteM i)
1713 
1714 {
1715   BaseFormPtr  bfp;
1716   SeqEntryPtr  sep;
1717 
1718 #ifdef WIN_MAC
1719   bfp = currentFormDataPtr;
1720 #else
1721   bfp = GetObjectExtra (i);
1722 #endif
1723   if (bfp == NULL) return;
1724   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1725   if (sep == NULL) return;
1726   VisitFeaturesInSep (sep, NULL, MapWholeToInt);
1727   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1728   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1729   ObjMgrDeSelect (0, 0, 0, 0, NULL);
1730 }
1731 
1732 static void CorrectBothStrands (SeqFeatPtr sfp, Pointer userdata)
1733 
1734 {
1735   SeqLocPtr  location, slp = NULL;
1736   SeqIntPtr  sint;
1737   SeqPntPtr  spp;
1738 
1739   if (sfp == NULL) return;
1740   location = sfp->location;
1741   if (location == NULL) return;
1742 
1743   while ((slp = SeqLocFindNext (location, slp)) != NULL) {
1744     switch (slp->choice) {
1745       case SEQLOC_INT :
1746         sint = (SeqIntPtr) slp->data.ptrvalue;
1747         if (sint != NULL) {
1748           if (sint->strand == Seq_strand_both) {
1749             sint->strand = Seq_strand_plus;
1750           } else if (sint->strand == Seq_strand_both_rev) {
1751             sint->strand = Seq_strand_minus;
1752           }
1753         }
1754         break;
1755       case SEQLOC_PNT :
1756         spp = (SeqPntPtr) slp->data.ptrvalue;
1757         if (spp != NULL) {
1758           if (spp->strand == Seq_strand_both) {
1759             spp->strand = Seq_strand_plus;
1760           } else if (spp->strand == Seq_strand_both_rev) {
1761             spp->strand = Seq_strand_minus;
1762           }
1763         }
1764         break;
1765       default :
1766         break;
1767     }
1768   }
1769 }
1770 
1771 static void ConvertBothStrands (IteM i)
1772 
1773 {
1774   BaseFormPtr  bfp;
1775   SeqEntryPtr  sep;
1776 
1777 #ifdef WIN_MAC
1778   bfp = currentFormDataPtr;
1779 #else
1780   bfp = GetObjectExtra (i);
1781 #endif
1782   if (bfp == NULL) return;
1783   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1784   if (sep == NULL) return;
1785   VisitFeaturesInSep (sep, NULL, CorrectBothStrands);
1786   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1787   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1788   ObjMgrDeSelect (0, 0, 0, 0, NULL);
1789 }
1790 
1791 static void AssignFeatIDs (IteM i)
1792 
1793 {
1794   BaseFormPtr  bfp;
1795   SeqEntryPtr  sep;
1796 
1797 #ifdef WIN_MAC
1798   bfp = currentFormDataPtr;
1799 #else
1800   bfp = GetObjectExtra (i);
1801 #endif
1802   if (bfp == NULL) return;
1803   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1804   if (sep == NULL) return;
1805 
1806   AssignFeatureIDs (sep);
1807 
1808   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1809   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1810   ObjMgrDeSelect (0, 0, 0, 0, NULL);
1811   Update ();
1812 }
1813 
1814 static void ReassignFeatIDs (IteM i)
1815 
1816 {
1817   MsgAnswer    ans;
1818   BaseFormPtr  bfp;
1819   SeqEntryPtr  sep;
1820 
1821 #ifdef WIN_MAC
1822   bfp = currentFormDataPtr;
1823 #else
1824   bfp = GetObjectExtra (i);
1825 #endif
1826   if (bfp == NULL) return;
1827   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1828   if (sep == NULL) return;
1829 
1830   ans = Message (MSG_OKC, "Are you sure you want to reassign feature identifiers?");
1831   if (ans == ANS_CANCEL) return;
1832 
1833   ReassignFeatureIDs (sep);
1834 
1835   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1836   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1837   ObjMgrDeSelect (0, 0, 0, 0, NULL);
1838   Update ();
1839 }
1840 
1841 static void UniqifyFeatIDs (IteM i)
1842 
1843 {
1844   MsgAnswer     ans;
1845   BaseFormPtr   bfp;
1846   BioseqSetPtr  bssp;
1847   Int4          count;
1848   Int4          offset = 0;
1849   SeqEntryPtr   sep;
1850 
1851 #ifdef WIN_MAC
1852   bfp = currentFormDataPtr;
1853 #else
1854   bfp = GetObjectExtra (i);
1855 #endif
1856   if (bfp == NULL) return;
1857   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1858   if (sep == NULL) return;
1859 
1860   if (! IS_Bioseq_set (sep)) return;
1861   bssp = (BioseqSetPtr) sep->data.ptrvalue;
1862   if (bssp == NULL || bssp->_class != BioseqseqSet_class_genbank) return;
1863 
1864   ans = Message (MSG_OKC, "Are you sure you want to make merged feature identifiers unique?");
1865   if (ans == ANS_CANCEL) return;
1866 
1867   for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
1868     count = FindHighestFeatureID (sep);
1869     OffsetFeatureIDs (sep, offset);
1870     OffsetFeatureIDXrefs (sep, offset);
1871     offset += count;
1872   }
1873 
1874   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1875   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1876   ObjMgrDeSelect (0, 0, 0, 0, NULL);
1877   Update ();
1878 }
1879 
1880 static void ClearFeatIDsAndLinks (IteM i)
1881 
1882 {
1883   MsgAnswer    ans;
1884   BaseFormPtr  bfp;
1885   SeqEntryPtr  sep;
1886 
1887 #ifdef WIN_MAC
1888   bfp = currentFormDataPtr;
1889 #else
1890   bfp = GetObjectExtra (i);
1891 #endif
1892   if (bfp == NULL) return;
1893   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1894   if (sep == NULL) return;
1895 
1896   ans = Message (MSG_YN, "Are you sure you want to remove feature IDs and links?");
1897   if (ans == ANS_NO) return;
1898 
1899   ClearFeatureIDs (sep);
1900 
1901   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1902   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1903   ObjMgrDeSelect (0, 0, 0, 0, NULL);
1904   Update ();
1905 }
1906 
1907 static void LinkByOverlap (IteM i)
1908 
1909 {
1910   BaseFormPtr  bfp;
1911   SeqEntryPtr  sep;
1912 
1913 #ifdef WIN_MAC
1914   bfp = currentFormDataPtr;
1915 #else
1916   bfp = GetObjectExtra (i);
1917 #endif
1918   if (bfp == NULL) return;
1919   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1920   if (sep == NULL) return;
1921 
1922   LinkCDSmRNAbyOverlap (sep);
1923 
1924   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1925   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1926   ObjMgrDeSelect (0, 0, 0, 0, NULL);
1927   Update ();
1928 }
1929 
1930 static void LinkByProduct (IteM i)
1931 
1932 {
1933   BaseFormPtr  bfp;
1934   ValNodePtr   bsplist;
1935   SeqEntryPtr  sep;
1936 
1937 #ifdef WIN_MAC
1938   bfp = currentFormDataPtr;
1939 #else
1940   bfp = GetObjectExtra (i);
1941 #endif
1942   if (bfp == NULL) return;
1943   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1944   if (sep == NULL) return;
1945 
1946   bsplist = LockFarComponentsEx (sep, FALSE, TRUE, TRUE, NULL);
1947   LinkCDSmRNAbyProduct (sep);
1948   bsplist = UnlockFarComponents (bsplist);
1949 
1950   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1951   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1952   ObjMgrDeSelect (0, 0, 0, 0, NULL);
1953   Update ();
1954 }
1955 
1956 static void LinkByLabel (IteM i)
1957 
1958 {
1959   BaseFormPtr  bfp;
1960   ValNodePtr   bsplist;
1961   SeqEntryPtr  sep;
1962 
1963 #ifdef WIN_MAC
1964   bfp = currentFormDataPtr;
1965 #else
1966   bfp = GetObjectExtra (i);
1967 #endif
1968   if (bfp == NULL) return;
1969   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1970   if (sep == NULL) return;
1971 
1972   bsplist = LockFarComponentsEx (sep, FALSE, TRUE, TRUE, NULL);
1973   LinkCDSmRNAbyLabel (sep);
1974   bsplist = UnlockFarComponents (bsplist);
1975 
1976   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1977   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1978   ObjMgrDeSelect (0, 0, 0, 0, NULL);
1979   Update ();
1980 }
1981 
1982 
1983 extern void RemoveFeatureLink (SeqFeatPtr sfp1, SeqFeatPtr sfp2)
1984 {
1985   SeqFeatXrefPtr  xref, next, PNTR prevlink;
1986   ObjectIdPtr     oip;
1987   SeqFeatPtr      link_sfp;
1988   Char            buf [32];
1989   CharPtr         str = NULL;
1990 
1991   if (sfp1 == NULL) return;
1992 
1993   prevlink = (SeqFeatXrefPtr PNTR) &(sfp1->xref);
1994   xref = sfp1->xref;
1995   while (xref != NULL) {
1996     next = xref->next;
1997     link_sfp = NULL;
1998 
1999     if (xref->id.choice == 3) {
2000       oip = (ObjectIdPtr) xref->id.value.ptrvalue;
2001       if (oip != NULL) {
2002         if (StringDoesHaveText (oip->str)) {
2003           str = oip->str;
2004         } else {
2005           sprintf (buf, "%ld", (long) oip->id);
2006           str = buf;
2007         }
2008         link_sfp = SeqMgrGetFeatureByFeatID (sfp1->idx.entityID, NULL, str, NULL, NULL);
2009       }
2010     }
2011     if (link_sfp == sfp2) {
2012       *prevlink = xref->next;
2013       xref->next = NULL;
2014       MemFree (xref);
2015     } else {
2016       prevlink = (SeqFeatXrefPtr PNTR) &(xref->next);
2017     }
2018 
2019     xref = next;
2020   }
2021 }
2022 
2023 
2024 extern void LinkTwoFeatures (SeqFeatPtr dst, SeqFeatPtr sfp)
2025 
2026 {
2027   ChoicePtr       cp;
2028   ObjectIdPtr     oip;
2029   SeqFeatXrefPtr  xref, prev_xref, next_xref;
2030   SeqFeatPtr      old_match;
2031 
2032   if (dst == NULL || sfp == NULL) return;
2033 
2034   cp = &(dst->id);
2035   if (cp == NULL) return;
2036   if (cp->choice == 3) {
2037     /* don't create a duplicate xref, remove links to other features */
2038     xref = sfp->xref;
2039     prev_xref = NULL;
2040     while (xref != NULL) {
2041       next_xref = xref->next;
2042       if (xref->id.choice == 3 && xref->id.value.ptrvalue != NULL) {
2043         if (ObjectIdMatch (cp->value.ptrvalue, xref->id.value.ptrvalue)) {
2044           /* already have this xref */
2045           return;
2046         } else {
2047           old_match = SeqMgrGetFeatureByFeatID (sfp->idx.entityID, NULL, NULL, xref, NULL);
2048           RemoveFeatureLink (sfp, old_match);
2049           RemoveFeatureLink (old_match, sfp);
2050         }
2051       } else {
2052         prev_xref = xref;
2053       }
2054       xref = next_xref;
2055     }
2056 
2057     oip = (ObjectIdPtr) cp->value.ptrvalue;
2058     if (oip != NULL) {
2059       oip = AsnIoMemCopy (oip, (AsnReadFunc) ObjectIdAsnRead,
2060                           (AsnWriteFunc) ObjectIdAsnWrite);
2061       if (oip != NULL) {
2062         xref = SeqFeatXrefNew ();
2063         if (xref != NULL) {
2064           xref->id.choice = 3;
2065           xref->id.value.ptrvalue = (Pointer) oip;
2066           xref->next = sfp->xref;
2067           sfp->xref = xref;
2068         }
2069       }
2070     }
2071   }
2072 }
2073 
2074 static void LinkSelected (IteM i)
2075 
2076 {
2077   BaseFormPtr   bfp;
2078   SeqEntryPtr   sep;
2079   SeqFeatPtr    sfp1, sfp2;
2080   SelStructPtr  ssp;
2081 
2082 #ifdef WIN_MAC
2083   bfp = currentFormDataPtr;
2084 #else
2085   bfp = GetObjectExtra (i);
2086 #endif
2087   if (bfp == NULL) return;
2088   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
2089   if (sep == NULL) return;
2090 
2091   AssignFeatureIDs (sep);
2092 
2093   ssp = ObjMgrGetSelected ();
2094   if (ssp == NULL) {
2095     Message (MSG_OK, "No features selected");
2096     return;
2097   }
2098   if (ssp->itemtype != OBJ_SEQFEAT) {
2099     Message (MSG_OK, "Something other than a feature is selected");
2100     return;
2101   }
2102   sfp1 = SeqMgrGetDesiredFeature (ssp->entityID, NULL, ssp->itemID, 0, NULL, NULL);
2103   if (sfp1 == NULL) {
2104     Message (MSG_OK, "Unable to find selected feature");
2105     return;
2106   }
2107   ssp = ssp->next;
2108   if (ssp == NULL) {
2109     Message (MSG_OK, "Only one feature was selected, two must be selected");
2110     return;
2111   }
2112   if (ssp->itemtype != OBJ_SEQFEAT) {
2113     Message (MSG_OK, "Something other than a feature is selected");
2114     return;
2115   }
2116   sfp2 = SeqMgrGetDesiredFeature (ssp->entityID, NULL, ssp->itemID, 0, NULL, NULL);
2117   if (ssp->next != NULL) {
2118     Message (MSG_OK, "Only two features must be selected");
2119     return;
2120   }
2121   if (sfp2 == NULL) {
2122     Message (MSG_OK, "Unable to find selected feature");
2123     return;
2124   }
2125 
2126   LinkTwoFeatures (sfp1, sfp2);
2127   LinkTwoFeatures (sfp2, sfp1);
2128 
2129   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
2130   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
2131   ObjMgrDeSelect (0, 0, 0, 0, NULL);
2132   Update ();
2133 }
2134 
2135 static void SelCDSmRNALink (IteM i)
2136 
2137 {
2138   Char            buf [32];
2139   ObjectIdPtr     oip;
2140   SeqFeatPtr      sfp;
2141   SelStructPtr    ssp;
2142   CharPtr         str = NULL;
2143   SeqFeatXrefPtr  xref;
2144 
2145   ssp = ObjMgrGetSelected ();
2146   if (ssp == NULL) {
2147     Message (MSG_OK, "No feature selected");
2148     return;
2149   }
2150   if (ssp->next != NULL) {
2151     Message (MSG_OK, "Only one feature must be selected");
2152     return;
2153   }
2154   if (ssp->itemtype != OBJ_SEQFEAT) {
2155     Message (MSG_OK, "Something other than a feature is selected");
2156     return;
2157   }
2158 
2159   sfp = SeqMgrGetDesiredFeature (ssp->entityID, NULL, ssp->itemID, 0, NULL, NULL);
2160   if (sfp == NULL) {
2161     Message (MSG_OK, "Unable to find selected feature");
2162     return;
2163   }
2164 
2165   for (xref = sfp->xref; xref != NULL; xref = xref->next) {
2166     if (xref->id.choice != 3) continue;
2167     oip = (ObjectIdPtr) xref->id.value.ptrvalue;
2168     if (oip != NULL) {
2169       if (StringDoesHaveText (oip->str)) {
2170         str = oip->str;
2171       } else {
2172         sprintf (buf, "%ld", (long) oip->id);
2173         str = buf;
2174       }
2175     }
2176   }
2177 
2178   if (str == NULL) {
2179     Message (MSG_OK, "Unable to extract feature ID xref");
2180     return;
2181   }
2182 
2183   sfp = SeqMgrGetFeatureByFeatID (ssp->entityID, NULL, str, NULL, NULL);
2184   if (sfp == NULL) {
2185     Message (MSG_OK, "Unable to find referenced feature");
2186     return;
2187   }
2188 
2189   ObjMgrAlsoSelect (sfp->idx.entityID, sfp->idx.itemID, OBJ_SEQFEAT, 0, NULL);
2190   ObjMgrSendMsg (OM_MSG_UPDATE, sfp->idx.entityID, 0, 0);
2191   Update ();
2192 }
2193 
2194 extern void ForceTaxonFixupBtn (IteM i, ButtoN b)
2195 
2196 {
2197   BaseFormPtr  bfp;
2198   SeqEntryPtr  sep;
2199 
2200   if (b != NULL) {
2201     bfp = GetObjectExtra (b);
2202   } else {
2203 #ifdef WIN_MAC
2204     bfp = currentFormDataPtr;
2205 #else
2206     bfp = GetObjectExtra (i);
2207 #endif
2208   }
2209   if (bfp == NULL) return;
2210   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
2211   if (sep == NULL) return;
2212   /* SeqEntryExplore (sep, (Pointer) bfp, CleanupGenbankBlockCallback); */
2213   SeqEntryExplore (sep, NULL, CleanupEmptyFeatCallback);
2214   SeqEntryExplore (sep, NULL, MergeAdjacentAnnotsCallback);
2215   MySeqEntryToAsn3 (sep, TRUE, FALSE, TRUE);
2216   CorrectGenCodes (sep, bfp->input_entityID);
2217   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
2218   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
2219 }
2220 
2221 static void ForceTaxonFixup (IteM i)
2222 
2223 {
2224   ForceTaxonFixupBtn (i, NULL);
2225 }
2226 
2227 static void JustTaxonFixup (IteM i)
2228 
2229 {
2230   BaseFormPtr  bfp;
2231   SeqEntryPtr  sep;
2232 
2233 #ifdef WIN_MAC
2234   bfp = currentFormDataPtr;
2235 #else
2236   bfp = GetObjectExtra (i);
2237 #endif
2238   if (bfp == NULL) return;
2239   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
2240   if (sep == NULL) return;
2241   Taxon3ReplaceOrgInSeqEntry (sep, FALSE);
2242   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
2243   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
2244 }
2245 
2246 
2247 typedef struct hasdupfeatsdata {
2248   Uint1 featdef;
2249   Int4  num_feat;
2250   Int4  num_cds_with_product;
2251   ValNodePtr delete_list;
2252   Boolean case_sensitive;
2253   Boolean ignore_partials;
2254 } HasDupFeatsData, PNTR HasDupFeatsPtr;
2255 
2256 typedef struct dupfeatsdlg {
2257   DIALOG_MESSAGE_BLOCK
2258   DialoG feat_type;
2259   ButtoN ignore_partials;
2260   Uint2  entityID;
2261   WindoW window;
2262 } DupFeatsDlgData, PNTR DupFeatsDlgPtr;
2263 
2264 static Pointer DupFeatsDlgToData (DialoG d)
2265 {
2266   DupFeatsDlgPtr dlg;
2267   HasDupFeatsPtr data;
2268   ValNodePtr     vnp;
2269 
2270   dlg = (DupFeatsDlgPtr) GetObjectExtra (d);
2271   if (dlg == NULL) {
2272     return NULL;
2273   }
2274 
2275   data = (HasDupFeatsPtr) MemNew (sizeof (HasDupFeatsData));
2276   data->num_feat = 0;
2277   data->num_cds_with_product = 0;
2278   data->delete_list = NULL;
2279   data->case_sensitive = TRUE;
2280 
2281   vnp = DialogToPointer (dlg->feat_type);
2282   if (vnp == NULL) {
2283     data->featdef = 0;
2284   } else {
2285     if (vnp->choice == Feature_type_any) {
2286       data->featdef = 0;
2287     } else {
2288       data->featdef = GetFeatdefFromFeatureType (vnp->choice);
2289     }
2290     vnp = ValNodeFreeData (vnp);
2291   }
2292 
2293   data->ignore_partials = GetStatus (dlg->ignore_partials);
2294 
2295   return data;
2296 }
2297 
2298 
2299 static DialoG DupFeatsDialog (GrouP g, Uint2 entityID, WindoW w)
2300 {
2301   DupFeatsDlgPtr dlg;
2302   GrouP          p;
2303   ValNode        vn;
2304   ValNodePtr feature_list = NULL;
2305 
2306   dlg = (DupFeatsDlgPtr) MemNew (sizeof (DupFeatsDlgData));
2307 
2308   p = HiddenGroup (g, -1, 0, NULL);
2309   SetObjectExtra (p, dlg, StdCleanupExtraProc);
2310 
2311   dlg->dialog = (DialoG) p;
2312   dlg->fromdialog = DupFeatsDlgToData;
2313 
2314   dlg->entityID = entityID;
2315   dlg->window = w;
2316 
2317   feature_list = ValNodeNew (NULL);
2318   feature_list->choice = Feature_type_any;
2319   feature_list->data.ptrvalue = StringSave ("All");
2320   AddAllFeaturesToChoiceList (&feature_list);
2321   dlg->feat_type = ValNodeSelectionDialog (p, feature_list, TALL_SELECTION_LIST, ValNodeStringName,
2322                                 ValNodeSimpleDataFree, ValNodeStringCopy,
2323                                 ValNodeChoiceMatch, "feature type", 
2324                                 NULL, NULL, FALSE);
2325 
2326   vn.choice = Feature_type_any;
2327   vn.data.ptrvalue = NULL;
2328   vn.next = NULL;
2329   PointerToDialog (dlg->feat_type, &vn);
2330   dlg->ignore_partials = CheckBox (p, "Ignore partials", NULL);
2331 
2332   AlignObjects (ALIGN_CENTER, (HANDLE) dlg->feat_type, (HANDLE) dlg->ignore_partials, NULL);
2333 
2334   return (DialoG) p;
2335 }
2336 
2337 
2338 static void HasDupFeatsBioseqCallback (BioseqPtr bsp, Pointer data)
2339 {
2340   HasDupFeatsPtr h;
2341   SeqFeatPtr     sfp1, sfp2;
2342   SeqMgrFeatContext fcontext;
2343 
2344   if (bsp == NULL || data == NULL) {
2345     return;
2346   }
2347 
2348   h = (HasDupFeatsPtr) data;
2349 
2350   sfp1 = SeqMgrGetNextFeature (bsp, NULL, 0,h->featdef, &fcontext);
2351   while (sfp1 != NULL) {
2352     sfp2 = SeqMgrGetNextFeature (bsp, sfp1, 0, h->featdef, &fcontext);
2353     if (sfp1 == sfp2) {
2354       break;
2355     }
2356     if (DoFeaturesMatch (sfp1, sfp2, FALSE, h->case_sensitive, h->ignore_partials)) {
2357       h->num_feat++;
2358       if (sfp2->data.choice == SEQFEAT_CDREGION && sfp2->product != NULL) {
2359         h->num_cds_with_product++;
2360       }
2361       ValNodeAddPointer (&(h->delete_list), OBJ_SEQFEAT, sfp2);
2362     }
2363     sfp1 = sfp2;
2364   }
2365 }
2366 
2367 
2368 static Boolean RemoveDuplicateFeatsAction (Uint2 entityID, HasDupFeatsPtr data)
2369 {
2370   SeqEntryPtr sep;
2371   Boolean     rval = FALSE;
2372   MsgAnswer       ans;
2373   Boolean         remove_proteins = FALSE;
2374   ValNodePtr      vnp;
2375   SeqFeatPtr      sfp;
2376   BioseqPtr       protbsp;
2377 
2378   sep = GetTopSeqEntryForEntityID (entityID);
2379 
2380   VisitBioseqsInSep (sep, data, HasDupFeatsBioseqCallback);
2381   if (data->num_feat == 0) {
2382     Message (MSG_ERROR, "No duplicates found");
2383     return rval;
2384   }
2385 
2386   if (data->num_cds_with_product > 0) {
2387     ans = Message (MSG_YNC, "%d duplicate features found.  %d coding regions have protein products.  Remove protein products?",
2388                    data->num_feat, data->num_cds_with_product);
2389     if (ans == ANS_CANCEL) {
2390       data->delete_list = ValNodeFree (data->delete_list);
2391       return rval;
2392     } else if (ans == ANS_YES) {
2393       remove_proteins = TRUE;
2394     }
2395   } 
2396 
2397   for (vnp = data->delete_list; vnp != NULL; vnp = vnp->next) {
2398     sfp = (SeqFeatPtr) vnp->data.ptrvalue;
2399     if (sfp != NULL) {
2400       if (remove_proteins && sfp->data.choice == SEQFEAT_CDREGION && sfp->product != NULL) {
2401         protbsp = BioseqFindFromSeqLoc (sfp->product);
2402         if (protbsp != NULL) {
2403           protbsp->idx.deleteme = TRUE;
2404         }
2405       }
2406       sfp->idx.deleteme = TRUE;
2407     }
2408   }
2409 
2410   DeleteMarkedObjects (entityID, 0, NULL);
2411   if (remove_proteins) {
2412     RenormalizeNucProtSets (sep, TRUE);         
2413   }
2414 
2415   ObjMgrSetDirtyFlag (entityID, TRUE);
2416   ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
2417   rval = TRUE;
2418   return rval;
2419 }
2420 
2421 
2422 static void DoRemoveDuplicateFeats (ButtoN b)
2423 {
2424   DialoG         d;
2425   DupFeatsDlgPtr dlg;
2426   HasDupFeatsPtr data;
2427 
2428   d = (DialoG) GetObjectExtra (b);
2429   dlg = (DupFeatsDlgPtr) GetObjectExtra (d);
2430 
2431   if (dlg == NULL) {
2432     return;
2433   }
2434 
2435   data = (HasDupFeatsPtr) DialogToPointer (dlg->dialog);
2436 
2437   if (RemoveDuplicateFeatsAction (dlg->entityID, data)) {
2438     Remove (dlg->window);
2439   }
2440   data = MemFree (data);
2441 }
2442 
2443 
2444 static void RemoveDuplicateFeatsWithOptions (IteM i)
2445 {
2446   BaseFormPtr  bfp;
2447   WindoW       w;
2448   GrouP        h, c;
2449   ButtoN       b;
2450   DialoG       d;
2451 
2452 #ifdef WIN_MAC
2453   bfp = currentFormDataPtr;
2454 #else
2455   bfp = GetObjectExtra (i);
2456 #endif
2457   if (bfp == NULL) return;
2458 
2459   w = FixedWindow (-50, -33, -10, -10, "Remove Duplicate Features", StdCloseWindowProc);
2460   h = HiddenGroup (w, -1, 0, NULL);
2461   SetGroupSpacing (h, 10, 10);
2462 
2463   d = DupFeatsDialog (h, bfp->input_entityID, w);
2464   c = HiddenGroup (h, 2, 0, NULL);
2465   b = DefaultButton (c, "Accept", DoRemoveDuplicateFeats);
2466   SetObjectExtra (b, d, NULL);
2467   PushButton (c, "Cancel", StdCancelButtonProc);
2468   AlignObjects (ALIGN_CENTER, (HANDLE) d, (HANDLE) c, NULL);
2469 
2470   Show (w);
2471 }
2472 
2473 
2474 static void NewRemoveDuplicateFeats (IteM i, Uint2 featdef)
2475 {
2476   BaseFormPtr  bfp;
2477   HasDupFeatsData h;
2478 
2479 #ifdef WIN_MAC
2480   bfp = currentFormDataPtr;
2481 #else
2482   bfp = GetObjectExtra (i);
2483 #endif
2484   if (bfp == NULL) return;
2485 
2486   h.featdef = (Uint1) featdef;
2487   h.num_cds_with_product = 0;
2488   h.num_feat = 0;
2489   h.delete_list = NULL;
2490   h.case_sensitive = TRUE;
2491   h.ignore_partials = FALSE;
2492 
2493   RemoveDuplicateFeatsAction (bfp->input_entityID, &h);
2494 }
2495 
2496 
2497 static void NewRemoveDuplicateFeatsAll (IteM i)
2498 {
2499   NewRemoveDuplicateFeats (i, 0);
2500 }
2501 
2502 
2503 static void NewRemoveDuplicateFeatsGenes (IteM i)
2504 {
2505   NewRemoveDuplicateFeats (i, FEATDEF_GENE);
2506 }
2507 
2508 
2509 
2510 /*
2511 static Boolean LIBCALLBACK RemoveGeneXrefsOnBioseqs (BioseqPtr bsp, SeqMgrBioseqContextPtr bcontext)
2512 
2513 {
2514   SeqFeatXrefPtr     curr;
2515   SeqMgrFeatContext  fcontext;
2516   GeneRefPtr         grp;
2517   GeneRefPtr         grpx;
2518   SeqFeatXrefPtr     PNTR last;
2519   SeqFeatXrefPtr     next;
2520   Boolean            redundantgenexref;
2521   SeqFeatPtr         sfp;
2522   SeqFeatPtr         sfpx;
2523   CharPtr            syn1;
2524   CharPtr            syn2;
2525 
2526   sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &fcontext);
2527   while (sfp != NULL) {
2528     if (sfp->data.choice != SEQFEAT_GENE) {
2529       grp = SeqMgrGetGeneXref (sfp);
2530       if (grp != NULL && (! SeqMgrGeneIsSuppressed (grp))) {
2531         sfpx = SeqMgrGetOverlappingGene (sfp->location, NULL);
2532         if (sfpx != NULL && sfpx->data.choice == SEQFEAT_GENE) {
2533           grpx = (GeneRefPtr) sfpx->data.value.ptrvalue;
2534           if (grpx != NULL) {
2535             redundantgenexref = FALSE;
2536             if ((! StringHasNoText (grp->locus)) && (! StringHasNoText (grpx->locus))) {
2537               if ((StringICmp (grp->locus, grpx->locus) == 0)) {
2538                 redundantgenexref = TRUE;
2539               }
2540             } else if ((! StringHasNoText (grp->locus_tag)) && (! StringHasNoText (grpx->locus_tag))) {
2541               if ((StringICmp (grp->locus_tag, grpx->locus_tag) == 0)) {
2542                 redundantgenexref = TRUE;
2543               }
2544             } else if (grp->syn != NULL && grpx->syn != NULL) {
2545               syn1 = (CharPtr) grp->syn->data.ptrvalue;
2546               syn2 = (CharPtr) grpx->syn->data.ptrvalue;
2547               if ((! StringHasNoText (syn1)) && (! StringHasNoText (syn2))) {
2548                 if ((StringICmp (syn1, syn2) == 0)) {
2549                   redundantgenexref = TRUE;
2550                 }
2551               }
2552             }
2553             if (redundantgenexref) {
2554               last = (SeqFeatXrefPtr PNTR) &(sfp->xref);
2555               curr = sfp->xref;
2556               while (curr != NULL) {
2557                 next = curr->next;
2558                 if (curr->data.choice == SEQFEAT_GENE) {
2559                   *last = next;
2560                   curr->next = NULL;
2561                   SeqFeatXrefFree (curr);
2562                 } else {
2563                   last = &(curr->next);
2564                 }
2565                 curr = next;
2566               }
2567             }
2568           }
2569         }
2570       } 
2571     }
2572     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &fcontext);
2573   }
2574 
2575   return TRUE;
2576 }
2577 */
2578 
2579 typedef struct dummysmfedata {
2580   Int4  max;
2581   Int4  num_at_max;
2582 } DummySmfeData, PNTR DummySmfePtr;
2583 
2584 static Boolean LIBCALLBACK SQNDummySMFEProc (
2585   SeqFeatPtr sfp,
2586   SeqMgrFeatContextPtr context
2587 )
2588 
2589 
2590 {
2591   DummySmfePtr  dsp;
2592   Int4          len;
2593 
2594   if (sfp == NULL || context == NULL) return TRUE;
2595   dsp = context->userdata;
2596   if (dsp == NULL) return TRUE;
2597 
2598   len = SeqLocLen (sfp->location);
2599   if (len < dsp->max) {
2600     dsp->max = len;
2601     dsp->num_at_max = 1;
2602   } else if (len == dsp->max) {
2603     (dsp->num_at_max)++;
2604   }
2605 
2606   return TRUE;
2607 }
2608 
2609 static Boolean LIBCALLBACK RemoveGeneXrefsOnBioseqs (BioseqPtr bsp, SeqMgrBioseqContextPtr bcontext)
2610 
2611 {
2612   Int2               count;
2613   SeqFeatXrefPtr     curr;
2614   DummySmfeData      dsd;
2615   SeqMgrFeatContext  fcontext;
2616   GeneRefPtr         grp;
2617   GeneRefPtr         grpx;
2618   SeqFeatXrefPtr     PNTR last;
2619   SeqFeatXrefPtr     next;
2620   Boolean            redundantgenexref;
2621   SeqFeatPtr         sfp;
2622   SeqFeatPtr         sfpx;
2623   CharPtr            syn1, syn2;
2624 
2625   sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &fcontext);
2626   while (sfp != NULL) {
2627     grp = SeqMgrGetGeneXref (sfp);
2628     if (grp != NULL && (! SeqMgrGeneIsSuppressed (grp))) {
2629       sfpx = SeqMgrGetOverlappingGene (sfp->location, NULL);
2630       if (sfpx != NULL && sfpx->data.choice == SEQFEAT_GENE) {
2631         grpx = (GeneRefPtr) sfpx->data.value.ptrvalue;
2632         if (grpx != NULL) {
2633 
2634           redundantgenexref = TRUE;
2635           if ((!StringHasNoText (grp->locus)) && (!StringHasNoText (grpx->locus))) {
2636             if ((StringICmp (grp->locus, grpx->locus) != 0)) {
2637               redundantgenexref = FALSE;
2638             }
2639           } else if (StringDoesHaveText (grp->locus_tag) && StringDoesHaveText (grp->locus_tag)) {
2640             if ((StringICmp (grp->locus_tag, grpx->locus_tag) != 0)) {
2641               redundantgenexref = FALSE;
2642             }
2643           } else if (grp->syn != NULL && grpx->syn != NULL) {
2644             syn1 = (CharPtr) grp->syn->data.ptrvalue;
2645             syn2 = (CharPtr) grpx->syn->data.ptrvalue;
2646             if ((!StringHasNoText (syn1)) && (!StringHasNoText (syn2))) {
2647               if ((StringICmp (syn1, syn2) != 0)) {
2648                 redundantgenexref = FALSE;
2649               }
2650             }
2651           }
2652 
2653           if (redundantgenexref) {
2654             MemSet ((Pointer) &dsd, 0, sizeof (DummySmfeData));
2655             dsd.max = INT4_MAX;
2656             dsd.num_at_max = 0;
2657             count = SeqMgrGetAllOverlappingFeatures (sfp->location, FEATDEF_GENE, NULL, 0,
2658                                                       LOCATION_SUBSET, (Pointer) &dsd, SQNDummySMFEProc);
2659 
2660             if (dsd.num_at_max < 2) {
2661               last = (SeqFeatXrefPtr PNTR) &(sfp->xref);
2662               curr = sfp->xref;
2663               while (curr != NULL) {
2664                 next = curr->next;
2665                 if (curr->data.choice == SEQFEAT_GENE) {
2666                   *last = next;
2667                   curr->next = NULL;
2668                   SeqFeatXrefFree (curr);
2669                 } else {
2670                   last = &(curr->next);
2671                 }
2672                 curr = next;
2673               }
2674             }
2675           }
2676         }
2677       }
2678     } 
2679     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &fcontext);
2680   }
2681 
2682   return TRUE;
2683 }
2684 
2685 static void RemoveGeneXrefs (IteM i)
2686 
2687 {
2688   BaseFormPtr  bfp;
2689   Uint2        entityID;
2690   SeqEntryPtr  sep;
2691 
2692 #ifdef WIN_MAC
2693   bfp = currentFormDataPtr;
2694 #else
2695   bfp = GetObjectExtra (i);
2696 #endif
2697   if (bfp == NULL) return;
2698   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
2699   if (sep == NULL) return;
2700   entityID = SeqMgrIndexFeatures (bfp->input_entityID, NULL);
2701   if (entityID < 1) return;
2702   SeqMgrExploreBioseqs (entityID, 0, NULL, RemoveGeneXrefsOnBioseqs, TRUE, TRUE, TRUE);
2703   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
2704   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
2705 }
2706 
2707 static void RemoveGeneXNoLC (SeqFeatPtr sfp, Pointer userdata)
2708 
2709 {
2710   BioseqPtr       bsp;
2711   GeneRefPtr      grp;
2712   SeqFeatXrefPtr  curr;
2713   SeqFeatXrefPtr  PNTR last;
2714   SeqFeatXrefPtr  next;
2715 
2716   grp = SeqMgrGetGeneXref (sfp);
2717   if (grp == NULL || SeqMgrGeneIsSuppressed (grp)) return;
2718   if (StringHasNoText (grp->locus_tag)) return;
2719   bsp = BioseqFindFromSeqLoc (sfp->location);
2720   if (bsp == NULL) return;
2721   if (SeqMgrGetFeatureByLabel (bsp, grp->locus, SEQFEAT_GENE, 0, NULL) != NULL) return;
2722   last = (SeqFeatXrefPtr PNTR) &(sfp->xref);
2723   curr = sfp->xref;
2724   while (curr != NULL) {
2725     next = curr->next;
2726     if (curr->data.choice == SEQFEAT_GENE) {
2727       *last = next;
2728       curr->next = NULL;
2729       SeqFeatXrefFree (curr);
2730     } else {
2731       last = &(curr->next);
2732     }
2733     curr = next;
2734   }
2735 }
2736 
2737 static void RemoveGeneXrefsNoGene (IteM i)
2738 
2739 {
2740   BaseFormPtr  bfp;
2741   SeqEntryPtr  sep;
2742 
2743 #ifdef WIN_MAC
2744   bfp = currentFormDataPtr;
2745 #else
2746   bfp = GetObjectExtra (i);
2747 #endif
2748   if (bfp == NULL) return;
2749   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
2750   if (sep == NULL) return;
2751   VisitFeaturesInSep (sep, NULL, RemoveGeneXNoLC);
2752   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
2753   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
2754 }
2755 
2756 static void RemoveGeneXNoLT (SeqFeatPtr sfp, Pointer userdata)
2757 
2758 {
2759   BioseqPtr       bsp;
2760   GeneRefPtr      grp;
2761   SeqFeatXrefPtr  curr;
2762   SeqFeatXrefPtr  PNTR last;
2763   SeqFeatXrefPtr  next;
2764 
2765   grp = SeqMgrGetGeneXref (sfp);
2766   if (grp == NULL || SeqMgrGeneIsSuppressed (grp)) return;
2767   if (StringHasNoText (grp->locus_tag)) return;
2768   bsp = BioseqFindFromSeqLoc (sfp->location);
2769   if (bsp == NULL) return;
2770   if (SeqMgrGetGeneByLocusTag (bsp, grp->locus_tag, NULL) != NULL) return;
2771   last = (SeqFeatXrefPtr PNTR) &(sfp->xref);
2772   curr = sfp->xref;
2773   while (curr != NULL) {
2774     next = curr->next;
2775     if (curr->data.choice == SEQFEAT_GENE) {
2776       *last = next;
2777       curr->next = NULL;
2778       SeqFeatXrefFree (curr);
2779     } else {
2780       last = &(curr->next);
2781     }
2782     curr = next;
2783   }
2784 }
2785 
2786 static void RemoveGeneXrefsNoLocTag (IteM i)
2787 
2788 {
2789   BaseFormPtr  bfp;
2790   SeqEntryPtr  sep;
2791 
2792 #ifdef WIN_MAC
2793   bfp = currentFormDataPtr;
2794 #else
2795   bfp = GetObjectExtra (i);
2796 #endif
2797   if (bfp == NULL) return;
2798   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
2799   if (sep == NULL) return;
2800   VisitFeaturesInSep (sep, NULL, RemoveGeneXNoLT);
2801   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
2802   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
2803 }
2804 
2805 static void DoRemoveNSGeneXrefs (SeqFeatPtr sfp, Pointer userdata)
2806 
2807 {
2808   SeqFeatXrefPtr  curr;
2809   GeneRefPtr      grp;
2810   SeqFeatXrefPtr  PNTR last;
2811   SeqFeatXrefPtr  next;
2812 
2813   last = (SeqFeatXrefPtr PNTR) &(sfp->xref);
2814   curr = sfp->xref;
2815   while (curr != NULL) {
2816     next = curr->next;
2817     if (curr->data.choice == SEQFEAT_GENE) {
2818       grp = (GeneRefPtr) curr->data.value.ptrvalue;
2819       if (SeqMgrGeneIsSuppressed (grp)) {
2820         last = &(curr->next);
2821       } else {
2822         *last = next;
2823         curr->next = NULL;
2824         SeqFeatXrefFree (curr);
2825       }
2826     } else {
2827       last = &(curr->next);
2828     }
2829     curr = next;
2830   }
2831 }
2832 
2833 static void RemoveNSGeneXrefs (IteM i)
2834 
2835 {
2836   BaseFormPtr  bfp;
2837   SeqEntryPtr  sep;
2838 
2839 #ifdef WIN_MAC
2840   bfp = currentFormDataPtr;
2841 #else
2842   bfp = GetObjectExtra (i);
2843 #endif
2844   if (bfp == NULL) return;
2845   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
2846   if (sep == NULL) return;
2847   VisitFeaturesInSep (sep, NULL, DoRemoveNSGeneXrefs);
2848   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
2849   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
2850 }
2851 
2852 static void DoRemoveGeneXrefs (SeqFeatPtr sfp, Pointer userdata)
2853 
2854 {
2855   SeqFeatXrefPtr  curr;
2856   SeqFeatXrefPtr  PNTR last;
2857   SeqFeatXrefPtr  next;
2858 
2859   last = (SeqFeatXrefPtr PNTR) &(sfp->xref);
2860   curr = sfp->xref;
2861   while (curr != NULL) {
2862     next = curr->next;
2863     if (curr->data.choice == SEQFEAT_GENE) {
2864       *last = next;
2865       curr->next = NULL;
2866       SeqFeatXrefFree (curr);
2867     } else {
2868       last = &(curr->next);
2869     }
2870     curr = next;
2871   }
2872 }
2873 
2874 static void RemoveAllGeneXrefs (IteM i)
2875 
2876 {
2877   BaseFormPtr  bfp;
2878   SeqEntryPtr  sep;
2879 
2880 #ifdef WIN_MAC
2881   bfp = currentFormDataPtr;
2882 #else
2883   bfp = GetObjectExtra (i);
2884 #endif
2885   if (bfp == NULL) return;
2886   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
2887   if (sep == NULL) return;
2888   VisitFeaturesInSep (sep, NULL, DoRemoveGeneXrefs);
2889   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
2890   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
2891 }
2892 
2893 typedef struct removegenexref
2894 {
2895   FORM_MESSAGE_BLOCK
2896   DialoG  feature_select;
2897   DialoG  constraints;
2898   DialoG  accept_cancel;
2899   
2900   ButtoN  suppressing;
2901   ButtoN  nonsuppressing;
2902   ButtoN  unnecessary;
2903     
2904   Boolean do_suppressing;
2905   Boolean do_nonsuppressing;
2906   Boolean do_unnecessary;
2907 } RemoveGeneXrefData, PNTR RemoveGeneXrefPtr;
2908 
2909 static void RemoveGeneXrefsChangeNotify (Pointer userdata)
2910 {
2911   RemoveGeneXrefPtr dlg;
2912   ValNodePtr        vnp;
2913   Boolean           do_enable = FALSE;
2914   
2915   dlg = (RemoveGeneXrefPtr) userdata;
2916   if (dlg == NULL) 
2917   {
2918     return;
2919   }
2920   
2921   vnp = (ValNodePtr) DialogToPointer (dlg->feature_select);
2922   if (vnp != NULL)
2923   {
2924     ValNodeFree (vnp);
2925     if (GetStatus (dlg->suppressing)
2926         || GetStatus (dlg->nonsuppressing)
2927         || GetStatus (dlg->unnecessary))
2928     {
2929       do_enable = TRUE;
2930     }
2931   }
2932   if (do_enable)
2933   {
2934     EnableAcceptCancelDialogAccept (dlg->accept_cancel);
2935   }
2936   else
2937   {
2938     DisableAcceptCancelDialogAccept (dlg->accept_cancel);
2939   }
2940 } 
2941 
2942 static void RemoveGeneXrefsChangeBtn (ButtoN b)
2943 {
2944   RemoveGeneXrefPtr dlg;
2945 
2946   dlg = (RemoveGeneXrefPtr) GetObjectExtra (b);
2947   RemoveGeneXrefsChangeNotify (dlg);
2948 }
2949 
2950 static void RemoveGeneXrefsClear (Pointer data)
2951 {
2952   RemoveGeneXrefPtr dlg;
2953 
2954   dlg = (RemoveGeneXrefPtr) data;
2955   if (dlg == NULL) return;
2956  
2957   PointerToDialog (dlg->feature_select, NULL);
2958   PointerToDialog (dlg->constraints, NULL);
2959 }
2960 
2961 static void RemoveGeneXrefsClearText (Pointer data)
2962 {
2963   RemoveGeneXrefPtr    dlg;
2964   FilterSetPtr          fsp;
2965 
2966   dlg = (RemoveGeneXrefPtr) data;
2967   if (dlg == NULL) return;
2968  
2969   fsp = DialogToPointer (dlg->constraints);
2970   FilterSetClearText (fsp);
2971   PointerToDialog (dlg->constraints, fsp);
2972   FilterSetFree (fsp);
2973 }
2974 
2975 static Boolean IsUnnecessaryGeneXref (SeqFeatPtr sfp, GeneRefPtr grp)
2976 {
2977   SeqFeatPtr sfpx;
2978   GeneRefPtr grpx;
2979   Boolean    redundantgenexref = FALSE;
2980   CharPtr    syn1;
2981   CharPtr    syn2;
2982   
2983   if (sfp == NULL || grp == NULL || SeqMgrGeneIsSuppressed (grp))
2984   {
2985     return FALSE;
2986   }
2987   
2988   sfpx = SeqMgrGetOverlappingGene (sfp->location, NULL);
2989   if (sfpx == NULL || sfpx->data.choice != SEQFEAT_GENE)
2990   {
2991     return FALSE;
2992   }
2993 
2994   grpx = (GeneRefPtr) sfpx->data.value.ptrvalue;
2995   if (grpx == NULL)
2996   {
2997     return FALSE;
2998   }
2999   
3000   if (StringDoesHaveText (grp->locus_tag) && StringDoesHaveText (grpx->locus_tag)) {
3001     if (StringICmp (grp->locus_tag, grpx->locus_tag) == 0) {
3002       redundantgenexref = TRUE;
3003     }
3004   } else if (StringDoesHaveText (grp->locus) && StringDoesHaveText (grpx->locus)) {
3005     if (StringICmp (grp->locus, grpx->locus) == 0) {
3006       redundantgenexref = TRUE;
3007     }
3008   } else if (grp->syn != NULL && grpx->syn != NULL) {
3009     syn1 = (CharPtr) grp->syn->data.ptrvalue;
3010     syn2 = (CharPtr) grpx->syn->data.ptrvalue;
3011     if (StringDoesHaveText (syn1) && StringDoesHaveText (syn2)) {
3012       if (StringICmp (syn1, syn2) == 0) {
3013         redundantgenexref = TRUE;
3014       }
3015     }
3016   }
3017   return redundantgenexref;
3018 }
3019 
3020 static void RemoveGeneXrefsCallback (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
3021 {
3022   RemoveGeneXrefPtr    dlg;
3023   SeqFeatXrefPtr       curr;
3024   GeneRefPtr           grp;
3025   SeqFeatXrefPtr       PNTR last;
3026   SeqFeatXrefPtr       next;
3027   Boolean              is_suppressed;
3028 
3029   if (sfp == NULL || userdata == NULL)
3030   {
3031     return;
3032   }
3033   
3034   dlg = (RemoveGeneXrefPtr) userdata;
3035 
3036   last = (SeqFeatXrefPtr PNTR) &(sfp->xref);
3037   curr = sfp->xref;
3038   while (curr != NULL) {
3039     next = curr->next;
3040     if (curr->data.choice == SEQFEAT_GENE) {
3041       grp = (GeneRefPtr) curr->data.value.ptrvalue;
3042       is_suppressed = SeqMgrGeneIsSuppressed (grp);
3043       
3044       if ((dlg->do_suppressing && is_suppressed)
3045           || (dlg->do_nonsuppressing && !is_suppressed)
3046           || (dlg->do_unnecessary && IsUnnecessaryGeneXref (sfp, grp)))
3047       {
3048         *last = next;
3049         curr->next = NULL;
3050         SeqFeatXrefFree (curr);
3051       }
3052       else 
3053       {
3054         last = &(curr->next);
3055       }
3056     } else {
3057       last = &(curr->next);
3058     }
3059     curr = next;
3060   }
3061  
3062 }
3063 
3064 static Boolean RemoveGeneXrefsAction (Pointer userdata)
3065 {
3066   RemoveGeneXrefPtr    dlg;
3067   FilterSetPtr         fsp;
3068   SeqEntryPtr          sep;
3069   ValNodePtr           feature_type_list, vnp;
3070   Uint1                 feat_def_choice;
3071   
3072   if (userdata == NULL) return FALSE;
3073   
3074   dlg = (RemoveGeneXrefPtr) userdata;
3075   
3076   sep = GetTopSeqEntryForEntityID (dlg->input_entityID);
3077   if (sep == NULL) return FALSE;
3078   
3079   feature_type_list = (ValNodePtr) DialogToPointer (dlg->feature_select);
3080   
3081   if (feature_type_list == NULL)
3082   {
3083     return FALSE;
3084   }
3085   
3086   fsp = (FilterSetPtr) DialogToPointer (dlg->constraints);
3087   
3088   dlg->do_suppressing = GetStatus (dlg->suppressing);
3089   dlg->do_nonsuppressing = GetStatus (dlg->nonsuppressing);
3090   dlg->do_unnecessary = GetStatus (dlg->unnecessary);
3091     
3092   for (vnp = feature_type_list; vnp != NULL; vnp = vnp->next)
3093   {
3094     feat_def_choice = vnp->choice;
3095     if (feat_def_choice == 255)
3096     {
3097       feat_def_choice = 0;
3098     }
3099     OperateOnSeqEntryConstrainedObjects (sep, fsp, 
3100                                          RemoveGeneXrefsCallback,
3101                                          NULL, 0, feat_def_choice, 0, dlg);
3102   }
3103   
3104   ValNodeFree (feature_type_list);
3105   FilterSetFree (fsp);
3106   
3107   ObjMgrSetDirtyFlag (dlg->input_entityID, TRUE);
3108   ObjMgrSendMsg (OM_MSG_UPDATE, dlg->input_entityID, 0, 0);  
3109   Update ();
3110   return TRUE;
3111 }
3112 
3113 static void NewRemoveGeneXrefs (IteM i)
3114 
3115 {
3116   BaseFormPtr       bfp;
3117   RemoveGeneXrefPtr dlg;
3118   WindoW            w;
3119   GrouP             h, k;
3120   SeqEntryPtr       sep;
3121 
3122 #ifdef WIN_MAC
3123   bfp = currentFormDataPtr;
3124 #else
3125   bfp = GetObjectExtra (i);
3126 #endif
3127   if (bfp == NULL) return;
3128 
3129   dlg = (RemoveGeneXrefPtr) MemNew (sizeof (RemoveGeneXrefData));
3130   if (dlg == NULL) return;
3131   
3132   w = FixedWindow (-50, -33, -10, -10, "Remove Gene Xrefs", StdCloseWindowProc);
3133   SetObjectExtra (w, dlg, StdCleanupExtraProc);
3134   dlg->form = (ForM) w;
3135   dlg->input_entityID = bfp->input_entityID;
3136   
3137   h = HiddenGroup (w, -1, 0, NULL);
3138   SetGroupSpacing (h, 10, 10);
3139 
3140   sep = GetTopSeqEntryForEntityID(bfp->input_entityID);
3141   dlg->feature_select =  FeatureSelectionDialogEx (h, TRUE, sep,
3142                                                  RemoveGeneXrefsChangeNotify, 
3143                                                  dlg);
3144   
3145   k = NormalGroup (h, 0, 3, "Remove Gene Xrefs that are", programFont, NULL);
3146   dlg->suppressing = CheckBox (k, "Suppressing", RemoveGeneXrefsChangeBtn);
3147   SetObjectExtra (dlg->suppressing, dlg, NULL);
3148   dlg->nonsuppressing = CheckBox (k, "Non-Suppressing", RemoveGeneXrefsChangeBtn);
3149   SetObjectExtra (dlg->nonsuppressing, dlg, NULL);
3150   dlg->unnecessary = CheckBox (k, "Unnecessary", RemoveGeneXrefsChangeBtn);
3151   SetObjectExtra (dlg->unnecessary, dlg, NULL);
3152   
3153   dlg->constraints = FilterGroup (h, TRUE, FALSE, TRUE, FALSE, FALSE, "Where feature text");
3154   dlg->accept_cancel = AcceptCancelDialog (h, RemoveGeneXrefsAction, NULL, RemoveGeneXrefsClear, RemoveGeneXrefsClearText, (Pointer)dlg, w);
3155   AlignObjects (ALIGN_CENTER, (HANDLE) dlg->feature_select,
3156                               (HANDLE) k,
3157                               (HANDLE) dlg->constraints,
3158                               (HANDLE) dlg->accept_cancel, NULL);
3159                                 
3160   Show (w);
3161 }
3162 
3163 static void DoRefreshGeneXrefs (SeqFeatPtr sfp, Pointer userdata)
3164 
3165 {
3166   SeqFeatXrefPtr    curr;
3167   GeneRefPtr        grp, grpfeat;
3168   SeqFeatPtr        gene;
3169   SeqMgrFeatContext fcontext;
3170   BioseqPtr         bsp;
3171 
3172   if (sfp == NULL) return;
3173 
3174   for (curr = sfp->xref; curr != NULL; curr = curr->next)
3175   {
3176     if (curr->data.choice == SEQFEAT_GENE) {
3177       grp = (GeneRefPtr) curr->data.value.ptrvalue;
3178       if (grp != NULL)
3179       {
3180         bsp = BioseqFindFromSeqLoc (sfp->location);
3181         gene = SeqMgrGetFeatureByLabel (bsp, grp->locus, SEQFEAT_GENE, 0, &fcontext);
3182         if (gene != NULL && gene->data.choice == SEQFEAT_GENE) {
3183           grpfeat = (GeneRefPtr) gene->data.value.ptrvalue;
3184           if (grpfeat != NULL) {
3185             GeneRefFree (grp);
3186             grp = GeneRefDup (grpfeat);
3187             curr->data.value.ptrvalue = grp;
3188           }
3189         }
3190       }
3191     }
3192   }
3193 }
3194 
3195 static void RefreshGeneXRefs (IteM i)
3196 
3197 {
3198   BaseFormPtr  bfp;
3199   SeqEntryPtr  sep;
3200 
3201 #ifdef WIN_MAC
3202   bfp = currentFormDataPtr;
3203 #else
3204   bfp = GetObjectExtra (i);
3205 #endif
3206   if (bfp == NULL) return;
3207   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3208   if (sep == NULL) return;
3209   VisitFeaturesInSep (sep, NULL, DoRefreshGeneXrefs);
3210   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
3211   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
3212 }
3213 
3214 static ValNodePtr RemoveDbxrefList (ValNodePtr vnp)
3215 
3216 {
3217   ValNodePtr  next;
3218 
3219   while (vnp != NULL) {
3220     next = vnp->next;
3221     DbtagFree ((DbtagPtr) vnp->data.ptrvalue);
3222     MemFree (vnp);
3223     vnp = next;
3224   }
3225   return NULL;
3226 }
3227 
3228 static void DoRemoveDbxrefs (SeqFeatPtr sfp, Pointer userdata)
3229 
3230 {
3231   GeneRefPtr  grp;
3232   Uint1       feattype;
3233 
3234   if (sfp == NULL) return;
3235 
3236   if (userdata != NULL && (feattype = *(Uint1 PNTR)userdata) != sfp->data.choice) return;
3237   sfp->dbxref = RemoveDbxrefList (sfp->dbxref);
3238   if (sfp->data.choice != SEQFEAT_GENE) return;
3239   grp = (GeneRefPtr) sfp->data.value.ptrvalue;
3240   if (grp == NULL) return;
3241   grp->db = RemoveDbxrefList (grp->db);
3242 }
3243 
3244 static void DoRemoveBioSourceDbxrefs (BioSourcePtr biop, Pointer userdata)
3245 {
3246   if (biop == NULL || biop->org == NULL) return;
3247   
3248   biop->org->db = RemoveDbxrefList (biop->org->db);
3249 }
3250 
3251 static void RemoveDbxrefsCommon (IteM i, Uint1 PNTR subtype, Boolean remove_source, Boolean remove_features)
3252 
3253 {
3254   BaseFormPtr  bfp;
3255   SeqEntryPtr  sep;
3256 
3257 #ifdef WIN_MAC
3258   bfp = currentFormDataPtr;
3259 #else
3260   bfp = GetObjectExtra (i);
3261 #endif
3262   if (bfp == NULL) return;
3263   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3264   if (sep == NULL) return;
3265   if (remove_features) {
3266     VisitFeaturesInSep (sep, subtype, DoRemoveDbxrefs);
3267   }
3268   if (subtype == NULL && remove_source)
3269   {
3270     VisitBioSourcesInSep (sep, NULL, DoRemoveBioSourceDbxrefs);
3271   }
3272   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
3273   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
3274 }
3275 
3276 static void RemoveGeneDbxrefs (IteM i)
3277 {
3278   Uint1        subtype = SEQFEAT_GENE;
3279   RemoveDbxrefsCommon (i, &subtype, FALSE, TRUE);
3280 }
3281 
3282 static void RemoveRNADbxrefs (IteM i)
3283 
3284 {
3285   Uint1        subtype = SEQFEAT_RNA;
3286 
3287   RemoveDbxrefsCommon (i, &subtype, FALSE, TRUE);
3288 }
3289 
3290 static void RemoveCDSDbxrefs (IteM i)
3291 
3292 {
3293   Uint1        subtype = FEATDEF_CDS;
3294   RemoveDbxrefsCommon (i, &subtype, FALSE, TRUE);
3295 }
3296 
3297 static void RemoveAllFeatureDbxrefs (IteM i)
3298 {
3299   RemoveDbxrefsCommon (i, NULL, FALSE, TRUE);
3300 }
3301 
3302 static void RemoveAllDbxrefs (IteM i)
3303 
3304 {
3305   RemoveDbxrefsCommon (i, NULL, TRUE, TRUE);
3306 }
3307 
3308 
3309 static void RemoveAllBioSourceDbxrefs (IteM i)
3310 
3311 {
3312   RemoveDbxrefsCommon (i, NULL, TRUE, FALSE);
3313 }
3314 
3315 
3316 static void RemoveMissingFeatureXrefsCallback (SeqFeatPtr sfp, Pointer data)
3317 
3318 {
3319   SeqFeatXrefPtr  xref, xref_next, xref_prev = NULL;
3320   SeqFeatPtr      matchsfp;
3321 
3322   if (sfp == NULL) {
3323     return;
3324   }
3325 
3326   for (xref = sfp->xref; xref != NULL; xref = xref_next) {
3327     xref_next = xref->next;
3328     if (xref->id.choice != 0
3329         && (matchsfp = SeqMgrGetFeatureByFeatID (sfp->idx.entityID, NULL, NULL, xref, NULL)) == NULL) {
3330       if (xref_prev == NULL) {
3331         sfp->xref = xref->next;
3332       } else {
3333         xref_prev->next = xref->next;
3334       }
3335       xref->next = NULL;
3336       xref = SeqFeatXrefFree (xref);
3337     } else {
3338       xref_prev = xref;
3339     }
3340   }
3341 }
3342 
3343 
3344 static void RemoveMissingFeatureXrefs (IteM i)
3345 
3346 {
3347   BaseFormPtr  bfp;
3348   SeqEntryPtr  sep;
3349 
3350 #ifdef WIN_MAC
3351   bfp = currentFormDataPtr;
3352 #else
3353   bfp = GetObjectExtra (i);
3354 #endif
3355   if (bfp == NULL) return;
3356   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3357   if (sep == NULL) return;
3358   WatchCursor();
3359   Update();
3360   VisitFeaturesInSep (sep, NULL, RemoveMissingFeatureXrefsCallback);
3361   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
3362   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
3363   ArrowCursor();
3364   Update();
3365 }
3366 
3367 
3368 static void ClearPubFig (PubdescPtr pdp, Pointer userdata)
3369 
3370 {
3371   if (pdp == NULL) return;
3372   pdp->fig = MemFree (pdp->fig);
3373   pdp->num = NumberingFree (pdp->num);
3374 }
3375 
3376 static void RemovePubFig (IteM i)
3377 
3378 {
3379   BaseFormPtr  bfp;
3380   SeqEntryPtr  sep;
3381 
3382 #ifdef WIN_MAC
3383   bfp = currentFormDataPtr;
3384 #else
3385   bfp = GetObjectExtra (i);
3386 #endif
3387   if (bfp == NULL) return;
3388   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3389   if (sep == NULL) return;
3390   VisitPubdescsInSep (sep, NULL, ClearPubFig);
3391   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
3392   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
3393 }
3394 
3395 static void RemoveSelFeats (IteM i)
3396 
3397 {
3398   MsgAnswer          ans;
3399   BaseFormPtr        bfp;
3400   BioseqPtr          cdna;
3401   SeqMgrFeatContext  fcontext;
3402   BioseqPtr          prot;
3403   Boolean            remove_asked;
3404   Boolean            remove_mrnas = FALSE;
3405   Boolean            remove_prots = FALSE;
3406   SelStructPtr       sel;
3407   SeqEntryPtr        sep;
3408   SeqFeatPtr         sfp;
3409   SelStructPtr       ssp;
3410   Boolean            unremoved_feats = FALSE;
3411 
3412 #ifdef WIN_MAC
3413   bfp = currentFormDataPtr;
3414 #else
3415   bfp = GetObjectExtra (i);
3416 #endif
3417   if (bfp == NULL) return;
3418   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3419   if (sep == NULL) return;
3420 
3421   ssp = ObjMgrGetSelected ();
3422   if (ssp == NULL) return;
3423 
3424   remove_asked = FALSE;
3425   for (sel = ssp; sel != NULL; sel = sel->next) {
3426     if (sel->entityID != bfp->input_entityID) 
3427     {
3428       unremoved_feats = TRUE;
3429       continue;      
3430     }
3431     if (sel->itemtype == OBJ_SEQFEAT) {
3432       sfp = SeqMgrGetDesiredFeature (sel->entityID, NULL, sel->itemID, 0, NULL, &fcontext);
3433       if (sfp != NULL) {
3434         sfp->idx.deleteme = TRUE;
3435         if (sfp->data.choice == SEQFEAT_CDREGION && sfp->product != NULL) {
3436           prot = BioseqFindFromSeqLoc (sfp->product);
3437           if (prot != NULL) {
3438             if (! remove_asked) {
3439               ans = Message (MSG_YN, "Remove protein products?");
3440               if (ans == ANS_YES) {
3441                 remove_prots = TRUE;
3442               }
3443               remove_asked = TRUE;
3444             }
3445             if (remove_prots) {
3446               prot->idx.deleteme = TRUE;
3447             }
3448           }
3449         }
3450       }
3451     }
3452   }
3453 
3454   remove_asked = FALSE;
3455   for (sel = ssp; sel != NULL; sel = sel->next) {
3456     if (sel->entityID != bfp->input_entityID) 
3457     {
3458       unremoved_feats = TRUE;
3459       continue;      
3460     }
3461     if (sel->itemtype == OBJ_SEQFEAT) {
3462       sfp = SeqMgrGetDesiredFeature (sel->entityID, NULL, sel->itemID, 0, NULL, &fcontext);
3463       if (sfp != NULL) {
3464         sfp->idx.deleteme = TRUE;
3465         if (sfp->data.choice == SEQFEAT_RNA && sfp->product != NULL) {
3466           cdna = BioseqFindFromSeqLoc (sfp->product);
3467           if (cdna != NULL) {
3468             if (! remove_asked) {
3469               ans = Message (MSG_YN, "Remove mRNA products?");
3470               if (ans == ANS_YES) {
3471                 remove_mrnas = TRUE;
3472               }
3473               remove_asked = TRUE;
3474             }
3475             if (remove_mrnas) {
3476               cdna->idx.deleteme = TRUE;
3477             }
3478           }
3479         }
3480       }
3481     }
3482   }
3483 
3484   ObjMgrSelect (0, 0, 0, 0, NULL);
3485 
3486   DeleteMarkedObjects (bfp->input_entityID, 0, NULL);
3487 
3488   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
3489   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
3490   if (unremoved_feats)
3491   {
3492     Message (MSG_ERROR, "Warning!  Features mapped to far sequences cannot be deleted!");
3493   }
3494 }
3495 
3496 static void RemoveUnselFeats (IteM i)
3497 
3498 {
3499   MsgAnswer          ans;
3500   BaseFormPtr        bfp;
3501   BioseqPtr          bsp;
3502   BioseqPtr          cdna;
3503   SeqMgrFeatContext  fcontext;
3504   BioseqPtr          prot;
3505   Boolean            remove_asked;
3506   Boolean            remove_mrnas = FALSE;
3507   Boolean            remove_prots = FALSE;
3508   SelStructPtr       sel;
3509   SeqEntryPtr        sep;
3510   SeqFeatPtr         sfp;
3511   SelStructPtr       ssp;
3512   SeqEntryPtr        scope;
3513   Boolean            sel_on_local = FALSE;
3514   Boolean            sel_on_far = FALSE;
3515 
3516 #ifdef WIN_MAC
3517   bfp = currentFormDataPtr;
3518 #else
3519   bfp = GetObjectExtra (i);
3520 #endif
3521   if (bfp == NULL) return;
3522   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3523   if (sep == NULL) return;
3524 
3525   ssp = ObjMgrGetSelected ();
3526   if (ssp == NULL) return;
3527 
3528   scope = SeqEntrySetScope (NULL);
3529   bsp = NULL;
3530   for (sel = ssp; sel != NULL && bsp == NULL; sel = sel->next) {
3531     if (sel->entityID != bfp->input_entityID) 
3532     {
3533       if (sel->itemtype == OBJ_SEQFEAT)
3534       {
3535         sel_on_far = TRUE;
3536       }
3537       continue;
3538     }    
3539     if (sel->itemtype == OBJ_SEQFEAT) {
3540       sel_on_local = TRUE;
3541       sfp = SeqMgrGetDesiredFeature (sel->entityID, NULL, sel->itemID, 0, NULL, &fcontext);
3542       if (sfp != NULL) {
3543         bsp = BioseqFindFromSeqLoc (sfp->location);
3544       }
3545     }
3546   }
3547   SeqEntrySetScope (scope);
3548   if (bsp == NULL) 
3549   {
3550     if (sel_on_far && ! sel_on_local)
3551     {
3552       Message (MSG_ERROR, "Warning!  Features mapped to far sequences cannot be deleted!");
3553     }
3554     return;
3555   }
3556 
3557   sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &fcontext);
3558   while (sfp != NULL) {
3559     sfp->idx.deleteme = TRUE;
3560     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &fcontext);
3561   }
3562 
3563   for (sel = ssp; sel != NULL; sel = sel->next) {
3564     if (sel->entityID != bfp->input_entityID) continue;
3565     if (sel->itemtype == OBJ_SEQFEAT) {
3566       sfp = SeqMgrGetDesiredFeature (0, bsp, sel->itemID, 0, NULL, &fcontext);
3567       if (sfp != NULL) {
3568         sfp->idx.deleteme = FALSE;
3569       }
3570     }
3571   }
3572 
3573   remove_asked = FALSE;
3574   sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &fcontext);
3575   while (sfp != NULL) {
3576     if (sfp->idx.deleteme) {
3577       if (sfp->data.choice == SEQFEAT_CDREGION && sfp->product != NULL) {
3578         prot = BioseqFindFromSeqLoc (sfp->product);
3579         if (prot != NULL) {
3580           if (! remove_asked) {
3581             ans = Message (MSG_YN, "Remove protein products?");
3582             if (ans == ANS_YES) {
3583               remove_prots = TRUE;
3584             }
3585             remove_asked = TRUE;
3586           }
3587           if (remove_prots) {
3588             prot->idx.deleteme = TRUE;
3589           }
3590         }
3591       }
3592     }
3593     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &fcontext);
3594   }
3595 
3596   remove_asked = FALSE;
3597   sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &fcontext);
3598   while (sfp != NULL) {
3599     if (sfp->idx.deleteme) {
3600       if (sfp->data.choice == SEQFEAT_RNA && sfp->product != NULL) {
3601         cdna = BioseqFindFromSeqLoc (sfp->product);
3602         if (cdna != NULL) {
3603           if (! remove_asked) {
3604             ans = Message (MSG_YN, "Remove mRNA products?");
3605             if (ans == ANS_YES) {
3606               remove_mrnas = TRUE;
3607             }
3608             remove_asked = TRUE;
3609           }
3610           if (remove_mrnas) {
3611             cdna->idx.deleteme = TRUE;
3612           }
3613         }
3614       }
3615     }
3616     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &fcontext);
3617   }
3618 
3619   ObjMgrSelect (0, 0, 0, 0, NULL);
3620 
3621   DeleteMarkedObjects (bfp->input_entityID, 0, NULL);
3622 
3623   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
3624   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
3625 }
3626 
3627 static void RemoveFeatsOutOfSelRange (IteM i)
3628 
3629 {
3630   MsgAnswer          ans;
3631   BaseFormPtr        bfp;
3632   BioseqPtr          bsp;
3633   BioseqPtr          cdna;
3634   SeqMgrFeatContext  fcontext;
3635   BioseqPtr          prot;
3636   Boolean            remove_asked;
3637   Boolean            remove_mrnas = FALSE;
3638   Boolean            remove_prots = FALSE;
3639   SelStructPtr       sel;
3640   SeqEntryPtr        sep;
3641   SeqFeatPtr         sfp;
3642   SeqLocPtr          slp = NULL;
3643   SelStructPtr       ssp;
3644   SeqEntryPtr        scope;
3645   Boolean            sel_on_local = FALSE;
3646   Boolean            sel_on_far = FALSE;
3647 
3648 #ifdef WIN_MAC
3649   bfp = currentFormDataPtr;
3650 #else
3651   bfp = GetObjectExtra (i);
3652 #endif
3653   if (bfp == NULL) return;
3654   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3655   if (sep == NULL) return;
3656 
3657   ssp = ObjMgrGetSelected ();
3658   if (ssp == NULL) {
3659     Message (MSG_ERROR, "Warning!  No features are selected - please select one");
3660     return;
3661   }
3662   if (ssp->next != NULL) {
3663     Message (MSG_ERROR, "Warning!  Multiple features are selected - please select only one");
3664     return;
3665   }
3666 
3667   scope = SeqEntrySetScope (NULL);
3668   bsp = NULL;
3669   for (sel = ssp; sel != NULL && bsp == NULL; sel = sel->next) {
3670     if (sel->entityID != bfp->input_entityID) 
3671     {
3672       if (sel->itemtype == OBJ_SEQFEAT)
3673       {
3674         sel_on_far = TRUE;
3675       }
3676       continue;
3677     }    
3678     if (sel->itemtype == OBJ_SEQFEAT) {
3679       sel_on_local = TRUE;
3680       sfp = SeqMgrGetDesiredFeature (sel->entityID, NULL, sel->itemID, 0, NULL, &fcontext);
3681       if (sfp != NULL) {
3682         slp = sfp->location;
3683         bsp = BioseqFindFromSeqLoc (slp);
3684       }
3685     }
3686   }
3687   SeqEntrySetScope (scope);
3688   if (bsp == NULL) 
3689   {
3690     if (sel_on_far && ! sel_on_local)
3691     {
3692       Message (MSG_ERROR, "Warning!  Please select only a feature on a near sequence");
3693     }
3694     return;
3695   }
3696   if (slp == NULL) {
3697     Message (MSG_ERROR, "Warning!  Failure to get location from selected feature");
3698     return;
3699   }
3700 
3701   sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &fcontext);
3702   while (sfp != NULL) {
3703     if (SeqLocAinB (sfp->location, slp) >= 0) {
3704       sfp->idx.deleteme = FALSE;
3705     } else {
3706       sfp->idx.deleteme = TRUE;
3707     }
3708     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &fcontext);
3709   }
3710 
3711   remove_asked = FALSE;
3712   sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &fcontext);
3713   while (sfp != NULL) {
3714     if (sfp->idx.deleteme) {
3715       if (sfp->data.choice == SEQFEAT_CDREGION && sfp->product != NULL) {
3716         prot = BioseqFindFromSeqLoc (sfp->product);
3717         if (prot != NULL) {
3718           if (! remove_asked) {
3719             ans = Message (MSG_YN, "Remove protein products?");
3720             if (ans == ANS_YES) {
3721               remove_prots = TRUE;
3722             }
3723             remove_asked = TRUE;
3724           }
3725           if (remove_prots) {
3726             prot->idx.deleteme = TRUE;
3727           }
3728         }
3729       }
3730     }
3731     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &fcontext);
3732   }
3733 
3734   remove_asked = FALSE;
3735   sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &fcontext);
3736   while (sfp != NULL) {
3737     if (sfp->idx.deleteme) {
3738       if (sfp->data.choice == SEQFEAT_RNA && sfp->product != NULL) {
3739         cdna = BioseqFindFromSeqLoc (sfp->product);
3740         if (cdna != NULL) {
3741           if (! remove_asked) {
3742             ans = Message (MSG_YN, "Remove mRNA products?");
3743             if (ans == ANS_YES) {
3744               remove_mrnas = TRUE;
3745             }
3746             remove_asked = TRUE;
3747           }
3748           if (remove_mrnas) {
3749             cdna->idx.deleteme = TRUE;
3750           }
3751         }
3752       }
3753     }
3754     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &fcontext);
3755   }
3756 
3757   ObjMgrSelect (0, 0, 0, 0, NULL);
3758 
3759   DeleteMarkedObjects (bfp->input_entityID, 0, NULL);
3760 
3761   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
3762   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
3763 }
3764 
3765 static void RemoveCDDRegions (IteM i)
3766 
3767 {
3768   BaseFormPtr  bfp;
3769   SeqEntryPtr  sep;
3770 
3771 #ifdef WIN_MAC
3772   bfp = currentFormDataPtr;
3773 #else
3774   bfp = GetObjectExtra (i);
3775 #endif
3776   if (bfp == NULL) return;
3777   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3778   if (sep == NULL) return;
3779   FreeCDDRegions (sep);
3780   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
3781   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
3782 }
3783 
3784 static void RemoveCDDAligns (IteM i)
3785 
3786 {
3787   BaseFormPtr  bfp;
3788   SeqEntryPtr  sep;
3789 
3790 #ifdef WIN_MAC
3791   bfp = currentFormDataPtr;
3792 #else
3793   bfp = GetObjectExtra (i);
3794 #endif
3795   if (bfp == NULL) return;
3796   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3797   if (sep == NULL) return;
3798   FreeCDDAligns (sep);
3799   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
3800   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
3801 }
3802 
3803 static void RemoveCDDDups (IteM i)
3804 
3805 {
3806   BaseFormPtr  bfp;
3807   SeqEntryPtr  sep;
3808 
3809 #ifdef WIN_MAC
3810   bfp = currentFormDataPtr;
3811 #else
3812   bfp = GetObjectExtra (i);
3813 #endif
3814   if (bfp == NULL) return;
3815   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3816   if (sep == NULL) return;
3817   RemoveDuplicateCDDs (sep);
3818   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
3819   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
3820 }
3821 
3822 static void RetainBestCDD (IteM i)
3823 
3824 {
3825   BaseFormPtr  bfp;
3826   SeqEntryPtr  sep;
3827 
3828 #ifdef WIN_MAC
3829   bfp = currentFormDataPtr;
3830 #else
3831   bfp = GetObjectExtra (i);
3832 #endif
3833   if (bfp == NULL) return;
3834   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3835   if (sep == NULL) return;
3836   LeaveBestCDD (sep);
3837   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
3838   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
3839 }
3840 
3841 static void LastDitchLookup (BioSourcePtr biop)
3842 
3843 {
3844   DbtagPtr      dbt;
3845   Char          orgname [256];
3846   OrgRefPtr     orp;
3847   CharPtr       ptr;
3848   CharPtr       binomial_end = NULL, trinomial_end = NULL;
3849   SubSourcePtr  ssp;
3850   Int4          taxID;
3851   ValNodePtr    vnp;
3852 
3853   if (biop == NULL) return;
3854   orp = biop->org;
3855   if (orp == NULL) return;
3856   /* if this organism has already been assigned a taxon ID, skip it */
3857   if (orp->db != NULL) {
3858     for (vnp = orp->db; vnp != NULL; vnp = vnp->next) {
3859       dbt = (DbtagPtr) vnp->data.ptrvalue;
3860       if (dbt != NULL) {
3861         if (StringICmp (dbt->db, "taxon") == 0) return;
3862       }
3863     }
3864   }
3865   /* we are looking for a name that might become a recognizable name if we
3866    * truncated it after the first four words (if the third word is subsp.),
3867    * after the first three words (if the third word is not subsp.),
3868    * or after the first two words if the above two attempts failed.
3869    */
3870  
3871   StringNCpy_0 (orgname, orp->taxname, sizeof (orgname));
3872   if (StringHasNoText (orgname)) return;
3873   ptr = StringChr (orgname, ' ');
3874   if (ptr == NULL) return;
3875   /* skip over the first word and the spaces after it. */
3876   while (*ptr == ' ') 
3877   {
3878     ptr++;
3879   }
3880   ptr = StringChr (ptr, ' ');
3881   /* if there are only two words, give up. */
3882   if (ptr == NULL) 
3883   {
3884     return;
3885   }
3886   binomial_end = ptr;
3887   while (*ptr == ' ')
3888   {
3889     ptr++;
3890   }
3891   if (StringNCmp (ptr, "subsp.", 6) == 0)
3892   {
3893     ptr += 6;
3894     while (*ptr == ' ' )
3895     {
3896       ptr++;
3897     }
3898   }
3899   
3900   ptr = StringChr (ptr, ' ');
3901   if (ptr != NULL)
3902   {
3903     trinomial_end = ptr;
3904   }
3905   
3906   /* see if trinomial produces a tax server hit */
3907   taxID = 0;
3908   if (trinomial_end != NULL)
3909   {
3910     *trinomial_end = '\0';
3911     taxID = Taxon3GetTaxIdByName (orgname);
3912   }
3913   if (taxID < 1)
3914   {
3915     /* see if binomial produces a tax server hit */
3916     *binomial_end = '\0';
3917     taxID = Taxon3GetTaxIdByName (orgname);
3918   }
3919   
3920   if (taxID < 1) return;
3921   
3922   /* create a note that contains the original name of the organism, and truncate
3923    * the actual organism after the binomial or trinomial.
3924    */
3925   ssp = SubSourceNew ();
3926   if (ssp != NULL) {
3927     ssp->subtype = 255;
3928     ssp->name = orp->taxname;
3929         orp->taxname = NULL;
3930     ssp->next = biop->subtype;
3931     biop->subtype = ssp;
3932     SetTaxNameAndRemoveTaxRef (orp, StringSave (orgname));
3933   }
3934 }
3935 
3936 static void LastDitchTaxonFixup (SeqEntryPtr sep, Pointer data, Int4 index, Int2 indent)
3937 
3938 {
3939         BioseqPtr bsp = NULL;
3940         BioseqSetPtr bssp = NULL;
3941         ValNodePtr descr, vnp;
3942         BioSourcePtr biosp = NULL;
3943         SeqAnnotPtr annot, sap;
3944         SeqFeatPtr sfp;
3945         
3946         if (IS_Bioseq(sep)) {
3947                 bsp = sep->data.ptrvalue;
3948                 descr = bsp->descr;
3949                 annot = bsp->annot;
3950         } else {
3951                 bssp = sep->data.ptrvalue;
3952                 descr = bssp->descr;
3953                 annot = bssp->annot;
3954         }
3955         for (vnp = descr; vnp; vnp = vnp->next) {
3956                 if (vnp->choice == Seq_descr_source) {
3957                         biosp = vnp->data.ptrvalue;
3958                         LastDitchLookup (biosp); 
3959                 }
3960         }
3961         for (sap = annot; sap != NULL; sap = sap->next) {
3962                 if (sap->type == 1) {
3963                         for (sfp = (SeqFeatPtr) sap->data; sfp != NULL; sfp = sfp->next) {
3964                                 if (sfp->data.choice == SEQFEAT_BIOSRC) {
3965                                         biosp = sfp->data.value.ptrvalue;
3966                                         LastDitchLookup (biosp);
3967                                 }
3968                         }
3969                 }
3970         }
3971 }
3972 
3973 static void GenSpecTaxonFixup (IteM i)
3974 
3975 {
3976   BaseFormPtr  bfp;
3977   SeqEntryPtr  sep;
3978 
3979 #ifdef WIN_MAC
3980   bfp = currentFormDataPtr;
3981 #else
3982   bfp = GetObjectExtra (i);
3983 #endif
3984   if (bfp == NULL) return;
3985   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3986   if (sep == NULL) return;
3987   SeqEntryExplore (sep, NULL, LastDitchTaxonFixup);
3988   ForceTaxonFixupBtn (i, NULL);
3989 }
3990 
3991 
3992 static void MergeToPartsCallback (SeqFeatPtr sfp, Pointer userdata)
3993 {
3994   BoolPtr ordered;
3995   
3996   if (sfp == NULL) return;
3997   ordered = (BoolPtr) userdata;
3998   
3999   MergeFeatureIntervalsToParts (sfp, *ordered);
4000 }
4001 
4002 static void MergeToParts (IteM i, Boolean ordered)
4003 {
4004   BaseFormPtr       bfp;
4005   SelStructPtr      ssp;
4006   Boolean           some_sel_not_feat = FALSE;
4007   Boolean           some_sel_feat = FALSE;
4008   SeqFeatPtr        sfp;
4009   SeqMgrFeatContext fcontext;
4010   SeqEntryPtr       sep;
4011 
4012   ssp = ObjMgrGetSelected ();
4013   if (ssp == NULL) {
4014 #ifdef WIN_MAC
4015     bfp = currentFormDataPtr;
4016 #else
4017     bfp = GetObjectExtra (i);
4018 #endif
4019     if (bfp == NULL) {
4020       Message (MSG_ERROR, "MergeToParts error");
4021       return;
4022     }
4023     sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
4024     if (sep == NULL) return;
4025     VisitFeaturesInSep (sep, (Pointer) &ordered, MergeToPartsCallback);
4026     ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
4027     ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
4028   }
4029   else
4030   {
4031     while (ssp != NULL)
4032     {
4033       if (ssp->itemtype == OBJ_SEQFEAT)
4034       {
4035         sfp = SeqMgrGetDesiredFeature (ssp->entityID, NULL, ssp->itemID, 0, NULL, &fcontext);
4036         if (sfp != NULL)
4037         {
4038           MergeFeatureIntervalsToParts (sfp, ordered);
4039           some_sel_feat = TRUE;
4040           ObjMgrSetDirtyFlag (ssp->entityID, TRUE);
4041           ObjMgrSendMsg (OM_MSG_UPDATE, ssp->entityID, 0, 0);
4042         }
4043       }
4044       else
4045       {
4046         some_sel_not_feat = TRUE;        
4047       }
4048       ssp = ssp->next;
4049     }
4050     if (!some_sel_feat)
4051     {
4052       Message (MSG_ERROR, "No features selected!");
4053     }
4054     else if (some_sel_not_feat)
4055     {
4056       Message (MSG_ERROR, "Some selected items were not features!");
4057     }
4058   }
4059   Update ();
4060 }
4061 
4062 extern void MergeToPartsJoin (IteM i)
4063 {
4064   MergeToParts (i, FALSE);
4065 }
4066 
4067 extern void MergeToPartsOrdered (IteM i)
4068 {
4069   MergeToParts (i, TRUE);
4070 }
4071 
4072 
4073 static Boolean MergeSegSeqCallback (GatherContextPtr gcp)
4074 
4075 {
4076   BioseqPtr     bsp;
4077   CodeBreakPtr  cbp;
4078   CdRegionPtr   crp;
4079   Boolean       noLeft;
4080   Boolean       noRight;
4081   RnaRefPtr     rrp;
4082   SeqEntryPtr   sep;
4083   SeqFeatPtr    sfp;
4084   SeqLocPtr     slp;
4085   tRNAPtr       trna;
4086 
4087   if (gcp->thistype != OBJ_SEQFEAT) return TRUE;
4088   sfp = (SeqFeatPtr) gcp->thisitem;
4089   if (sfp == NULL || sfp->location == NULL) return TRUE;
4090   bsp = GetBioseqGivenSeqLoc (sfp->location, gcp->entityID);
4091   if (bsp == NULL) return TRUE;
4092   if (ISA_aa (bsp->mol)) return TRUE;
4093   if (bsp->repr != Seq_repr_seg) {
4094     sep = GetBestTopParentForData (gcp->entityID, bsp);
4095     if (sep == NULL) return TRUE;
4096     sep = FindNucSeqEntry (sep);
4097     if (sep == NULL || sep->choice != 1) return TRUE;
4098     bsp = (BioseqPtr) sep->data.ptrvalue;
4099     if (bsp == NULL) return TRUE;
4100   }
4101   CheckSeqLocForPartial (sfp->location, &noLeft, &noRight);
4102   slp = SeqLocMerge (bsp, sfp->location, NULL, FALSE, TRUE, FALSE);
4103   if (slp == NULL) return TRUE;
4104   sfp->location = SeqLocFree (sfp->location);
4105   sfp->location = slp;
4106   FreeAllFuzz (sfp->location);
4107   SetSeqLocPartial (sfp->location, noLeft, noRight);
4108   sfp->partial = (sfp->partial || noLeft || noRight);
4109   switch (sfp->data.choice) {
4110     case SEQFEAT_CDREGION :
4111       crp = (CdRegionPtr) sfp->data.value.ptrvalue;
4112       if (crp != NULL && crp->code_break != NULL) {
4113         for (cbp = crp->code_break; cbp != NULL; cbp = cbp->next) {
4114           slp = SeqLocMerge (bsp, cbp->loc, NULL, FALSE, TRUE, FALSE);
4115           if (slp != NULL) {
4116             cbp->loc = SeqLocFree (cbp->loc);
4117             cbp->loc = slp;
4118             FreeAllFuzz (cbp->loc);
4119           }
4120         }
4121       }
4122       break;
4123     case SEQFEAT_RNA :
4124       rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
4125       if (rrp != NULL && rrp->type == 3 && rrp->ext.choice == 2) {
4126         trna = rrp->ext.value.ptrvalue;
4127         if (trna != NULL && trna->anticodon != NULL) {
4128           slp = SeqLocMerge (bsp, trna->anticodon, NULL, FALSE, TRUE, FALSE);
4129           if (slp != NULL) {
4130             trna->anticodon = SeqLocFree (trna->anticodon);
4131             trna->anticodon = slp;
4132             FreeAllFuzz (trna->anticodon);
4133           }
4134         }
4135       }
4136       break;
4137     default :
4138       break;
4139   }
4140   return TRUE;
4141 }
4142 
4143 static void MergeToSegSeq (IteM i)
4144 
4145 {
4146   BaseFormPtr   bfp;
4147   GatherScope   gs;
4148   SelStructPtr  ssp;
4149 
4150   ssp = ObjMgrGetSelected ();
4151   if (ssp == NULL) {
4152 #ifdef WIN_MAC
4153     bfp = currentFormDataPtr;
4154 #else
4155     bfp = GetObjectExtra (i);
4156 #endif
4157     if (bfp == NULL) {
4158       Message (MSG_ERROR, "MergeToSegSeq error");
4159       return;
4160     }
4161     MemSet ((Pointer) (&gs), 0, sizeof (GatherScope));
4162     gs.seglevels = 1;
4163     MemSet((Pointer)(gs.ignore), (int)(TRUE), (size_t)(OBJ_MAX * sizeof(Boolean)));
4164     gs.ignore[OBJ_BIOSEQ] = FALSE;
4165     gs.ignore[OBJ_BIOSEQ_SEG] = FALSE;
4166     gs.ignore[OBJ_SEQANNOT] = FALSE;
4167     gs.ignore[OBJ_SEQFEAT] = FALSE;
4168     GatherEntity (bfp->input_entityID, NULL, MergeSegSeqCallback, &gs);
4169     ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
4170     ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
4171     /*
4172     Message (MSG_ERROR, "No item selected");
4173     */
4174     return;
4175   }
4176   if (ssp->itemtype != OBJ_SEQFEAT) {
4177     Message (MSG_ERROR, "Feature must be selected");
4178     return;
4179   }
4180   GatherItem (ssp->entityID, ssp->itemID, ssp->itemtype, NULL, MergeSegSeqCallback);
4181   ObjMgrSetDirtyFlag (ssp->entityID, TRUE);
4182   ObjMgrSendMsg (OM_MSG_UPDATE, ssp->entityID, 0, 0);
4183 }
4184 
4185 static void SegToRawCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
4186 
4187 {
4188   BioseqPtr  bsp;
4189 
4190   if (sep == NULL) return;
4191   if (! IS_Bioseq (sep)) return;
4192   bsp = (BioseqPtr) sep->data.ptrvalue;
4193   if (bsp == NULL || (bsp->repr != Seq_repr_seg && bsp->repr != Seq_repr_delta)) return;
4194   SegOrDeltaBioseqToRaw (bsp);
4195 }
4196 
4197 static void SegSeqToRawSeq (IteM i)
4198 
4199 {
4200   BaseFormPtr  bfp;
4201   SeqEntryPtr  sep;
4202 
4203 #ifdef WIN_MAC
4204   bfp = currentFormDataPtr;
4205 #else
4206   bfp = GetObjectExtra (i);
4207 #endif
4208   if (bfp == NULL) return;
4209   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
4210   if (sep == NULL) return;
4211   SeqEntryExplore (sep, (Pointer) bfp, SegToRawCallback);
4212   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
4213   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
4214   Message (MSG_OK, "Some manual desktop manipulations remain");
4215 }
4216 
4217 static void CollectBioseqsForConversion (BioseqPtr bsp, Pointer userdata)
4218 {
4219   ValNodePtr PNTR list;
4220   
4221   if (bsp == NULL || bsp->repr != Seq_repr_raw || ISA_aa (bsp->mol)) return;
4222   if (userdata == NULL)
4223   {
4224     return;
4225   }
4226   list = (ValNodePtr PNTR) userdata;
4227   
4228   ValNodeAddPointer (list, 0, bsp);
4229 }
4230 
4231 static ValNodePtr GetAnnotListForBspList (ValNodePtr bsp_list)
4232 {
4233   BioseqPtr   bsp;
4234   SeqAnnotPtr sanp;
4235   ValNodePtr  complete_annot_list = NULL, align_annot_list;
4236   ValNodePtr  annot_vnp, vnp, bsp_vnp;
4237   Boolean     found;
4238 
4239   for (bsp_vnp = bsp_list; bsp_vnp != NULL; bsp_vnp = bsp_vnp->next)
4240   {
4241     bsp = (BioseqPtr)(bsp_vnp->data.ptrvalue);
4242     align_annot_list = FindAlignSeqAnnotsForBioseq (bsp);
4243     for (annot_vnp = align_annot_list; annot_vnp != NULL; annot_vnp = annot_vnp->next)
4244     {
4245       sanp = (SeqAnnotPtr) annot_vnp->data.ptrvalue;
4246       if (sanp->type == 2 && sanp->data != NULL)
4247       {
4248         for (vnp = complete_annot_list, found = FALSE;
4249              vnp != NULL && !found;
4250              vnp = vnp->next)
4251         {
4252           if (vnp->data.ptrvalue == sanp)
4253           {
4254             found = TRUE;
4255           }
4256         }
4257         if (!found)
4258         {
4259           ValNodeAddPointer (&complete_annot_list, 0, sanp);
4260         }
4261       }
4262     }
4263     align_annot_list = ValNodeFree (align_annot_list);
4264   }
4265   return complete_annot_list;
4266 }
4267 
4268 
4269 static void 
4270 CleanupAlignmentsAfterConversion 
4271 (ValNodePtr adjusted_bsp_list,
4272  Uint2 entityID)
4273 {
4274   ValNodePtr  align_annot_list, annot_vnp;
4275   SeqAnnotPtr sanp;
4276   
4277   align_annot_list = GetAnnotListForBspList (adjusted_bsp_list);
4278   for (annot_vnp = align_annot_list;
4279        annot_vnp != NULL; 
4280        annot_vnp = annot_vnp->next)
4281   {
4282     sanp = annot_vnp->data.ptrvalue;
4283     if (sanp != NULL && sanp->type == 2)
4284     {
4285       ConsolidateSegmentsOverKnownLengthGaps (sanp->data);
4286       FixOneAlignmentOverGaps (sanp->data, entityID);
4287     }
4288   }
4289   align_annot_list = ValNodeFree (align_annot_list);
4290   DeleteMarkedObjects (entityID, 0, NULL);
4291   
4292 }
4293 
4294 static void CorrectAlignmentsAfterNToGapConversion (SeqEntryPtr sep, Uint2 entityID)
4295 {
4296   ValNodePtr adjusted_bsp_list = NULL;
4297   
4298   VisitBioseqsInSep (sep, &adjusted_bsp_list, CollectBioseqsForConversion);
4299   CleanupAlignmentsAfterConversion (adjusted_bsp_list, entityID);
4300   adjusted_bsp_list = ValNodeFree (adjusted_bsp_list);
4301 }
4302 
4303 static void ConvertNsToGapsWithSizeList (Uint2 entityID, Int4Ptr gap_sizes, Boolean adjust_cds)
4304 {
4305   ValNodePtr  adjusted_bsp_list = NULL;
4306   SeqEntryPtr sep;
4307   
4308   sep = GetTopSeqEntryForEntityID (entityID);
4309   if (sep == NULL) return;
4310   VisitBioseqsInSep (sep, &adjusted_bsp_list, CollectBioseqsForConversion);
4311 
4312   if (adjust_cds)
4313   {
4314     /* remove the gap locations from the coding regions first */
4315     VisitBioseqsInSep (sep, gap_sizes, PrepareCodingRegionLocationsForDeltaConversionCallback);
4316   }
4317   
4318   VisitBioseqsInSep (sep, gap_sizes, ConvertNsToGaps);
4319   CleanupAlignmentsAfterConversion (adjusted_bsp_list, entityID);
4320   adjusted_bsp_list = ValNodeFree (adjusted_bsp_list);
4321   ObjMgrSetDirtyFlag (entityID, TRUE);
4322   ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
4323 }
4324 
4325 
4326 static void RawSeqToDeltaSeq (IteM i)
4327 
4328 {
4329   BaseFormPtr  bfp;
4330 
4331 #ifdef WIN_MAC
4332   bfp = currentFormDataPtr;
4333 #else
4334   bfp = GetObjectExtra (i);
4335 #endif
4336   if (bfp == NULL) return;
4337   ConvertNsToGapsWithSizeList (bfp->input_entityID, NULL, FALSE);
4338 }
4339 
4340 static void RawSeqToDeltaSeqUnknownLengthGaps (IteM i)
4341 
4342 {
4343   BaseFormPtr  bfp;
4344   Int4         gap_sizes[2];
4345 
4346 #ifdef WIN_MAC
4347   bfp = currentFormDataPtr;
4348 #else
4349   bfp = GetObjectExtra (i);
4350 #endif
4351   if (bfp == NULL) return;
4352   gap_sizes [0] = 100;
4353   gap_sizes [1] = -1;
4354   ConvertNsToGapsWithSizeList (bfp->input_entityID, gap_sizes, FALSE);
4355 }
4356 
4357 static void RawSeqToDeltaSeqUnknown100LengthGaps (IteM i)
4358 
4359 {
4360   BaseFormPtr  bfp;
4361   Int4         gap_sizes[2];
4362 
4363 #ifdef WIN_MAC
4364   bfp = currentFormDataPtr;
4365 #else
4366   bfp = GetObjectExtra (i);
4367 #endif
4368   if (bfp == NULL) return;
4369   gap_sizes [0] = -1;
4370   gap_sizes [1] = 0;
4371   ConvertNsToGapsWithSizeList (bfp->input_entityID, gap_sizes, FALSE);
4372 }
4373 
4374 #if 0
4375 static void ConvertSegSetToDeltaItem (IteM i)
4376 {
4377   BaseFormPtr  bfp;
4378   SeqEntryPtr  sep;
4379   Int4         gap_sizes[2];
4380 
4381 #ifdef WIN_MAC
4382   bfp = currentFormDataPtr;
4383 #else
4384   bfp = GetObjectExtra (i);
4385 #endif
4386   if (bfp == NULL) return;
4387   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
4388   if (sep == NULL) return;
4389   ConvertSegSetsToDeltaSequences (sep);
4390   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
4391   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
4392 }
4393 #endif
4394 
4395 
4396 typedef struct gapconversiondata 
4397 {
4398   FEATURE_FORM_BLOCK
4399 
4400   GrouP  unknown_op;
4401   TexT   unknown_val_txt;
4402   GrouP  known_op;
4403   TexT   known_val_txt;
4404   ButtoN acceptBtn;
4405   DoC    explanation;
4406   ButtoN adjust_CDS_locations;
4407   
4408 } GapConversionData, PNTR GapConversionPtr;
4409 
4410 static ParData faParFmt = {FALSE, FALSE, FALSE, FALSE, FALSE, 0, 0};
4411 static ColData faColFmt = {0, 0, 80, 0, NULL, 'l', TRUE, FALSE, FALSE, FALSE, TRUE};
4412 
4413 static void SetConvertGapsAcceptAndText (GapConversionPtr gcp)
4414 {
4415   Char             str[15];
4416   Int4 unknown_val, known_val;
4417   Int4 unknown_op, known_op;
4418   Char explanation[300];
4419         
4420   if (gcp == NULL || gcp->explanation == NULL) return;
4421   GetTitle (gcp->unknown_val_txt, str, sizeof (str));
4422   unknown_val = atoi (str);
4423   unknown_op = GetValue (gcp->unknown_op);
4424   GetTitle (gcp->known_val_txt, str, sizeof (str));
4425   known_val = atoi (str);
4426   known_op = GetValue (gcp->known_op);
4427 
4428   Reset (gcp->explanation);
4429   explanation [0] = 0;
4430   
4431   if (unknown_val < 0 || known_val < 0)
4432   {
4433     sprintf (explanation, "%s", "Negative values are not permitted.");
4434         Disable (gcp->acceptBtn);
4435   }
4436   else if (known_val == unknown_val)
4437   {
4438     sprintf (explanation, 
4439                  "You must specify different values for known and unknown gap conversion sizes.");
4440         Disable (gcp->acceptBtn);
4441   }  
4442   else if (unknown_val == 0 && unknown_op == 1 && known_val == 0 && known_op == 1)
4443   {
4444     sprintf (explanation, "%s", "This combination will have no effect.");
4445     Disable (gcp->acceptBtn);
4446   }
4447   else if (unknown_val == 0 && unknown_op == 1 && (known_val == 0 || known_val == 1) && known_op == 2)
4448   {
4449     sprintf (explanation, "%s", "All sequences of Ns will be converted to gaps of known length.");
4450     Enable (gcp->acceptBtn);
4451   }
4452   else if ((unknown_val == 0 || unknown_val == 1) && unknown_op == 2 && known_val == 0 && known_op == 1)
4453   {
4454     sprintf (explanation, "%s", "All sequences of Ns will be converted to gaps of unknown length (size 100).");
4455     Enable (gcp->acceptBtn);
4456   }
4457   else if (unknown_val == 0 && unknown_op == 1)
4458   {     
4459         if (known_op == 1)
4460         {
4461           sprintf (explanation, 
4462                    "All sequences of exactly %d Ns will be converted to gaps of known length.\n"
4463                    "All other sequences of Ns will remain as Ns.", known_val);
4464           Enable (gcp->acceptBtn);
4465         }
4466         else
4467         {
4468           sprintf (explanation, 
4469                      "All sequences of %d or more Ns will be converted to gaps of known length.\n"
4470                      "All sequences of less than %d Ns will remain as Ns.", known_val, known_val);
4471           Enable (gcp->acceptBtn);
4472         }
4473   }
4474   else if (known_val == 0 && known_op == 1)
4475   {
4476         if (unknown_op == 1)
4477         {
4478           sprintf (explanation, 
4479                    "All sequences of exactly %d Ns will be converted to gaps of unknown length (size 100).\n"
4480                    "All other sequences of Ns will remain as Ns.", unknown_val);
4481           Enable (gcp->acceptBtn);
4482         }
4483         else if (unknown_op == 2)
4484         {
4485           sprintf (explanation, 
4486                    "All sequences of %d or more Ns will be converted to gaps of unknown length.\n"
4487                    "All sequences of less than %d Ns will remain as Ns.", unknown_val, unknown_val);
4488           Enable (gcp->acceptBtn);
4489         }
4490   }
4491   else if (known_op == 1 && unknown_op == 1)
4492   {
4493         sprintf (explanation, 
4494                  "All sequences of exactly %d Ns will be converted to gaps of known length.\n"
4495                  "All sequences of exactly %d Ns will be converted to gaps of unknown length (size 100).\n"
4496                  "All sequences of Ns with lengths other than %d or %d will remain as Ns.", 
4497                  known_val, unknown_val, known_val, unknown_val);
4498         Enable (gcp->acceptBtn);
4499   }
4500   else if (known_op == 2 && unknown_op == 2)
4501   {
4502     /* handle cases where both operators are greater than/equal to */
4503         if (known_val > unknown_val)
4504         {
4505           if (unknown_val == 0 || unknown_val == 1)
4506           {
4507             sprintf (explanation, 
4508                      "All sequences of Ns with lengths >= 1 and <= %d will be converted to gaps of unknown length (size 100).\n"
4509                      "All sequences of Ns with lengths >= %d will be converted to gaps of known length.\n",
4510                      known_val -1, known_val);         
4511           }
4512           else
4513           {
4514                 sprintf (explanation,
4515                      "All sequences of Ns with lengths >= %d and <= %d will be converted to gaps of unknown length (size 100).\n"
4516                      "All sequences of Ns with lengths >= %d will be converted to gaps of known length.\n"
4517                      "All sequences of Ns with lengths <= %d will remain as Ns.",
4518                      unknown_val, known_val -1, known_val, unknown_val - 1);         
4519           }
4520         }
4521         else
4522         {
4523           if (known_val == 0 || known_val == 1)
4524           {
4525             sprintf (explanation, 
4526                      "All sequences of Ns with lengths >= 1 and <= %d will be converted to gaps of known length.\n"
4527                      "All sequences of Ns with lengths >= %d will be converted to gaps of unknown length (size 100).\n",
4528                      unknown_val -1, unknown_val);         
4529           }
4530           else
4531           {
4532                 sprintf (explanation,
4533                      "All sequences of Ns with lengths >= %d and <= %d will be converted to gaps of known length.\n"
4534                      "All sequences of Ns with lengths >= %d will be converted to gaps of unknown length (size 100).\n"
4535                      "All sequences of Ns with lengths <= %d will remain as Ns.",
4536                      known_val, unknown_val -1, unknown_val, known_val - 1);         
4537           }
4538         }
4539   }
4540   else if (known_val > unknown_val)
4541   {
4542         if (known_op == 1)
4543         {
4544           /* we know that unknown_op is 2 */
4545       if (unknown_val == 0 || unknown_val == 1)
4546           {
4547         sprintf (explanation, 
4548                    "All sequences of exactly %d Ns will be converted to gaps of known length.\n"
4549                    "All sequences of Ns with lengths >= 1 and <= %d or lengths >= %d will be converted to gaps of unknown length (size 100).\n",
4550                    known_val, known_val - 1, known_val + 1);
4551           }
4552           else
4553           {
4554         sprintf (explanation, 
4555                     "All sequences of exactly %d Ns will be converted to gaps of known length.\n"
4556                      "All sequences of Ns with lengths >= %d and <= %d or lengths >= %d will be converted to gaps of unknown length (size 100).\n"
4557                      "All sequences of Ns with lengths <= %d will remain as Ns.", 
4558                      known_val, unknown_val, known_val - 1, known_val + 1, unknown_val - 1);
4559           }
4560           Enable (gcp->acceptBtn);
4561         }
4562         else if (known_op == 2)
4563         {
4564           /* we know that unknown_op is 1 */
4565           if (unknown_val == 1)
4566           {
4567                 sprintf (explanation,
4568                    "All sequences of exactly 1 Ns will be converted to gaps of unknown length (size 100).\n"
4569                    "All sequences with lengths >= %d will be converted to gaps of known length.\n"
4570                    "All sequences of Ns with lengths >= 2 and <= %d will remain as Ns",
4571                         known_val, known_val - 1);
4572           }
4573           else
4574           {
4575         sprintf (explanation, 
4576                    "All sequences of exactly %d Ns will be converted to gaps of unknown length (size 100).\n"
4577                    "All sequences of Ns with lengths >= %d will be converted to gaps of known length.\n"
4578                    "All sequences of Ns with lengths >= %d or lengths >= %d and <= %d will remain as Ns.  ",
4579                    unknown_val, known_val, unknown_val - 1, unknown_val + 1, known_val - 1);
4580           }
4581           Enable (gcp->acceptBtn);
4582         }
4583   }
4584   else
4585   {
4586         /* unknown_val > known_val */
4587     if (known_op == 1)
4588     {
4589       /* we know that unknown_op is 2 */
4590           sprintf (explanation, 
4591                    "All sequences of exactly %d Ns will be converted to gaps of known length.\n"
4592                    "All sequences of Ns with lengths >= %d will be converted to gaps of unknown length (size 100).\n"
4593                    "All sequences of Ns with lengths <= %d or lengths >= %d and <= %d will remain as Ns.\n",
4594                     known_val, unknown_val, known_val - 1, known_val + 1, unknown_val - 1);
4595     }
4596     else
4597     {
4598       /* we know that unknown_op is 1, known_op is 2 */
4599       if (known_val == 0 || known_val == 1)
4600       {
4601         sprintf (explanation,
4602                      "All sequences of exactly %d Ns will be converted to gaps of unknown length (size 100).\n"
4603                      "All sequences of Ns with lengths >= 1 and <= %d or lengths >= %d will be converted to gaps of known length.\n",
4604                  unknown_val, unknown_val - 1, unknown_val + 1);
4605       }
4606       else 
4607       {
4608         sprintf (explanation,
4609                      "All sequences of exactly %d Ns will be converted to gaps of unknown length (size 100).\n"
4610                      "All sequences of Ns with lengths >= %d and <= %d or lengths >= %d will be converted to gaps of known length.\n"
4611                      "All sequences of Ns with lengths <= %d will remain as Ns.",
4612                  unknown_val, known_val, unknown_val - 1, unknown_val + 1, known_val);
4613         
4614       }
4615     }
4616     Enable (gcp->acceptBtn);
4617   }  
4618   AppendText (gcp->explanation, explanation, &faParFmt, &faColFmt, programFont);
4619   UpdateDocument (gcp->explanation, 0, 0);
4620   Update ();    
4621 }
4622 
4623 static void SetGapsConvertAcceptButtonAndTextGroup (GrouP g)
4624 {
4625   GapConversionPtr gcp;
4626   
4627   gcp = (GapConversionPtr) GetObjectExtra (g);
4628   SetConvertGapsAcceptAndText (gcp);
4629 }
4630 
4631 static void SetGapsConvertAcceptButtonAndTextText (TexT nText)
4632 {
4633   GapConversionPtr gcp;
4634   
4635   gcp = (GapConversionPtr) GetObjectExtra (nText);
4636   SetConvertGapsAcceptAndText (gcp);
4637 }
4638 
4639 static void ConvertGaps (ButtoN b)
4640 {
4641   GapConversionPtr gcp;
4642   SeqEntryPtr      sep;
4643   Int4             gap_sizes[2];
4644   Char             str[15];
4645   Int4             unknown_val, known_val;
4646   Int4             unknown_op, known_op;
4647   
4648   if (b == NULL) return;
4649   gcp = (GapConversionPtr) GetObjectExtra (b);
4650   if (gcp == NULL) return;
4651   sep = GetTopSeqEntryForEntityID (gcp->input_entityID);
4652   if (sep == NULL) return;
4653   
4654   GetTitle (gcp->unknown_val_txt, str, sizeof (str));
4655   unknown_val = atoi (str);
4656   unknown_op = GetValue (gcp->unknown_op);
4657   if (unknown_op == 1)
4658   {
4659         gap_sizes [0] = unknown_val;
4660   }
4661   else
4662   {
4663     if (unknown_val == 0)
4664       unknown_val = 1;
4665         gap_sizes[0] = 0 - unknown_val;
4666   }
4667   GetTitle (gcp->known_val_txt, str, sizeof (str));
4668   known_val = atoi (str);
4669   known_op = GetValue (gcp->known_op);
4670   if (known_op == 1)
4671   {
4672         gap_sizes [1] = known_val;
4673   }
4674   else
4675   {
4676     if (known_val == 0)
4677       known_val = 1;
4678         gap_sizes[1] = 0 - known_val;
4679   }
4680   
4681   
4682   Hide (gcp->form);
4683   ConvertNsToGapsWithSizeList (gcp->input_entityID, gap_sizes, GetStatus (gcp->adjust_CDS_locations));
4684 
4685   Remove (gcp->form);  
4686 }
4687 
4688 static void ListRawSequencesInAlignments (BioseqPtr bsp, Pointer userdata)
4689 {
4690   ValNodePtr PNTR raw_list;
4691   Char            id_str [128];
4692   
4693   if (bsp == NULL || bsp->repr != Seq_repr_raw || userdata == NULL)
4694   {
4695         return;
4696   }
4697   
4698   if (!IsBioseqInAnyAlignment (bsp, bsp->idx.entityID))
4699   {
4700     return;
4701   }
4702   
4703   raw_list = (ValNodePtr PNTR) userdata;
4704   SeqIdWrite (SeqIdFindBest (bsp->id, SEQID_GENBANK), id_str, PRINTID_REPORT, sizeof (id_str) - 1);
4705   ValNodeAddPointer (raw_list, 0, StringSave (id_str));
4706 }
4707 
4708 static Boolean ContinueWithSequencesInAlignments (SeqEntryPtr sep)
4709 {
4710   ValNodePtr raw_in_aln = NULL;
4711   CharPtr    msg;
4712   MsgAnswer  ans;
4713   
4714   VisitBioseqsInSep (sep, &raw_in_aln, ListRawSequencesInAlignments);
4715   if (raw_in_aln != NULL)
4716   {
4717         msg = CreateListMessage ("Sequence", 
4718                                  raw_in_aln->next == NULL 
4719                                       ? " is in an alignment.  The alignment will be automatically adjusted after conversion.  Do you want to continue?" 
4720                                       : " are in alignments.  The alignment will be automatically adjusted after conversion.  Do you want to continue?",
4721                                       raw_in_aln);
4722         raw_in_aln = ValNodeFreeData (raw_in_aln);
4723     ans = Message (MSG_YN, msg);
4724     msg = MemFree (msg);
4725     if (ans == ANS_NO)
4726     {
4727       return FALSE;
4728     }
4729   }
4730   return TRUE;
4731 }
4732 
4733 static void ListDeltaSequences (BioseqPtr bsp, Pointer userdata)
4734 {
4735   ValNodePtr PNTR delta_list;
4736   Char            id_str [128];
4737   
4738   if (bsp == NULL || bsp->repr != Seq_repr_delta || userdata == NULL)
4739   {
4740         return;
4741   }
4742   
4743   delta_list = (ValNodePtr PNTR) userdata;
4744   SeqIdWrite (SeqIdFindBest (bsp->id, SEQID_GENBANK), id_str, PRINTID_REPORT, sizeof (id_str) - 1);
4745   ValNodeAddPointer (delta_list, 0, StringSave (id_str));
4746 }
4747 
4748 static Boolean ContinueWithDeltaSequences (SeqEntryPtr sep)
4749 {
4750   ValNodePtr delta_list = NULL;
4751   CharPtr    msg;
4752   MsgAnswer  ans;
4753   
4754   VisitBioseqsInSep (sep, &delta_list, ListDeltaSequences);
4755   if (delta_list != NULL)
4756   {
4757         msg = CreateListMessage ("Sequence", 
4758                                  delta_list->next == NULL 
4759                                       ? " is already a delta sequence and gaps will not be added.  Do you want to continue?" 
4760                                       : " are already delta sequences and gaps will not be added.  Do you want to continue?",
4761                                       delta_list);
4762         delta_list = ValNodeFreeData (delta_list);
4763     ans = Message (MSG_YN, msg);
4764     msg = MemFree (msg);
4765     if (ans == ANS_NO)
4766     {
4767       return FALSE;
4768     }
4769   }  
4770   return TRUE;
4771 }
4772 
4773 
4774 static void RawSeqToDeltaSeqUnknownWithUnknownLengthGaps (IteM i)
4775 {
4776   BaseFormPtr      bfp;
4777   GapConversionPtr gcp;
4778   WindoW           w;
4779   GrouP            h, l, g, c;
4780   RecT             r;
4781   PrompT           p1, p2;
4782   SeqEntryPtr      sep;
4783 
4784 #ifdef WIN_MAC
4785   bfp = currentFormDataPtr;
4786 #else
4787   bfp = GetObjectExtra (i);
4788 #endif
4789   if (bfp == NULL) return;
4790   
4791   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
4792   if (!ContinueWithDeltaSequences (sep))
4793   {
4794     return;
4795   }
4796   if (!ContinueWithSequencesInAlignments (sep))
4797   {
4798     return;
4799   }
4800 
4801   gcp = (GapConversionPtr) MemNew (sizeof (GapConversionData));
4802   if (gcp == NULL) return;
4803   
4804   gcp->input_entityID = bfp->input_entityID;
4805   w = FixedWindow (-50, -33, -10, -10, "Convert Ns to Gaps of Unknown Length", StdCloseWindowProc);
4806   SetObjectExtra (w, gcp, StdCleanupFormProc);
4807   gcp->form = (ForM) w;
4808   h = HiddenGroup (w, -1, 0, NULL);
4809   SetGroupSpacing (h, 10, 10);
4810   p1 = StaticPrompt (h, "Choose size of length of Ns to convert to gaps of unknown length", 0, dialogTextHeight, programFont, 'c');
4811   g = HiddenGroup (h, 2, 0, NULL);
4812   gcp->unknown_op = HiddenGroup (g, 0, 2, SetGapsConvertAcceptButtonAndTextGroup);
4813   SetObjectExtra (gcp->unknown_op, gcp, NULL);
4814   RadioButton (gcp->unknown_op, "=");
4815   RadioButton (gcp->unknown_op, ">=");
4816   SetValue (gcp->unknown_op, 1);
4817   gcp->unknown_val_txt = DialogText (g, "100", 14, SetGapsConvertAcceptButtonAndTextText);
4818   SetObjectExtra (gcp->unknown_val_txt, gcp, NULL);
4819   p2 = StaticPrompt (h, "Choose size of length of Ns to convert to gaps of known length", 0, dialogTextHeight, programFont, 'c');
4820   l = HiddenGroup (h, 2, 0, NULL);
4821   gcp->known_op = HiddenGroup (l, 0, 2, SetGapsConvertAcceptButtonAndTextGroup);
4822   SetObjectExtra (gcp->known_op, gcp, NULL);
4823   RadioButton (gcp->known_op, "=");
4824   RadioButton (gcp->known_op, ">=");
4825   SetValue (gcp->known_op, 1);
4826   gcp->known_val_txt = DialogText (l, "0", 14, SetGapsConvertAcceptButtonAndTextText);
4827   SetObjectExtra (gcp->known_val_txt, gcp, NULL);
4828   
4829   /* status text */
4830   gcp->explanation = DocumentPanel (h, stdCharWidth * 27, stdLineHeight * 8);
4831   ObjectRect (gcp->explanation, &r);
4832   InsetRect (&r, 4, 4);
4833   faColFmt.pixWidth = r.right - r.left;
4834   
4835   gcp->adjust_CDS_locations = CheckBox (h, "Adjust CDS locations for gaps", NULL);
4836   SetStatus (gcp->adjust_CDS_locations, TRUE);
4837 
4838   c = HiddenGroup (h, 4, 0, NULL);
4839   gcp->acceptBtn = PushButton (c, "Accept", ConvertGaps);
4840   SetObjectExtra (gcp->acceptBtn, gcp, NULL);
4841   PushButton (c, "Cancel", StdCancelButtonProc);
4842   
4843   AlignObjects (ALIGN_CENTER, (HANDLE) p1,
4844                               (HANDLE) g, 
4845                               (HANDLE) p2, 
4846                               (HANDLE) l,
4847                               (HANDLE) gcp->explanation,
4848                               (HANDLE) gcp->adjust_CDS_locations, 
4849                               (HANDLE) c, 
4850                               NULL);
4851   
4852   SetConvertGapsAcceptAndText (gcp);
4853   RealizeWindow (w);
4854   Show (w);
4855   Update ();
4856 }
4857 
4858 static Uint2 deltaconversionedittypes [] = 
4859 {
4860   TAGLIST_TEXT, TAGLIST_POPUP, TAGLIST_TEXT, TAGLIST_POPUP
4861 };
4862 
4863 ENUM_ALIST(deltaconversionedit_alist)
4864   {"Unknown length",  0},
4865   {"Known Length",    1},
4866 END_ENUM_ALIST
4867 
4868 ENUM_ALIST(deltaconversionedit_type_alist)
4869   {"Insert",  0},
4870   {"Replace",    1},
4871 END_ENUM_ALIST
4872 
4873 EnumFieldAssocPtr deltaconversionedit_alists [] = {
4874   NULL, deltaconversionedit_alist, NULL, deltaconversionedit_type_alist
4875 };
4876 
4877 static Uint2 deltaconversionedit_widths [] = {
4878   5, 5, 5, 5
4879 };
4880 
4881 typedef struct deltaconversion 
4882 {
4883   FEATURE_FORM_BLOCK
4884 
4885   DialoG gap_locations;
4886   GrouP  coord_grp;
4887   ButtoN adjust_CDS_locations;
4888   
4889 } DeltaConversionData, PNTR DeltaConversionPtr;
4890 
4891 
4892 static SeqAlignPtr 
4893 AdjustOneAlignmentForOneBioseqBasedOnGapLocations 
4894 (SeqAlignPtr salp_to_adjust,
4895  BioseqPtr   bsp,
4896  ValNodePtr  gaps,
4897  SeqAlignPtr gap_salp)
4898 {
4899   Int4          aln_index;
4900   SeqIdPtr      sip;
4901   ValNodePtr    gap_vnp;
4902   GapLocInfoPtr glip;
4903   SeqLocPtr     slp;
4904   Int4          gap_start;
4905   Int4          cumulative_offset = 0;
4906   DenseSegPtr   dsp;
4907   
4908   if (salp_to_adjust == NULL || salp_to_adjust->segtype != SAS_DENSEG
4909       || bsp == NULL || gaps == NULL)
4910   {
4911     return salp_to_adjust;
4912   }
4913 
4914   dsp = (DenseSegPtr) salp_to_adjust->segs;
4915   if (dsp == NULL) {
4916      return salp_to_adjust;
4917   }
4918   sip = bsp->id;
4919   aln_index = 0;
4920   while (sip != NULL && aln_index == 0)
4921   {
4922     aln_index = SeqIdOrderInBioseqIdList (sip, dsp->ids);
4923     if (aln_index == 0)
4924     {
4925       sip = sip->next;
4926     }
4927   }
4928   if (aln_index == 0) {
4929      /* bioseq not in alignment */
4930      return salp_to_adjust;
4931   }
4932   
4933   for (gap_vnp = gaps; gap_vnp != NULL; gap_vnp = gap_vnp->next)
4934   {
4935     glip = (GapLocInfoPtr) gap_vnp->data.ptrvalue;
4936     if (glip == NULL || glip->replace)
4937     {
4938       continue;
4939     }
4940     gap_start = glip->start_pos;
4941     if (gap_salp != NULL)
4942     {
4943       gap_start = AlnMgr2MapSeqAlignToBioseq(gap_salp, gap_start, aln_index);
4944     }
4945     if (gap_start < 1)
4946     {
4947       continue;
4948     }
4949     gap_start += cumulative_offset;
4950     if (gap_start > bsp->length)
4951     {
4952       continue;
4953     }
4954     slp = SeqLocIntNew (gap_start, gap_start + glip->length - 1, Seq_strand_plus, sip);
4955     salp_to_adjust = SeqAlignInsertByLoc (slp, salp_to_adjust);
4956     cumulative_offset += glip->length;
4957   }
4958   
4959   return salp_to_adjust;
4960 }
4961 
4962 
4963 static void ShiftAlignmentForGapLocations (SeqAnnotPtr sanp, ValNodePtr gaps)
4964 {
4965   SeqAlignPtr   salp;
4966   DenseSegPtr   dsp;
4967   Int4          alignment_position = 0, k;
4968   Int4          cumulative_offset = 0;
4969   BoolPtr       shift_this_row;
4970   Int4          seg_num = 0, shift_seg;
4971   ValNodePtr    gap_vnp;
4972   GapLocInfoPtr glip;
4973   
4974   if (sanp == NULL || sanp->data == NULL || sanp->type != 2 || gaps == NULL)
4975   {
4976     return;
4977   }
4978   
4979   salp = (SeqAlignPtr) sanp->data;
4980   if (salp->segtype != SAS_DENSEG || salp->segs == NULL)
4981   {
4982     return;
4983   }
4984   
4985   dsp = (DenseSegPtr) salp->segs;
4986   
4987   shift_this_row = (BoolPtr) MemNew (sizeof (Boolean) * dsp->dim);
4988   
4989   for (gap_vnp = gaps; gap_vnp != NULL; gap_vnp = gap_vnp->next)
4990   {
4991     glip = (GapLocInfoPtr) gap_vnp->data.ptrvalue;
4992     if (glip == NULL || glip->replace)
4993     {
4994       continue;
4995     }
4996     while (seg_num < dsp->numseg 
4997            && alignment_position + dsp->lens [seg_num] < glip->start_pos + cumulative_offset)
4998            
4999     {
5000       alignment_position += dsp->lens [seg_num];
5001       seg_num++;
5002     }
5003 
5004     if (seg_num < dsp->numseg)
5005     {
5006       dsp->lens [seg_num] += glip->length;
5007       for (k = 0; k < dsp->dim; k++)
5008       {
5009         if (dsp->starts [seg_num * dsp->dim + k] == -1)
5010         {
5011           shift_this_row[k] = FALSE;
5012         }
5013         else
5014         {
5015           shift_this_row[k] = TRUE;
5016         }
5017       }
5018       
5019       /* shift the rows for which a gap was inserted */
5020       for (k = 0; k < dsp->dim; k++)
5021       {
5022         if (!shift_this_row[k])
5023         {
5024           continue;
5025         }
5026         /* shift start for minus strand rows for seg_num only */
5027         if (dsp->strands != NULL 
5028             && dsp->strands [seg_num * dsp->dim + k] == Seq_strand_minus
5029             && dsp->starts [seg_num * dsp->dim + k] != -1)
5030         {
5031           dsp->starts [seg_num * dsp->dim + k] -= glip->length;
5032         }
5033         /* shift starts for rows after seg_num */
5034         for (shift_seg = seg_num + 1;
5035              shift_seg < dsp->numseg;
5036              shift_seg++)
5037         {
5038           if (dsp->starts [shift_seg * dsp->dim + k] != -1)
5039           {
5040             if (dsp->strands == NULL
5041                 || dsp->strands [shift_seg * dsp->dim + k] != Seq_strand_minus)
5042             {
5043               dsp->starts [shift_seg * dsp->dim + k] += glip->length;
5044             }
5045             else
5046             {
5047               dsp->starts [shift_seg * dsp->dim + k] -= glip->length;
5048             }
5049           }
5050         }
5051       }
5052     }
5053     cumulative_offset += glip->length;
5054   }  
5055   shift_this_row = MemFree (shift_this_row);
5056 }
5057 
5058 static void 
5059 AdjustAlignmentsBasedOnGapLocations 
5060 (ValNodePtr  adjusted_bsp_list,
5061  ValNodePtr  gaps,
5062  SeqAlignPtr salp,
5063  Uint2       entityID)
5064 {
5065   ValNodePtr  align_annot_list, annot_vnp, bsp_vnp;
5066   SeqAnnotPtr sanp, adjustment_sanp = NULL;
5067   BioseqPtr   bsp;
5068   
5069   for (bsp_vnp = adjusted_bsp_list; bsp_vnp != NULL; bsp_vnp = bsp_vnp->next)
5070   {
5071     bsp = (BioseqPtr)(bsp_vnp->data.ptrvalue);
5072     align_annot_list = FindAlignSeqAnnotsForBioseq (bsp);
5073     for (annot_vnp = align_annot_list;
5074          annot_vnp != NULL; 
5075          annot_vnp = annot_vnp->next)
5076     {
5077       sanp = annot_vnp->data.ptrvalue;
5078       if (sanp != NULL && sanp->type == 2)
5079       {
5080         if (sanp->data == salp)
5081         {
5082           adjustment_sanp = sanp;
5083         }
5084         else
5085         {
5086           sanp->data = AdjustOneAlignmentForOneBioseqBasedOnGapLocations 
5087                               (sanp->data, bsp, gaps, salp);
5088         }
5089       }
5090     }
5091     align_annot_list = ValNodeFree (align_annot_list);
5092   }
5093 
5094   if (adjustment_sanp != NULL)
5095   {
5096     ShiftAlignmentForGapLocations (adjustment_sanp, gaps);
5097   }
5098     
5099   CleanupAlignmentsAfterConversion (adjusted_bsp_list, entityID);
5100 }
5101 
5102 
5103 static void 
5104 ConvertRawBioseqToDelta 
5105 (BioseqPtr bsp,
5106  ValNodePtr gaps,
5107  SeqAlignPtr salp,
5108  Int4        aln_row) 
5109 
5110 {
5111   CharPtr       bases;
5112   Int4          len;
5113   ValNodePtr    seq_ext;
5114   SeqLitPtr     slp;
5115   IntFuzzPtr    ifp;
5116   ValNodePtr    gap_vnp;
5117   GapLocInfoPtr glip;
5118   Int4          orig_seq_offset;
5119   Char          tmp_ch;
5120   Int4          gap_start;
5121   SeqEntryPtr   sep;
5122 
5123   if (bsp == NULL || bsp->repr != Seq_repr_raw || ISA_aa (bsp->mol)
5124       || gaps == NULL) 
5125   {
5126     return;
5127   }
5128   if (salp != NULL && aln_row < 1)
5129   {
5130     return;
5131   }
5132 
5133   bases = GetSequenceByBsp (bsp);
5134   if (bases == NULL) return;
5135 
5136   seq_ext = NULL;
5137   len = 0;
5138   orig_seq_offset = 0;
5139 
5140   for (gap_vnp = gaps; gap_vnp != NULL; gap_vnp = gap_vnp->next)
5141   {
5142     glip = (GapLocInfoPtr) gap_vnp->data.ptrvalue;
5143     if (glip == NULL)
5144     {
5145       continue;
5146     }
5147     gap_start = glip->start_pos;
5148     /* remap for alignment coordinates if desired */
5149     if (salp != NULL)
5150     {
5151       gap_start = AlnMgr2MapSeqAlignToBioseq(salp, gap_start, aln_row);
5152     }
5153     if (gap_start < 1 || gap_start > bsp->length)
5154     {
5155       continue;
5156     }
5157     
5158     /* add data since last gap */
5159     if (gap_start - orig_seq_offset > 0) {
5160       slp = (SeqLitPtr) MemNew (sizeof (SeqLit));
5161       if (slp != NULL) 
5162       {
5163         slp->length = gap_start - orig_seq_offset;
5164         ValNodeAddPointer (&(seq_ext), (Int2) 2, (Pointer) slp);
5165         slp->seq_data = (SeqDataPtr) BSNew (slp->length);
5166         slp->seq_data_type = Seq_code_iupacna;
5167         tmp_ch = bases [gap_start];
5168         bases [gap_start] = 0;
5169         AddBasesToByteStore ((ByteStorePtr) slp->seq_data, bases + orig_seq_offset);
5170         bases [gap_start] = tmp_ch;
5171         len += slp->length;
5172         orig_seq_offset += slp->length;
5173       }
5174     }
5175     
5176     /* add gap */
5177     slp = (SeqLitPtr) MemNew (sizeof (SeqLit));
5178     if (slp != NULL) 
5179     {
5180       ValNodeAddPointer ((ValNodePtr PNTR) &(seq_ext), (Int2) 2, (Pointer) slp);
5181       if (glip->is_known)
5182       {
5183         slp->length = glip->length;
5184       }
5185       else
5186       {
5187         ifp = IntFuzzNew ();
5188         ifp->choice = 4;
5189         slp->fuzz = ifp;
5190         slp->length = 100;
5191       }
5192       len += slp->length;
5193     }
5194     if (glip->replace)
5195     {
5196       orig_seq_offset += glip->length;
5197     }
5198   }
5199   
5200   /* add remaining data after last gap to end */
5201   if (bsp->length - orig_seq_offset > 0) {
5202     slp = (SeqLitPtr) MemNew (sizeof (SeqLit));
5203     if (slp != NULL) 
5204     {
5205       slp->length = bsp->length - orig_seq_offset;
5206       ValNodeAddPointer (&(seq_ext), (Int2) 2, (Pointer) slp);
5207       slp->seq_data = (SeqDataPtr) BSNew (slp->length);
5208       slp->seq_data_type = Seq_code_iupacna;
5209       AddBasesToByteStore ((ByteStorePtr) slp->seq_data, bases + orig_seq_offset);
5210       len += slp->length;
5211     }
5212   }
5213   
5214   MemFree (bases);
5215 
5216   bsp->seq_data = SeqDataFree (bsp->seq_data, bsp->seq_data_type);
5217   bsp->seq_data_type = 0;
5218   bsp->repr = Seq_repr_delta;
5219   bsp->seq_ext_type = 4;
5220   bsp->seq_ext = seq_ext;
5221   bsp->length = len;
5222 
5223   BioseqPack (bsp);
5224   
5225   /* now adjust features for insertion */
5226   orig_seq_offset = 0;
5227   for (gap_vnp = gaps; gap_vnp != NULL; gap_vnp = gap_vnp->next)
5228   {
5229     glip = (GapLocInfoPtr) gap_vnp->data.ptrvalue;
5230     if (glip == NULL)
5231     {
5232       continue;
5233     }
5234     gap_start = glip->start_pos;
5235     /* remap for alignment coordinates if desired */
5236     if (salp != NULL)
5237     {
5238       gap_start = AlnMgr2MapSeqAlignToBioseq(salp, gap_start, aln_row);
5239     }
5240     if (gap_start < 1 || gap_start > bsp->length)
5241     {
5242       continue;
5243     }
5244     if (!glip->replace) {
5245       AdjustFeaturesForInsertion (bsp, bsp->id, 
5246                                 gap_start + orig_seq_offset,
5247                                 glip->length,
5248                                 FALSE);
5249     } else if (glip->length != 100 && !glip->is_known) {
5250       AdjustFeaturesForInsertion (bsp, bsp->id, gap_start + orig_seq_offset,
5251                                   100 - glip->length,
5252                                   FALSE);
5253     }
5254     orig_seq_offset += glip->length;
5255   }
5256 
5257   sep = GetTopSeqEntryForEntityID (bsp->idx.entityID);
5258 
5259   VisitFeaturesInSep (sep, (Pointer) Sequin_GlobalAlign2Seq, AdjustCDSLocationsForUnknownGapsCallback);
5260   
5261 }
5262 
5263 typedef struct converttodelta 
5264 {
5265   ValNodePtr  location_list;
5266   ValNodePtr  affected_bioseq_list;
5267   SeqAlignPtr salp;
5268 } ConvertToDeltaData, PNTR ConvertToDeltaPtr;
5269 
5270 static void ConvertBioseqToDeltaWithSequenceGapList (BioseqPtr bsp, Pointer userdata)
5271 {
5272   ConvertToDeltaPtr ctdp;
5273   
5274   if (bsp == NULL || bsp->id == NULL 
5275       || bsp->repr != Seq_repr_raw || ISA_aa (bsp->mol)
5276       || userdata == NULL)
5277   {
5278     return;
5279   }
5280   ctdp = (ConvertToDeltaPtr) userdata;
5281   if (ctdp->location_list == NULL)
5282   {
5283     return;
5284   }
5285   ValNodeAddPointer (&(ctdp->affected_bioseq_list), 0, bsp);
5286   ConvertRawBioseqToDelta (bsp, ctdp->location_list, NULL, -1);
5287 }
5288 
5289 static void ConvertBioseqToDeltaWithAlignmentGapList (BioseqPtr bsp, Pointer userdata)
5290 {
5291   Int4              aln_row = -1;
5292   SeqIdPtr          sip, sip_next;
5293   SeqAlignPtr       salp;
5294   ConvertToDeltaPtr ctdp;
5295   ValNodePtr        annot_list;
5296   SeqAnnotPtr       sanp;
5297   
5298   if (bsp == NULL || bsp->id == NULL 
5299       || bsp->repr != Seq_repr_raw || ISA_aa (bsp->mol)
5300       || userdata == NULL)
5301   {
5302     return;
5303   }
5304   ctdp = (ConvertToDeltaPtr) userdata;
5305   if (ctdp->location_list == NULL)
5306   {
5307     return;
5308   }
5309   
5310   annot_list = FindAlignSeqAnnotsForBioseq (bsp);
5311   if (annot_list == NULL || annot_list->data.ptrvalue == NULL)
5312   {
5313     return;
5314   }
5315   sanp = (SeqAnnotPtr) annot_list->data.ptrvalue;
5316   if (sanp->type != 2 || sanp->data == NULL)
5317   {
5318     return;
5319   }
5320 
5321   salp = sanp->data;
5322   ctdp->salp = salp;
5323   
5324   /* Make sure alignment is indexed.
5325    */
5326   AlnMgr2IndexSeqAlignEx(salp, FALSE);
5327   
5328   sip = bsp->id;
5329   
5330   while (sip != NULL && aln_row == -1)
5331   {
5332     sip_next = sip->next;
5333     sip->next = NULL;
5334     aln_row = AlnMgr2GetFirstNForSip (salp, sip);
5335     sip->next = sip_next;
5336     sip = sip_next;
5337   }
5338 
5339   ValNodeAddPointer (&(ctdp->affected_bioseq_list), 0, bsp);
5340   ConvertRawBioseqToDelta (bsp, ctdp->location_list, salp, aln_row);
5341 }
5342 
5343 static int LIBCALLBACK SortGapLocations (VoidPtr ptr1, VoidPtr ptr2)
5344 
5345 {
5346   ValNodePtr    vnp1, vnp2;
5347   GapLocInfoPtr glip1, glip2;
5348   
5349   if (ptr1 != NULL && ptr2 != NULL) {
5350     vnp1 = *((ValNodePtr PNTR) ptr1);
5351     vnp2 = *((ValNodePtr PNTR) ptr2);
5352     if (vnp1 != NULL && vnp2 != NULL) {
5353       glip1 = (GapLocInfoPtr) vnp1->data.ptrvalue;
5354       glip2 = (GapLocInfoPtr) vnp2->data.ptrvalue;
5355       if (glip1 != NULL && glip2 != NULL) {
5356         if (glip1->start_pos < glip2->start_pos)
5357         {
5358           return -1;
5359         }
5360         else if (glip1->start_pos > glip2->start_pos)
5361         {
5362           return 1;
5363         }
5364         else if (glip1->length < glip2->length)
5365         {
5366           return -1;
5367         }
5368         else if (glip1->length > glip2->length)
5369         {
5370           return 1;
5371         }
5372         else
5373         {
5374           return 0;
5375         }
5376       }
5377     }
5378   }
5379   return 0;
5380 }
5381 
5382 static Pointer DeltaLocToData (DialoG d)
5383 {
5384   TagListPtr    tlp;
5385   ValNodePtr    result_list = NULL, vnp;
5386   CharPtr       str;
5387   Int4          start_pos, len;
5388   Boolean       is_known, replace;
5389   GapLocInfoPtr glip;
5390   
5391   tlp = (TagListPtr) GetObjectExtra (d);
5392   
5393   if (tlp == NULL) return NULL;
5394   
5395   for (vnp = tlp->vnp;
5396        vnp != NULL;
5397        vnp = vnp->next)
5398   {
5399     str = ExtractTagListColumn ((CharPtr) vnp->data.ptrvalue, 0);
5400     if (StringHasNoText (str))
5401     {
5402       str = MemFree (str);
5403     }
5404     else
5405     {
5406       start_pos = atoi (str) - 1;
5407       str = MemFree (str);
5408       if (start_pos > 0)
5409       {
5410         str = ExtractTagListColumn ((CharPtr) vnp->data.ptrvalue, 3);
5411         if (StringICmp (str, "1") == 0)
5412         {
5413           replace = TRUE;
5414         }
5415         else
5416         {
5417           replace = FALSE;
5418         }
5419         str = MemFree (str);
5420 
5421         str = ExtractTagListColumn ((CharPtr) vnp->data.ptrvalue, 1);
5422         if (StringICmp (str, "1") == 0)
5423         {
5424           str = MemFree (str);
5425           is_known = TRUE;
5426           len = -1;
5427           str = ExtractTagListColumn ((CharPtr) vnp->data.ptrvalue, 2);
5428           if (!StringHasNoText (str))
5429           {
5430             len = atoi (str);
5431           }
5432           str = MemFree (str);
5433           if (len < 1)
5434           {
5435             Message (MSG_ERROR, "Must supply a length greater than zero for gaps of known length!");
5436             result_list = ValNodeFreeData (result_list);
5437             return NULL;
5438           }
5439         }
5440         else
5441         {
5442           str = MemFree (str);
5443           is_known = FALSE;
5444           if (replace)
5445           {
5446             str = ExtractTagListColumn ((CharPtr) vnp->data.ptrvalue, 2);
5447             if (StringHasNoText (str))
5448             {
5449               len = 100;
5450             }
5451             else
5452             {
5453               len = atoi (str);
5454               if (len < 1)
5455               {
5456                 len = 100;
5457               }
5458             }
5459             str = MemFree (str);
5460           }
5461           else
5462           {
5463             len = 100;
5464           }
5465         }
5466         
5467         glip = (GapLocInfoPtr) MemNew (sizeof (GapLocInfoData));
5468         if (glip != NULL)
5469         {
5470           glip->start_pos = start_pos;
5471           glip->is_known = is_known;
5472           glip->length = len;
5473           glip->replace = replace;
5474           ValNodeAddPointer (&result_list, 0, glip);
5475         }
5476       }
5477     }
5478   }
5479   
5480   result_list = ValNodeSort (result_list, SortGapLocations);
5481   return result_list;
5482 }
5483 
5484 static void DoConvertRawToDeltaWithGapLocations (ButtoN b)
5485 {
5486   DeltaConversionPtr dcp;
5487   SeqEntryPtr        sep;
5488   ConvertToDeltaData ctdd;
5489 
5490   dcp = (DeltaConversionPtr) GetObjectExtra (b);
5491   if (dcp == NULL)
5492   {
5493     return;
5494   }
5495   
5496   sep = GetTopSeqEntryForEntityID (dcp->input_entityID);
5497   if (sep == NULL)
5498   {
5499     return;
5500   }
5501 
5502   ctdd.location_list = DialogToPointer (dcp->gap_locations);
5503   if (ctdd.location_list == NULL)
5504   {
5505     Message (MSG_ERROR, "Must supply valid gap locations!");
5506     return;
5507   }
5508   ctdd.affected_bioseq_list = NULL;
5509   ctdd.salp = NULL;
5510   
5511   Hide (dcp->form);
5512   WatchCursor ();
5513   Update (); 
5514   if (dcp->coord_grp == NULL || GetValue (dcp->coord_grp) == 1)
5515   {
5516     VisitBioseqsInSep (sep, &ctdd, ConvertBioseqToDeltaWithSequenceGapList);
5517   }
5518   else
5519   {
5520     VisitBioseqsInSep (sep, &ctdd, ConvertBioseqToDeltaWithAlignmentGapList);
5521   }
5522   
5523   AdjustAlignmentsBasedOnGapLocations (ctdd.affected_bioseq_list, 
5524                                        ctdd.location_list, ctdd.salp, 
5525                                        dcp->input_entityID);                                      
5526 
5527   ctdd.affected_bioseq_list = ValNodeFree (ctdd.affected_bioseq_list);
5528   ctdd.location_list = ValNodeFreeData (ctdd.location_list);
5529   
5530   if (GetStatus (dcp->adjust_CDS_locations))
5531   {
5532     VisitFeaturesInSep (sep, (Pointer)Sequin_GlobalAlign2Seq, AdjustCDSLocationsForUnknownGapsCallback);
5533     DeleteMarkedObjects (dcp->input_entityID, 0, NULL);
5534   }  
5535   
5536   ObjMgrSetDirtyFlag (dcp->input_entityID, TRUE);
5537   ObjMgrSendMsg (OM_MSG_UPDATE, dcp->input_entityID, 0, 0);
5538   Remove (dcp->form);    
5539   ArrowCursor ();
5540   Update (); 
5541 }
5542 
5543 extern DialoG CreateTagListDialogEx (GrouP h, Uint2 rows, Uint2 cols,
5544                                      Int2 spacing, Uint2Ptr types,
5545                                      Uint2Ptr textWidths, EnumFieldAssocPtr PNTR alists,
5546                                      Boolean useBar, Boolean noExtend,
5547                                      ToDialogFunc tofunc, FromDialogFunc fromfunc);
5548 
5549 static void ConvertRawToDeltaWithGapLocations (IteM i)
5550 {
5551   BaseFormPtr        bfp;
5552   DeltaConversionPtr dcp;
5553   WindoW             w;
5554   GrouP              h, p, c;
5555   ButtoN             b;
5556   PrompT             p1, p2, p3;
5557   SeqEntryPtr        sep;
5558   RecT               r1, r2;
5559   TagListPtr         tlp;
5560 
5561 #ifdef WIN_MAC
5562   bfp = currentFormDataPtr;
5563 #else
5564   bfp = GetObjectExtra (i);
5565 #endif
5566   if (bfp == NULL) return;
5567 
5568   dcp = (DeltaConversionPtr) MemNew (sizeof (DeltaConversionData));
5569   if (dcp == NULL) return;
5570   
5571   dcp->input_entityID = bfp->input_entityID;
5572   sep = GetTopSeqEntryForEntityID (dcp->input_entityID);
5573   if (sep == NULL)
5574   {
5575     return;
5576   }
5577   
5578   if (!ContinueWithDeltaSequences (sep))
5579   {
5580     return;
5581   }
5582   if (!ContinueWithSequencesInAlignments (sep))
5583   {
5584     return;
5585   }
5586 
5587   w = FixedWindow (-50, -33, -10, -10, "Convert Raw Sequence to Delta Sequence", StdCloseWindowProc);
5588   SetObjectExtra (w, dcp, StdCleanupFormProc);
5589   dcp->form = (ForM) w;
5590   h = HiddenGroup (w, -1, 0, NULL);
5591   SetGroupSpacing (h, 10, 10);
5592  
5593   p = HiddenGroup (h, 3, 0, NULL);
5594   p1 = StaticPrompt (p, "Start", 0, dialogTextHeight, programFont, 'c');
5595   p2 = StaticPrompt (p, "Type", 0, dialogTextHeight, programFont, 'c');
5596   p3 = StaticPrompt (p, "Length", 0, dialogTextHeight, programFont, 'c');
5597   dcp->gap_locations = CreateTagListDialogEx (h, 4, 4, 2,
5598                                               deltaconversionedittypes, 
5599                                               deltaconversionedit_widths,
5600                                               deltaconversionedit_alists,
5601                                               TRUE, FALSE, NULL, DeltaLocToData);
5602   dcp->coord_grp = NormalGroup (h, 2, 0, "Coordinates", programFont, NULL);
5603   RadioButton (dcp->coord_grp, "Sequence");
5604   RadioButton (dcp->coord_grp, "Alignment");
5605   SetValue (dcp->coord_grp, 1);
5606   if (!SeqEntryHasAligns (dcp->input_entityID, sep))
5607   {
5608     Disable (dcp->coord_grp);
5609   }
5610   
5611   dcp->adjust_CDS_locations = CheckBox (h, "Adjust CDS locations for gaps", NULL);
5612   SetStatus (dcp->adjust_CDS_locations, TRUE);
5613   
5614   c = HiddenGroup (h, 2, 0, NULL);
5615   b = PushButton (c, "Accept", DoConvertRawToDeltaWithGapLocations);
5616   SetObjectExtra (b, dcp, NULL);
5617   PushButton (c, "Cancel", StdCancelButtonProc);
5618   
5619   AlignObjects (ALIGN_CENTER, (HANDLE) dcp->gap_locations,
5620                               (HANDLE) dcp->coord_grp,
5621                               (HANDLE) dcp->adjust_CDS_locations,
5622                               (HANDLE) c,
5623                               NULL);
5624 
5625   tlp = GetObjectExtra (dcp->gap_locations);
5626   if (tlp != NULL)
5627   {
5628     ObjectRect (tlp->control [0], &r1);
5629     ObjectRect (p1, &r2);
5630     r2.left = r1.left;
5631     r2.right = r1.right;
5632     SetPosition (p1, &r2);
5633     
5634     ObjectRect (tlp->control [1], &r1);
5635     ObjectRect (p2, &r2);
5636     r2.left = r1.left;
5637     r2.right = r1.right;
5638     SetPosition (p2, &r2);
5639     
5640     ObjectRect (tlp->control [2], &r1);
5641     ObjectRect (p3, &r2);
5642     r2.left = r1.left;
5643     r2.right = r1.right;
5644     SetPosition (p3, &r2);
5645   }
5646   RealizeWindow (w);
5647   
5648   Show (w);
5649   Update ();  
5650 }
5651 
5652 typedef struct xrefgenedata {
5653   GeneRefPtr  grp;
5654   SeqLocPtr   slp;
5655   Boolean     pseudo;
5656 } XrefGeneData, PNTR XrefGenePtr;
5657 
5658 static Boolean XrefToGeneCallback (GatherContextPtr gcp)
5659 
5660 {
5661   GeneRefPtr           grp;
5662   SeqFeatXrefPtr PNTR  last;
5663   SeqFeatXrefPtr       next;
5664   SeqFeatPtr           sfp;
5665   ValNodePtr PNTR      vnpp;
5666   XrefGenePtr          xgp;
5667   SeqFeatXrefPtr       xref;
5668 
5669   if (gcp->thistype != OBJ_SEQFEAT) return TRUE;
5670   vnpp = (ValNodePtr PNTR) gcp->userdata;
5671   if (vnpp == NULL) return TRUE;
5672   sfp = (SeqFeatPtr) gcp->thisitem;
5673   if (sfp == NULL || sfp->location == NULL) return TRUE;
5674   if (sfp->xref == NULL) return TRUE;
5675   grp = NULL;
5676   last = (SeqFeatXrefPtr PNTR) &(sfp->xref);
5677   xref = sfp->xref;
5678   while (xref != NULL) {
5679     next = xref->next;
5680     if (xref->data.choice == SEQFEAT_GENE) {
5681       *last = next;
5682       xref->next = NULL;
5683       grp = (GeneRefPtr) xref->data.value.ptrvalue;
5684       xref->data.value.ptrvalue = NULL;
5685       SeqFeatXrefFree (xref);
5686     } else {
5687       last = &(xref->next);
5688     }
5689     xref = next;
5690   }
5691   if (grp == NULL) return TRUE;
5692   xgp = MemNew (sizeof (XrefGeneData));
5693   if (xgp == NULL) return TRUE;
5694   xgp->grp = grp;
5695   xgp->slp = AsnIoMemCopy (sfp->location, (AsnReadFunc) SeqLocAsnRead,
5696                            (AsnWriteFunc) SeqLocAsnWrite);
5697   /* if feature is pseudo, gene created from xref on feature should also be pseudo */
5698   xgp->pseudo = sfp->pseudo;
5699 
5700   ValNodeAddPointer (vnpp, 0, xgp);
5701   return TRUE;
5702 }
5703 
5704 static void XrefToGene (IteM i)
5705 
5706 {
5707   BaseFormPtr   bfp;
5708   BioseqPtr     bsp;
5709   Uint2         entityID = 0;
5710   GatherScope   gs;
5711   ValNodePtr    head;
5712   SeqEntryPtr   nsep;
5713   SeqFeatPtr    sfp;
5714   SelStructPtr  ssp;
5715   ValNodePtr    vnp;
5716   XrefGenePtr   xgp;
5717 
5718   head = NULL;
5719   ssp = ObjMgrGetSelected ();
5720   if (ssp == NULL) {
5721 #ifdef WIN_MAC
5722     bfp = currentFormDataPtr;
5723 #else
5724     bfp = GetObjectExtra (i);
5725 #endif
5726     if (bfp == NULL) {
5727       Message (MSG_ERROR, "XrefToGene error");
5728       return;
5729     }
5730     entityID = bfp->input_entityID;
5731     MemSet ((Pointer) (&gs), 0, sizeof (GatherScope));
5732     gs.seglevels = 1;
5733     MemSet((Pointer)(gs.ignore), (int)(TRUE), (size_t)(OBJ_MAX * sizeof(Boolean)));
5734     gs.ignore[OBJ_BIOSEQ] = FALSE;
5735     gs.ignore[OBJ_BIOSEQ_SEG] = FALSE;
5736     gs.ignore[OBJ_SEQANNOT] = FALSE;
5737     gs.ignore[OBJ_SEQFEAT] = FALSE;
5738     GatherEntity (bfp->input_entityID, (Pointer) &head, XrefToGeneCallback, &gs);
5739   } else {
5740     entityID = ssp->entityID;
5741     if (ssp->itemtype != OBJ_SEQFEAT) {
5742       Message (MSG_ERROR, "Feature must be selected");
5743       return;
5744     }
5745     GatherItem (ssp->entityID, ssp->itemID, ssp->itemtype, (Pointer) &head, XrefToGeneCallback);
5746   }
5747   if (head == NULL || entityID == 0) return;
5748   for (vnp = head; vnp != NULL; vnp = vnp->next) {
5749     xgp = (XrefGenePtr) vnp->data.ptrvalue;
5750     if (xgp != NULL) {
5751       bsp = GetBioseqGivenSeqLoc (xgp->slp, entityID);
5752       if (bsp != NULL) {
5753         nsep = SeqMgrGetSeqEntryForData (bsp);
5754         if (! ExtendGene (xgp->grp, nsep, xgp->slp)) {
5755           sfp = CreateNewFeature (nsep, NULL, SEQFEAT_GENE, NULL);
5756           if (sfp != NULL) {
5757             sfp->data.value.ptrvalue = (Pointer) xgp->grp;
5758             xgp->grp = NULL;
5759             sfp->location = SeqLocFree (sfp->location);
5760             sfp->location = xgp->slp;
5761             xgp->slp = NULL;
5762             sfp->pseudo = xgp->pseudo;
5763           }
5764         }
5765       }
5766       GeneRefFree (xgp->grp);
5767       SeqLocFree (xgp->slp);
5768     }
5769   }
5770   ValNodeFreeData (head);
5771   ObjMgrSetDirtyFlag (entityID, TRUE);
5772   ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
5773 }
5774 
5775 static void GeneToXrefCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
5776 
5777 {
5778   BaseFormPtr     bfp;
5779   BioseqPtr       bsp;
5780   BioseqSetPtr    bssp;
5781   SeqFeatPtr      gene;
5782   GeneRefPtr      grp;
5783   SeqFeatPtr      sfp;
5784   SeqAnnotPtr     sap;
5785   SeqFeatXrefPtr  xref;
5786 
5787   if (sep == NULL) return;
5788   bfp = (BaseFormPtr) mydata;
5789   if (bfp == NULL) return;
5790   if (IS_Bioseq (sep)) {
5791     bsp = (BioseqPtr) sep->data.ptrvalue;
5792     sap = bsp->annot;
5793   } else if (IS_Bioseq_set (sep)) {
5794     bssp = (BioseqSetPtr) sep->data.ptrvalue;
5795     sap = bssp->annot;
5796   } else return;
5797   while (sap != NULL) {
5798     if (sap->type == 1) {
5799       sfp = (SeqFeatPtr) sap->data;
5800       while (sfp != NULL) {
5801         if (sfp->data.choice != SEQFEAT_GENE) {
5802           FindGeneAndProtForCDS (bfp->input_entityID, sfp, &gene, NULL);
5803           if (gene != NULL) {
5804             grp = (GeneRefPtr) gene->data.value.ptrvalue;
5805             if (grp != NULL) {
5806               xref = SeqFeatXrefNew ();
5807               if (xref != NULL) {
5808                 xref->data.choice = SEQFEAT_GENE;
5809                 xref->data.value.ptrvalue = AsnIoMemCopy ((Pointer) grp,
5810                                                           (AsnReadFunc) GeneRefAsnRead,
5811                                                           (AsnWriteFunc) GeneRefAsnWrite);
5812                 xref->next = sfp->xref;
5813                 sfp->xref = xref;
5814               }
5815             }
5816           }
5817         }
5818         sfp = sfp->next;
5819       }
5820     }
5821     sap = sap->next;
5822   }
5823 }
5824 
5825 static void GeneToXref (IteM i)
5826 
5827 {
5828   BaseFormPtr  bfp;
5829   SeqEntryPtr  sep;
5830 
5831 #ifdef WIN_MAC
5832   bfp = currentFormDataPtr;
5833 #else
5834   bfp = GetObjectExtra (i);
5835 #endif
5836   if (bfp == NULL) {
5837     Message (MSG_ERROR, "GeneToXref error");
5838     return;
5839   }
5840   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
5841   if (sep == NULL) return;
5842   SeqEntryExplore (sep, (Pointer) bfp, GeneToXrefCallback);
5843   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
5844   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
5845 }
5846 
5847 typedef struct featurefieldforgenechoice
5848 {
5849   Int4    first_choice;
5850   Int4    second_choice;
5851   CharPtr field_txt;  
5852 } FeatureFieldForGeneChoiceData, PNTR FeatureFieldForGeneChoicePtr;
5853 
5854 static FeatureFieldForGeneChoicePtr FeatureFieldForGeneChoiceFree (FeatureFieldForGeneChoicePtr fcp)
5855 {
5856   if (fcp != NULL)
5857   {
5858     fcp->field_txt = MemFree (fcp->field_txt);
5859     fcp = MemFree (fcp);
5860   }
5861   return fcp;
5862 }
5863 
5864 typedef struct featuretogene
5865 {
5866   FEATURE_FORM_BLOCK
5867 
5868   DialoG *gene_src_dlg_list;
5869   Int4   num_choices;
5870   ValNodePtr feature_choices;
5871   
5872   TexT   label_txt;
5873   PopuP  genechoice;
5874   GrouP  qual_caps_grp;
5875   DialoG feature_dlg;
5876   DialoG filter_grp;
5877   DialoG accept_cancel;
5878   
5879   ButtoN single_interval_btn;
5880   ButtoN selected_features_only_btn;
5881   
5882   Boolean single_interval;
5883   FeatureFieldForGeneChoicePtr fcp;
5884   
5885 } FeatureToGeneData, PNTR FeatureToGenePtr;
5886 
5887 static Int4 GetGeneSrcDlgIndex (FeatureToGenePtr fgp)
5888 {
5889   ValNodePtr vnp, check_vnp;
5890   Int4       rval = -1, i;
5891   
5892   if (fgp == NULL) return -1;
5893 
5894   vnp = DialogToPointer (fgp->feature_dlg);
5895   if (vnp == NULL)
5896   {
5897     return -1;
5898   }
5899 
5900   check_vnp = fgp->feature_choices;
5901   i = 0;
5902   while (check_vnp != NULL && check_vnp->choice != vnp->choice)
5903   {
5904     check_vnp = check_vnp->next;
5905     i++;    
5906   }
5907   if (check_vnp != NULL)
5908   {
5909     rval = i;
5910   }
5911   ValNodeFreeData (vnp);
5912   return rval;
5913 }
5914 
5915 static void EnableFeatureToGeneControls (Pointer userdata)
5916 {
5917   Int4             i;
5918   FeatureToGenePtr fgp;
5919   FeatureFieldForGeneChoicePtr fcp;
5920   
5921   fgp = (FeatureToGenePtr) userdata;
5922   if (fgp == NULL) return;
5923   Disable (fgp->qual_caps_grp);
5924   Disable (fgp->genechoice);
5925   
5926   i = GetGeneSrcDlgIndex (fgp);
5927   if (i >= 0)
5928   {
5929     fcp = (FeatureFieldForGeneChoicePtr) DialogToPointer (fgp->gene_src_dlg_list [i]);
5930     if (fcp != NULL)
5931     {
5932       if (fcp->first_choice > 1 || !StringHasNoText (fcp->field_txt))
5933       {
5934         Enable (fgp->qual_caps_grp);
5935         Enable (fgp->genechoice);
5936       }     
5937       fcp = FeatureFieldForGeneChoiceFree (fcp);
5938     }
5939   }
5940 }
5941 
5942 static void EnableFeatureToGeneControlsPopup (PopuP p)
5943 {
5944   FeatureToGenePtr fgp;
5945   
5946   fgp = (FeatureToGenePtr) GetObjectExtra (p);
5947   EnableFeatureToGeneControls (fgp);
5948 }
5949 
5950 static void EnableFeatureToGeneControlsText (TexT t)
5951 {
5952   FeatureToGenePtr fgp;
5953   
5954   fgp = (FeatureToGenePtr) GetObjectExtra (t);
5955   EnableFeatureToGeneControls (fgp);
5956   
5957 }
5958 
5959 typedef struct featurefieldforgenedlg 
5960 {
5961   DIALOG_MESSAGE_BLOCK
5962   PopuP first_choice_popup;
5963   PopuP second_choice_popup;
5964   TexT  label_txt;
5965   Nlm_ChangeNotifyProc change_notify;
5966   Pointer              change_userdata;
5967 } FeatureFieldForGeneDlgData, PNTR FeatureFieldForGeneDlgPtr;
5968 
5969 static void ResetFeatureFieldForGeneDlg (FeatureFieldForGeneDlgPtr dlg)
5970 {
5971   if (dlg == NULL)
5972   {
5973     return;
5974   }
5975   
5976   SetValue (dlg->first_choice_popup, 1);
5977   SafeSetValue (dlg->second_choice_popup, 1);
5978   SetTitle (dlg->label_txt, "");
5979 }
5980 
5981 static void FeatureFieldForGeneToDialog (DialoG d, Pointer userdata)
5982 {
5983   FeatureFieldForGeneDlgPtr    dlg;
5984   FeatureFieldForGeneChoicePtr data;
5985 
5986   dlg = (FeatureFieldForGeneDlgPtr) GetObjectExtra (d);
5987   data = (FeatureFieldForGeneChoicePtr) userdata;
5988   if (dlg == NULL)
5989   {
5990     return;
5991   }
5992   ResetFeatureFieldForGeneDlg (dlg);
5993   if (data == NULL)
5994   {
5995     return;
5996   }
5997   if (data->first_choice > 0)
5998   {
5999     SetValue (dlg->first_choice_popup, data->first_choice);
6000   }
6001   if (data->second_choice > 0)
6002   {
6003     SafeSetValue (dlg->second_choice_popup, data->second_choice);
6004   }
6005   if (!StringHasNoText (data->field_txt))
6006   {
6007     SetTitle (dlg->label_txt, data->field_txt);
6008   }
6009 }
6010 
6011 static Pointer FeatureFieldForGeneFromDialog (DialoG d)
6012 {
6013   FeatureFieldForGeneDlgPtr    dlg;
6014   FeatureFieldForGeneChoicePtr data;
6015 
6016   dlg = (FeatureFieldForGeneDlgPtr) GetObjectExtra (d);
6017   if (dlg == NULL)
6018   {
6019     return NULL;
6020   }
6021   data = (FeatureFieldForGeneChoicePtr) MemNew (sizeof (FeatureFieldForGeneChoiceData));
6022   if (data != NULL)
6023   {
6024     data->first_choice = GetValue (dlg->first_choice_popup);
6025     if (dlg->second_choice_popup != NULL)
6026     {
6027       data->second_choice = GetValue (dlg->second_choice_popup);
6028     }
6029     else
6030     {
6031       data->second_choice = 0;
6032     }
6033     if (TextHasNoText (dlg->label_txt))
6034     {
6035       data->field_txt = NULL;
6036     }
6037     else
6038     {
6039       data->field_txt = SaveStringFromText (dlg->label_txt);
6040     }
6041   }
6042   return data;
6043 }
6044 
6045 static void FeatureFieldForGeneChange (FeatureFieldForGeneDlgPtr dlg)
6046 {
6047   if (dlg == NULL)
6048   {
6049     return;
6050   }
6051   if (GetValue (dlg->first_choice_popup) > 1)
6052   {
6053     SafeEnable (dlg->second_choice_popup);
6054   }
6055   else
6056   {
6057     SafeDisable (dlg->second_choice_popup);
6058   }
6059   if (dlg->change_notify != NULL)
6060   {
6061     (dlg->change_notify) (dlg->change_userdata);
6062   }
6063 }
6064 
6065 static void FeatureFieldForGeneChangePopup (PopuP p)
6066 {
6067   FeatureFieldForGeneDlgPtr  dlg;
6068 
6069   dlg = (FeatureFieldForGeneDlgPtr) GetObjectExtra (p);
6070   FeatureFieldForGeneChange (dlg);  
6071 }
6072 
6073 static void FeatureFieldForGeneChangeText (TexT t)
6074 {
6075   FeatureFieldForGeneDlgPtr  dlg;
6076 
6077   dlg = (FeatureFieldForGeneDlgPtr) GetObjectExtra (t);
6078   FeatureFieldForGeneChange (dlg);  
6079 }
6080 
6081 static PopuP MakeFieldChoicePopup (GrouP g, Int4 featdef_choice, Pointer extradata)
6082 {
6083   PopuP p;
6084   
6085   p = PopupList (g, TRUE, FeatureFieldForGeneChangePopup);
6086   SetObjectExtra (p, extradata, NULL);
6087   
6088   if (featdef_choice == FEATDEF_CDS
6089       || featdef_choice == FEATDEF_tRNA
6090       || featdef_choice == FEATDEF_rRNA
6091       || featdef_choice == FEATDEF_misc_RNA
6092       || featdef_choice == FEATDEF_mRNA)
6093   {  
6094     PopupItem (p, "None");
6095     PopupItem (p, "Comment");
6096     PopupItem (p, "Product");
6097   }
6098   else
6099   {
6100     PopupItem (p, "None");
6101     PopupItem (p, "Comment");
6102   }
6103   SetValue (p, 1);
6104   return p;     
6105 }
6106 
6107 static DialoG 
6108 FeatureFieldForGeneDialog 
6109 (GrouP parent, 
6110  Int4  featdef_choice,
6111  Nlm_ChangeNotifyProc change_notify,
6112  Pointer              change_userdata)
6113 {
6114   FeatureFieldForGeneDlgPtr  dlg;
6115   GrouP                     p;
6116   
6117   dlg = (FeatureFieldForGeneDlgPtr) MemNew (sizeof (FeatureFieldForGeneDlgData));
6118   if (dlg == NULL)
6119   {
6120     return NULL;
6121   }
6122 
6123   p = NormalGroup (parent, 2, 0, "Select qualifier to use in gene", NULL, NULL);
6124   SetObjectExtra (p, dlg, StdCleanupExtraProc);
6125 
6126   dlg->dialog = (DialoG) p;
6127   dlg->todialog = FeatureFieldForGeneToDialog;
6128   dlg->fromdialog = FeatureFieldForGeneFromDialog;
6129   dlg->dialogmessage = NULL;
6130   dlg->testdialog = NULL;
6131   dlg->change_notify = change_notify;
6132   dlg->change_userdata = change_userdata;
6133 
6134   StaticPrompt (p, "1st Choice", 0, 0, programFont, 'c');
6135   dlg->first_choice_popup = MakeFieldChoicePopup (p, featdef_choice, dlg);
6136   
6137   if (featdef_choice == FEATDEF_CDS
6138       || featdef_choice == FEATDEF_tRNA
6139       || featdef_choice == FEATDEF_rRNA
6140       || featdef_choice == FEATDEF_misc_RNA
6141       || featdef_choice == FEATDEF_mRNA)
6142   {
6143     StaticPrompt (p, "2nd Choice", 0, 0, programFont, 'c');
6144     dlg->second_choice_popup = MakeFieldChoicePopup (p, featdef_choice, dlg);
6145     Disable (dlg->second_choice_popup);
6146   }
6147   else
6148   {
6149     dlg->second_choice_popup = NULL;
6150   }
6151 
6152   StaticPrompt (p, "Use this string:", 0, 0, programFont, 'c');
6153   dlg->label_txt = DialogText (p, "", 10, FeatureFieldForGeneChangeText);
6154   SetObjectExtra (dlg->label_txt, dlg, NULL);
6155     
6156   return (DialoG) p;  
6157 }
6158 
6159 static CharPtr GetGeneSrcChoice (SeqFeatPtr sfp, Int4 choice)
6160 {
6161   CharPtr           src_txt = NULL;
6162   RnaRefPtr         rrp;
6163   SeqMgrFeatContext fcontext;
6164   
6165   if (sfp == NULL || choice < 2)
6166   {
6167     return NULL;
6168   }
6169   
6170   if (choice == 2 && !StringHasNoText (sfp->comment))
6171   {
6172     src_txt = StringSave (sfp->comment);
6173   }
6174   else if (choice == 3)
6175   {
6176     if (sfp->idx.subtype == FEATDEF_tRNA)
6177     {
6178       sfp = SeqMgrGetDesiredFeature (sfp->idx.entityID, NULL,
6179                                      0, 0, sfp, &fcontext);
6180       if (!StringHasNoText (fcontext.label))
6181       {
6182         src_txt = (CharPtr) MemNew (StringLen (fcontext.label) + 6);
6183         if (src_txt != NULL)
6184         {
6185           sprintf (src_txt, "tRNA-%s", fcontext.label);
6186         }
6187       }
6188     }
6189     else if (sfp->idx.subtype == FEATDEF_CDS
6190              || sfp->idx.subtype == FEATDEF_mRNA)
6191     {
6192       sfp = SeqMgrGetDesiredFeature (sfp->idx.entityID, NULL,
6193                                      0, 0, sfp, &fcontext);
6194       if (!StringHasNoText (fcontext.label))
6195       {
6196         src_txt = StringSave (fcontext.label);
6197       }
6198     }
6199     else if (sfp->data.choice == SEQFEAT_RNA)
6200     {
6201       rrp = (RnaRefPtr) (sfp->data.value.ptrvalue);
6202       if (rrp != NULL && rrp->ext.choice == 1
6203           && !StringHasNoText (rrp->ext.value.ptrvalue))
6204       {
6205         src_txt = StringSave (rrp->ext.value.ptrvalue);
6206       }
6207     }
6208   }
6209   return src_txt;  
6210 }
6211 
6212 static CharPtr GetGeneSrc (SeqFeatPtr sfp, FeatureFieldForGeneChoicePtr fcp)
6213 {
6214   CharPtr src_txt = NULL;
6215   
6216   if (sfp == NULL || fcp == NULL)
6217   {
6218     return NULL;
6219   }
6220   
6221   src_txt = GetGeneSrcChoice (sfp, fcp->first_choice);
6222   if (src_txt == NULL)
6223   {
6224     src_txt = GetGeneSrcChoice (sfp, fcp->second_choice);
6225   }
6226   if (src_txt == NULL && !StringHasNoText (fcp->field_txt))
6227   {
6228     src_txt = StringSave (fcp->field_txt);
6229   }
6230   return src_txt;  
6231 }
6232 
6233 static Boolean IsBioseqmRNA (BioseqPtr bsp)
6234 {
6235   SeqDescrPtr       sdp;
6236   SeqMgrDescContext context;
6237   MolInfoPtr        mip;
6238   
6239   sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_molinfo, &context);
6240   if (sdp == NULL || sdp->data.ptrvalue == NULL)
6241   {
6242     return FALSE;
6243   }
6244   
6245   mip = (MolInfoPtr) sdp->data.ptrvalue;
6246   if (mip->biomol == 3)
6247   {
6248     return TRUE;
6249   }
6250   return FALSE;
6251 }
6252 
6253 static void FeatureToGeneCallback (SeqFeatPtr sfp, Pointer userdata, FilterSetPtr fsp)
6254 {
6255   SeqFeatPtr         gene, overlap_gene;
6256   GeneRefPtr         grp;
6257   Boolean            partial5, partial3;
6258   FeatureToGenePtr   fgp;
6259   CharPtr            gene_val = NULL;
6260   Int4               i;
6261   BioseqPtr          bsp;
6262   CharPtr            cp;
6263   SeqLocPtr          gene_location;
6264 
6265   if (sfp == NULL || userdata == NULL) return;
6266   fgp = (FeatureToGenePtr) userdata;
6267   
6268   if (SeqMgrGetGeneXref (sfp) != NULL) return;
6269   
6270   bsp = BioseqFindFromSeqLoc (sfp->location);
6271   if (bsp == NULL) return;
6272   
6273   gene_location = SeqLocMerge (bsp, sfp->location, NULL, fgp->single_interval, FALSE, FALSE);
6274   if (gene_location == NULL) return;
6275   
6276   overlap_gene = SeqMgrGetOverlappingGene (sfp->location, NULL);
6277   if (overlap_gene != NULL && SeqLocCompare (gene_location, overlap_gene->location) == SLC_A_EQ_B)
6278   {
6279     gene_location = SeqLocFree (gene_location);
6280     return;
6281   }
6282   
6283   if (IsBioseqmRNA (bsp))
6284   {
6285     gene_location = SeqLocFree (gene_location);
6286     gene_location = SeqLocIntNew (0, bsp->length - 1, 
6287                                   SeqLocStrand (sfp->location),
6288                                   SeqIdFindBest (bsp->id, 0));
6289   }
6290   
6291   gene_val = GetGeneSrc (sfp, fgp->fcp);
6292 
6293   if (gene_val != NULL)
6294   {
6295         /* apply capitalization */
6296           switch (GetValue (fgp->qual_caps_grp))
6297         {
6298           case 1:
6299             /* do nothing, leave capitalization as is */
6300             break;
6301           case 2:
6302             /* capitalize first letter */
6303             gene_val [0] = toupper (gene_val[0]);
6304             break;
6305           case 3:
6306                 /* capitalize all letters */
6307                 for (cp = gene_val; *cp != 0; cp++)
6308                 {
6309                   *cp = toupper (*cp);
6310                 }
6311                 break;
6312         }
6313   }
6314 
6315   gene = SeqFeatNew ();
6316   if (gene == NULL) return;
6317     
6318   grp = GeneRefNew ();
6319   if (grp == NULL) return;
6320   i = GetValue (fgp->genechoice);
6321   switch (i)
6322   {
6323         case 1:
6324           grp->locus = gene_val;
6325           break;
6326         case 2:
6327           grp->locus_tag = gene_val;
6328           break;
6329         case 3:
6330           grp->desc = gene_val;
6331           break;
6332         case 4:
6333           grp->allele = gene_val;
6334           break;
6335         default:
6336           gene->comment = gene_val;
6337           break;
6338   }
6339     
6340   gene->data.choice = SEQFEAT_GENE;
6341   gene->data.value.ptrvalue = (Pointer) grp;
6342   gene->location = gene_location;
6343   CheckSeqLocForPartial (sfp->location, &partial5, &partial3);
6344   SetSeqLocPartial (gene->location, partial5, partial3);
6345   gene->partial = sfp->partial;
6346   gene->next = sfp->next;
6347   sfp->next = gene;
6348 }
6349 
6350 static Boolean FeatureToGeneAccept (Pointer userdata)
6351 {
6352   FeatureToGenePtr  fgp;
6353   SeqEntryPtr       sep;
6354   SelStructPtr      sel;
6355   SeqFeatPtr        sfp;
6356   SeqMgrFeatContext fcontext;
6357   FilterSetPtr      fsp;
6358   Int4              i, featdef_choice;
6359   ValNodePtr        vnp;
6360   
6361   fgp = (FeatureToGenePtr) userdata;
6362   if (fgp == NULL) return FALSE;
6363   
6364   vnp = DialogToPointer (fgp->feature_dlg);
6365   if (vnp == NULL)
6366   {
6367     return FALSE;
6368   }
6369   featdef_choice = vnp->choice;
6370   vnp = ValNodeFreeData (vnp);
6371   
6372   i = GetGeneSrcDlgIndex (fgp);
6373   if (i < 0)
6374   {
6375     return FALSE;
6376   }
6377 
6378   fgp->fcp = DialogToPointer (fgp->gene_src_dlg_list [i]);
6379   
6380   fsp = DialogToPointer (fgp->filter_grp);
6381   
6382   sep = GetTopSeqEntryForEntityID (fgp->input_entityID);
6383   if (sep == NULL) return FALSE;
6384   fgp->single_interval = GetStatus (fgp->single_interval_btn);
6385   if (GetStatus (fgp->selected_features_only_btn))
6386   {
6387     sel = ObjMgrGetSelected ();
6388     while (sel != NULL)
6389     {
6390       if (sel->itemtype == OBJ_SEQFEAT)
6391       {
6392         sfp = SeqMgrGetDesiredFeature (sel->entityID, NULL, sel->itemID, 0, NULL, &fcontext);
6393         if (sfp != NULL)
6394         {
6395           FeatureToGeneCallback (sfp, fgp, NULL);
6396         }
6397       }
6398       sel = sel->next;
6399     }
6400   }
6401   else
6402   {
6403     OperateOnSeqEntryConstrainedObjects (sep, fsp, FeatureToGeneCallback,
6404                                          NULL, 0, featdef_choice, 0, fgp);
6405   }
6406   
6407   FilterSetFree (fsp);
6408   fgp->fcp = FeatureFieldForGeneChoiceFree (fgp->fcp);
6409   
6410   ObjMgrSetDirtyFlag (fgp->input_entityID, TRUE);
6411   ObjMgrSendMsg (OM_MSG_UPDATE, fgp->input_entityID, 0, 0);
6412   return TRUE;
6413 }
6414 
6415 static void ChangeGeneFeatureSelection (Pointer userdata)
6416 {
6417   FeatureToGenePtr  fgp;
6418   Int4              i;
6419   
6420   fgp = (FeatureToGenePtr) userdata;
6421   if (fgp == NULL)
6422   {
6423     return;
6424   }
6425   
6426   for (i = 0; i < fgp->num_choices; i++)
6427   {
6428     Hide (fgp->gene_src_dlg_list [i]);
6429   }
6430 
6431   i = GetGeneSrcDlgIndex (fgp);
6432   
6433   if (i < 0)
6434   {
6435     DisableAcceptCancelDialogAccept (fgp->accept_cancel);
6436   }
6437   else
6438   {
6439     EnableAcceptCancelDialogAccept (fgp->accept_cancel);
6440     Show (fgp->gene_src_dlg_list [i]);
6441   }
6442   EnableFeatureToGeneControls (fgp);
6443 }
6444 
6445 static void CleanupFeatureToGeneForm (GraphiC g, VoidPtr data)
6446 {
6447   FeatureToGenePtr fgp;
6448 
6449   fgp = (FeatureToGenePtr) data;
6450   if (fgp != NULL) 
6451   {
6452     fgp->feature_choices = ValNodeFreeData (fgp->feature_choices);
6453     MemFree (fgp);
6454   }
6455 }
6456 
6457 static void FeatureToGeneClearText (Pointer userdata)
6458 {
6459   FeatureToGenePtr             fgp;
6460   Int4                         j;
6461   FilterSetPtr                 fsp;
6462   FeatureFieldForGeneChoicePtr fcp;
6463 
6464   fgp = (FeatureToGenePtr) userdata;
6465   if (fgp == NULL)
6466   {
6467     return;
6468   }
6469   
6470   for (j = 0; j < fgp->num_choices; j++)
6471   {
6472     fcp = (FeatureFieldForGeneChoicePtr) DialogToPointer (fgp->gene_src_dlg_list [j]);
6473     if (fcp != NULL)
6474     {
6475       fcp->field_txt = MemFree (fcp->field_txt);
6476     }
6477     PointerToDialog (fgp->gene_src_dlg_list [j], fcp);
6478     FeatureFieldForGeneChoiceFree (fcp);
6479   }
6480   
6481   fsp = (FilterSetPtr) DialogToPointer (fgp->filter_grp);
6482   FilterSetClearText (fsp);
6483   PointerToDialog (fgp->filter_grp, fsp);
6484   FilterSetFree (fsp);
6485   EnableFeatureToGeneControls (fgp);
6486 }
6487 
6488 static void FeatureToGeneClear (Pointer userdata)
6489 {
6490   FeatureToGenePtr  fgp;
6491   Int4              j;
6492 
6493   fgp = (FeatureToGenePtr) userdata;
6494   if (fgp == NULL)
6495   {
6496     return;
6497   }
6498   
6499   PointerToDialog (fgp->feature_dlg, NULL);
6500   for (j = 0; j < fgp->num_choices; j++)
6501   {
6502     PointerToDialog (fgp->gene_src_dlg_list [j], NULL);
6503   }
6504   PointerToDialog (fgp->filter_grp, NULL);
6505   
6506   SetValue (fgp->qual_caps_grp, 1);
6507   SetValue (fgp->genechoice, 1);
6508   SetStatus (fgp->single_interval_btn, TRUE);
6509   SetStatus (fgp->selected_features_only_btn, FALSE);
6510 
6511   ChangeGeneFeatureSelection (fgp);
6512   EnableFeatureToGeneControls (fgp);
6513 }
6514 
6515 static void FeatureToGene (IteM i)
6516 {
6517   BaseFormPtr       bfp;
6518   FeatureToGenePtr  fgp;
6519   WindoW            w;
6520   Int4              j;
6521   GrouP             h, k, m, n;
6522   ValNodePtr        vnp;
6523   SeqEntryPtr       sep;
6524 
6525 #ifdef WIN_MAC
6526   bfp = currentFormDataPtr;
6527 #else
6528   bfp = GetObjectExtra (i);
6529 #endif
6530   if (bfp == NULL) {
6531     Message (MSG_ERROR, "Feature to Gene error");
6532     return;
6533   }
6534   
6535   fgp = (FeatureToGenePtr) MemNew (sizeof (FeatureToGeneData));
6536   if (fgp == NULL) return;
6537   fgp->input_entityID = bfp->input_entityID;
6538   w = FixedWindow (-50, -33, -10, -10, "Feature to Gene", StdCloseWindowProc);
6539   SetObjectExtra (w, fgp, CleanupFeatureToGeneForm);
6540   fgp->form = (ForM) w;
6541 
6542   h = HiddenGroup (w, -1, 0, NULL);
6543   SetGroupSpacing (h, 10, 10);
6544 
6545   sep = GetTopSeqEntryForEntityID(bfp->input_entityID);
6546   fgp->feature_dlg = FeatureSelectionDialogEx (h, FALSE, sep, ChangeGeneFeatureSelection, fgp);
6547   k = HiddenGroup (h, 0, 0, NULL);
6548 
6549   fgp->feature_choices = BuildFeatureDialogList (TRUE, sep);
6550   fgp->num_choices = ValNodeLen (fgp->feature_choices);
6551   fgp->gene_src_dlg_list = (DialoG *) MemNew (fgp->num_choices * sizeof (DialoG));
6552   
6553   for (j = 0, vnp = fgp->feature_choices;
6554        j < fgp->num_choices && vnp != NULL;
6555        j++, vnp = vnp->next)
6556   {
6557     fgp->gene_src_dlg_list [j] = FeatureFieldForGeneDialog (k, vnp->choice,
6558                                                             EnableFeatureToGeneControls,
6559                                                             fgp);
6560   }
6561   
6562   fgp->qual_caps_grp = NormalGroup (h, 3, 0,
6563                      "Capitalization for gene", NULL, NULL);
6564   RadioButton (fgp->qual_caps_grp, "As is");
6565   RadioButton (fgp->qual_caps_grp, "Capitalize first initial");
6566   RadioButton (fgp->qual_caps_grp, "Capitalize all");
6567   SetValue (fgp->qual_caps_grp, 1);
6568   Disable (fgp->qual_caps_grp);
6569   m = HiddenGroup (h, 2, 0, NULL);
6570   StaticPrompt (m, "Select gene qualifier to populate", 0,0, programFont, 'c');
6571   fgp->genechoice = PopupList (m, TRUE, NULL);
6572   PopupItem (fgp->genechoice, "locus");
6573   PopupItem (fgp->genechoice, "locus_tag");
6574   PopupItem (fgp->genechoice, "gene description");
6575   PopupItem (fgp->genechoice, "allele");
6576   PopupItem (fgp->genechoice, "gene comment");
6577   SetValue (fgp->genechoice, 1);
6578   Disable (fgp->genechoice);
6579   
6580   n = HiddenGroup (h, 2, 0, NULL);
6581   fgp->single_interval_btn = CheckBox (n, "Create gene with single interval location", NULL);
6582   SetStatus (fgp->single_interval_btn, TRUE);
6583   fgp->selected_features_only_btn = CheckBox (n, "Only create genes for selected features", NULL);
6584   SetStatus (fgp->selected_features_only_btn, FALSE);
6585   
6586   fgp->filter_grp = FilterGroup (h, TRUE, FALSE, FALSE, FALSE, FALSE, "Where feature field contains");
6587 
6588   fgp->accept_cancel = AcceptCancelDialog (h, FeatureToGeneAccept, NULL, FeatureToGeneClear, FeatureToGeneClearText, (Pointer)fgp, w);
6589 
6590   AlignObjects (ALIGN_CENTER, (HANDLE) fgp->feature_dlg,
6591                               (HANDLE) k, 
6592                               (HANDLE) fgp->qual_caps_grp, 
6593                               (HANDLE) m,
6594                               (HANDLE) n,
6595                               (HANDLE) fgp->filter_grp,
6596                               (HANDLE) fgp->accept_cancel, 
6597                               NULL);
6598                 
6599   RealizeWindow (w);
6600   Show (w);
6601   Update ();
6602   ChangeGeneFeatureSelection (fgp);
6603 }
6604 
6605 
6606 typedef struct featuretocdsform
6607 {
6608   FEATURE_FORM_BLOCK
6609   PopuP   feature_choice;
6610   
6611   DialoG  gene_field;
6612   DialoG  exon_field;
6613   DialoG  mrna_field;
6614   GrouP   qual_caps_grp;
6615   TexT    append_text;
6616   ButtoN  accept_btn;
6617   ButtoN  fuse_multiple_btn;
6618   ButtoN  include_utr_btn;
6619   
6620   Int4       featdef_choice;
6621   ValNodePtr gene_field_list;
6622   ValNodePtr mrna_field_list;
6623   ValNodePtr exon_field_list;
6624   CharPtr    append_string;
6625   Int4       caps_choice;
6626   Boolean    fuse_multiple;
6627   Boolean    makemRNA;
6628   Boolean    include_utr;
6629   SeqEntryPtr sep;
6630   LogInfoData lid;
6631   
6632 } FeatureToCDSFormData, PNTR FeatureToCDSFormPtr;
6633 
6634 #define FEATURE_TO_CDS_GENE 1
6635 #define FEATURE_TO_CDS_MRNA 2
6636 #define FEATURE_TO_CDS_EXON 3
6637 
6638 static void EnableFeatureToCDSControls (Pointer data)
6639 {
6640   FeatureToCDSFormPtr    fp;
6641   Int4                   feature_choice;
6642   Boolean                need_name_string = FALSE;
6643   ValNodePtr             missing = NULL;
6644   CharPtr                cp;
6645 
6646   fp = (FeatureToCDSFormPtr) data;
6647   if (fp == NULL)
6648   {
6649     return;
6650   }
6651   Enable (fp->accept_btn);
6652   feature_choice = GetValue (fp->feature_choice);
6653   if (feature_choice == FEATURE_TO_CDS_GENE)
6654   {
6655     missing = TestDialog (fp->gene_field);
6656     if (missing != NULL)
6657     {
6658       need_name_string = TRUE;
6659       ValNodeFree (missing);
6660     }
6661   }
6662   else if (feature_choice == FEATURE_TO_CDS_EXON)
6663   {
6664     missing = DialogToPointer (fp->exon_field);
6665     if (missing == NULL)
6666     {
6667       need_name_string = TRUE;
6668     }
6669     ValNodeFree (missing);
6670   }
6671   else if (feature_choice == FEATURE_TO_CDS_MRNA)
6672   {
6673     missing = DialogToPointer (fp->mrna_field);
6674     if (missing == NULL)
6675     {
6676       need_name_string = TRUE;
6677     }
6678     ValNodeFree (missing);
6679   }
6680   
6681   if (need_name_string)
6682   {
6683     Disable (fp->qual_caps_grp);
6684     cp = SaveStringFromText (fp->append_text);
6685     if (StringHasNoText (cp))
6686     {
6687       Disable (fp->accept_btn);
6688     }
6689     MemFree (cp);
6690   }
6691   else
6692   {
6693     Enable (fp->qual_caps_grp);
6694   }
6695 }
6696 
6697 static void EnableFeatureToCDSControlsText (TexT t)
6698 {
6699   FeatureToCDSFormPtr    fp;
6700 
6701   fp = (FeatureToCDSFormPtr) GetObjectExtra (t);
6702   EnableFeatureToCDSControls (fp);
6703 }
6704 
6705 static void ChangeFeatureToCDS (PopuP p)
6706 {
6707   FeatureToCDSFormPtr    fp;
6708   Int4                   feature_choice;
6709 
6710   fp = (FeatureToCDSFormPtr) GetObjectExtra (p);
6711   if (fp != NULL)
6712   {
6713     feature_choice = GetValue (fp->feature_choice);
6714     if (feature_choice == FEATURE_TO_CDS_GENE)
6715     {
6716       Show (fp->gene_field);
6717       Hide (fp->mrna_field);
6718       Hide (fp->exon_field);
6719     }
6720     else if (feature_choice == FEATURE_TO_CDS_MRNA)
6721     {
6722       Show (fp->mrna_field);
6723       Hide (fp->gene_field);
6724       Hide (fp->exon_field);
6725     }
6726     else
6727     {
6728       Show (fp->exon_field);
6729       Hide (fp->mrna_field);
6730       Hide (fp->gene_field);
6731     }
6732   }
6733   EnableFeatureToCDSControls (fp);
6734 }
6735 
6736 static void CleanupFeatureToCDSPage (GraphiC g, VoidPtr data)
6737 {
6738   FeatureToCDSFormPtr fp;
6739 
6740   fp = (FeatureToCDSFormPtr) data;
6741   if (fp != NULL) 
6742   {
6743     fp->append_string = MemFree (fp->append_string);
6744     fp->gene_field_list = ValNodeFree (fp->gene_field_list);
6745     fp->mrna_field_list = ValNodeFree (fp->mrna_field_list);
6746     fp->exon_field_list = ValNodeFree (fp->exon_field_list);
6747     MemFree (fp);
6748   }
6749 }
6750 
6751 static void LogFeatureToCDSNoProtein (FeatureToCDSFormPtr fp, CharPtr feature_label, SeqIdPtr sip)
6752 {
6753   Char       id [41];
6754 
6755   if (fp == NULL || fp->lid.fp == NULL || sip == NULL) return;
6756 
6757   id [0] = '\0';
6758   SeqIdWrite (SeqIdFindBest (sip, 0), id, PRINTID_FASTA_LONG, sizeof (id) - 1);
6759   
6760   if (StringHasNoText (feature_label))
6761   {
6762     fprintf (fp->lid.fp, "No protein added for unlabeled feature on sequence %s\n", id);
6763   }
6764   else
6765   {
6766     fprintf (fp->lid.fp, "No protein added for %s on sequence %s\n", feature_label, id);
6767   }
6768   fp->lid.data_in_log = TRUE;
6769 }
6770 
6771 static CharPtr GetNewProteinName (SeqFeatPtr sfp, FeatureToCDSFormPtr fp)
6772 {
6773   SeqMgrFeatContext context;
6774   CharPtr           prot_name_src = NULL;
6775   CharPtr           protName = NULL;
6776   Int4              prot_len;
6777   CharPtr           cp;
6778   
6779   if (sfp == NULL || fp == NULL || sfp->idx.subtype != fp->featdef_choice)
6780   {
6781     return NULL;
6782   }
6783 
6784   if (SeqMgrGetDesiredFeature (sfp->idx.entityID, NULL,
6785                                0, 0, sfp, &context) == NULL) return NULL;
6786                                
6787   /* determine the new protein name */
6788   if (fp->featdef_choice == FEATDEF_GENE)
6789   {
6790     prot_name_src = GetGeneFieldString (sfp, fp->gene_field_list, NULL);
6791   }
6792   else if (fp->featdef_choice == FEATDEF_mRNA)
6793   {
6794     prot_name_src = GetmRNAFieldString (sfp, fp->mrna_field_list, NULL);
6795   }
6796   else if (fp->featdef_choice == FEATDEF_exon)
6797   {
6798     prot_name_src = GetExonFieldString (sfp, fp->exon_field_list);
6799   }
6800   else if (fp->featdef_choice == FEATDEF_CDS)
6801   {
6802     prot_name_src = GetCDSFieldString(sfp, fp->mrna_field_list, NULL);
6803   }
6804   
6805   if (StringHasNoText (prot_name_src) && StringHasNoText (fp->append_string))
6806   {
6807         return NULL;
6808   }
6809 
6810   prot_len = StringLen (prot_name_src) + StringLen (fp->append_string) + 2;
6811   
6812   /* add one to length for terminating null */
6813   protName = (CharPtr) MemNew (prot_len * sizeof (Char));
6814   if (protName == NULL) return NULL;
6815   
6816   if (!StringHasNoText (prot_name_src))
6817   {
6818     StringCpy (protName, prot_name_src);
6819         /* apply capitalization */
6820     switch (fp->caps_choice)
6821         {
6822           case 1:
6823             /* do nothing, leave capitalization as is */
6824             break;
6825           case 2:
6826             /* capitalize first letter */
6827             protName [0] = toupper (protName[0]);
6828             break;
6829           case 3:
6830                 /* capitalize all letters */
6831                 for (cp = protName; *cp != 0; cp++)
6832                 {
6833                   *cp = toupper (*cp);
6834                 }
6835                 break;
6836         }
6837         if (!StringHasNoText (fp->append_string))
6838         {
6839           StringCat (protName, " ");
6840         }
6841   }
6842   prot_name_src = MemFree (prot_name_src);
6843   if (!StringHasNoText (fp->append_string))
6844   {
6845     StringCat (protName, fp->append_string);
6846   }
6847   return protName;  
6848 }
6849 
6850 static SeqFeatPtr MakeCDS(SeqLocPtr location, CharPtr name_str, Uint2 entityID, SeqEntryPtr sep, LogInfoPtr lip)
6851 {
6852   SeqFeatPtr        cds, sfp;
6853   Int2              genCode;
6854   CdRegionPtr       crp;
6855   ByteStorePtr      bs;
6856   BioseqPtr         bsp;
6857   SeqEntryPtr       psep, nsep, old, topsep;
6858   MolInfoPtr        mip;
6859   ProtRefPtr        prp;
6860   Char              ch;
6861   ValNodePtr        descr;
6862   Int2              i;
6863   Boolean           partial5, partial3;
6864   CharPtr           prot;
6865   CharPtr           ptr;
6866   ValNodePtr        vnp;
6867   
6868   cds = SeqFeatNew ();
6869   
6870   CheckSeqLocForPartial (location, &partial5, &partial3);
6871 
6872   if (cds == NULL) return NULL;
6873   cds->data.choice = SEQFEAT_CDREGION;
6874 
6875   genCode = SeqEntryToGeneticCode (sep, NULL, NULL, 0);
6876   crp = CreateNewCdRgn (1, FALSE, genCode);
6877   if (crp == NULL) {
6878     return NULL;
6879   }
6880  
6881   cds->data.value.ptrvalue = (Pointer) crp;
6882   cds->location = SeqLocFree (cds->location);
6883   cds->location = AsnIoMemCopy ((Pointer) location,
6884                                 (AsnReadFunc) SeqLocAsnRead,
6885                                 (AsnWriteFunc) SeqLocAsnWrite);
6886   cds->partial = partial5 | partial3;                                
6887   
6888   if (!SetBestFrameByLocation (cds)) {
6889     LogCDSAmbiguousFrame (lip, cds);
6890   }
6891  
6892   bs = ProteinFromCdRegionEx (cds, TRUE, FALSE);
6893   if (bs != NULL) {
6894     prot = BSMerge (bs, NULL);
6895     bs = BSFree (bs);
6896     if (prot != NULL) {
6897       ptr = prot;
6898       ch = *ptr;
6899       while (ch != '\0') {
6900         *ptr = TO_UPPER (ch);
6901         ptr++;
6902         ch = *ptr;
6903       }
6904       i = (Int2) StringLen (prot);
6905       if (i > 0 && prot [i - 1] == '*') {
6906         prot [i - 1] = '\0';
6907       }
6908       bs = BSNew (1000);
6909           if (bs != NULL) {
6910         ptr = prot;
6911         BSWrite (bs, (VoidPtr) ptr, (Int4) StringLen (ptr));
6912       }
6913     }
6914   }
6915   bsp = BioseqNew ();
6916   if (bsp == NULL) return NULL;
6917   bsp->repr = Seq_repr_raw;
6918   bsp->mol = Seq_mol_aa;
6919   bsp->seq_data_type = Seq_code_ncbieaa;
6920   bsp->seq_data = (SeqDataPtr) bs;
6921   bsp->length = BSLen (bs);
6922   bs = NULL;
6923   old = SeqEntrySetScope (NULL);
6924   bsp->id = MakeNewProteinSeqId (cds->location, NULL);
6925   SeqMgrAddToBioseqIndex (bsp);
6926   SeqEntrySetScope (old);
6927   psep = SeqEntryNew ();
6928   if (psep != NULL) {
6929     psep->choice = 1;
6930     psep->data.ptrvalue = (Pointer) bsp;
6931     SeqMgrSeqEntry (SM_BIOSEQ, (Pointer) bsp, psep);
6932     mip = MolInfoNew ();
6933     if (mip != NULL) {
6934       mip->biomol = 8;
6935       mip->tech = 8;
6936       if (partial5 && partial3) {
6937         mip->completeness = 5;
6938       } else if (partial5) {
6939         mip->completeness = 3;
6940       } else if (partial3) {
6941         mip->completeness = 4;
6942       }
6943       vnp = CreateNewDescriptor (psep, Seq_descr_molinfo);
6944       if (vnp != NULL) {
6945         vnp->data.ptrvalue = (Pointer) mip;
6946       }
6947     }
6948     descr = ExtractBioSourceAndPubs (sep);
6949     if (IS_Bioseq_set (sep))
6950     {
6951       topsep = sep;
6952     }
6953     else
6954     {
6955       topsep = GetBestTopParentForData (entityID, sep->data.ptrvalue);
6956     }
6957     AddSeqEntryToSeqEntry (topsep, psep, TRUE);
6958     nsep = FindNucSeqEntry (sep);
6959     ReplaceBioSourceAndPubs (sep, descr);
6960     SetSeqFeatProduct (cds, bsp);
6961     prp = CreateNewProtRef (name_str, NULL, NULL, NULL);
6962     sfp = CreateNewFeature (psep, NULL, SEQFEAT_PROT, NULL);
6963     if (sfp != NULL) {
6964        sfp->data.value.ptrvalue = (Pointer) prp;
6965     }
6966   }
6967   return cds;
6968 
6969 }
6970 
6971 
6972 static SeqFeatPtr MakemRNA (SeqLocPtr location, CharPtr protName, SeqEntryPtr sep, Boolean include_utr)
6973 {
6974   SeqFeatPtr sfp;
6975   RnaRefPtr  rrp;
6976   Boolean    partial5, partial3;
6977   
6978   sfp = SeqFeatNew();
6979   rrp = RnaRefNew();
6980   rrp->type = RNA_TYPE_mRNA;
6981   rrp->ext.choice = 1;
6982   rrp->ext.value.ptrvalue = protName;
6983   sfp->data.value.ptrvalue = rrp;
6984   sfp->data.choice = SEQFEAT_RNA;
6985   
6986   CheckSeqLocForPartial (location, &partial5, &partial3);
6987   sfp->location = SeqLocFree (sfp->location);
6988   if (include_utr) {
6989     sfp->location = GetmRNALocationFromCDSLocation (location, sfp->idx.entityID);
6990   } else {
6991     sfp->location = AsnIoMemCopy ((Pointer) location,
6992                                   (AsnReadFunc) SeqLocAsnRead,
6993                                   (AsnWriteFunc) SeqLocAsnWrite);
6994   }
6995   sfp->partial = partial5 | partial3;
6996   
6997   return sfp;
6998 }
6999 
7000 
7001 static SeqFeatPtr FeatureToCDS (SeqFeatPtr sfp, FeatureToCDSFormPtr fp)
7002 
7003 {
7004   SeqFeatPtr        cds;
7005   SeqMgrFeatContext context;
7006   CharPtr           protName = NULL;
7007   RnaRefPtr         rrp;
7008 
7009   
7010   if (sfp == NULL || fp == NULL || sfp->idx.subtype != fp->featdef_choice)
7011   {
7012     return NULL;
7013   }
7014 
7015   if (fp->makemRNA) {
7016     cds = SeqMgrGetOverlappingmRNA (sfp->location, &context);
7017   } else  {
7018     cds = SeqMgrGetOverlappingCDS (sfp->location, &context);
7019   }
7020   if (cds != NULL) 
7021   {
7022     return NULL;        
7023   }
7024 
7025   if (SeqMgrGetDesiredFeature (sfp->idx.entityID, NULL,
7026                                0, 0, sfp, &context) == NULL) 
7027   {
7028     return NULL;
7029   }
7030                                
7031   protName = GetNewProteinName (sfp, fp);
7032   if (protName == NULL)
7033   {
7034     LogFeatureToCDSNoProtein (fp, context.label, SeqLocId (sfp->location));
7035     return NULL;
7036   }
7037 
7038   /* make sure mRNA product name matches CDS protein name */
7039   if (fp->featdef_choice == FEATDEF_mRNA && !fp->makemRNA)
7040   {
7041     rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
7042     if (rrp != NULL)
7043     {
7044       rrp->ext.value.ptrvalue = MemFree (rrp->ext.value.ptrvalue);
7045       rrp->ext.value.ptrvalue = StringSave (protName);
7046     }    
7047   }
7048   
7049   /* need to remove string */
7050   if (fp->featdef_choice == FEATDEF_GENE)
7051   {
7052     RemoveGeneFieldString (sfp, fp->gene_field_list);
7053   }
7054   else if (fp->featdef_choice == FEATDEF_mRNA)
7055   {
7056     RemovemRNAFieldString (sfp, fp->mrna_field_list);
7057   }
7058   else if (fp->featdef_choice == FEATDEF_exon)
7059   {
7060     RemoveExonFieldString (sfp, fp->exon_field_list);
7061   }
7062   else if (fp->featdef_choice == FEATDEF_CDS)
7063   {
7064     RemoveCDSFieldString (sfp, fp->mrna_field_list);
7065   }
7066   
7067   if (fp->makemRNA) {
7068     cds = MakemRNA (sfp->location, protName, fp->sep, fp->include_utr);
7069   } else {
7070     cds = MakeCDS(sfp->location, protName, fp->input_entityID, fp->sep, &(fp->lid));
7071   }
7072   
7073   cds->partial = sfp->partial;
7074   cds->next = sfp->next;
7075   sfp->next = cds;
7076 
7077   return cds;
7078 }
7079 
7080 static void 
7081 LogFeatureToCDSMismatchProtein 
7082 (FeatureToCDSFormPtr fp, 
7083  SeqIdPtr            sip)
7084 {
7085   Char       id [41];
7086 
7087   if (fp == NULL || fp->lid.fp == NULL || sip == NULL) return;
7088 
7089   id [0] = '\0';
7090   SeqIdWrite (SeqIdFindBest (sip, 0), id, PRINTID_FASTA_LONG, sizeof (id) - 1);
7091   
7092   fprintf (fp->lid.fp, "The protein names generated from features on %s do not match\n", id);
7093   
7094   fp->lid.data_in_log = TRUE;
7095 }
7096 
7097 extern void LogCDSAmbiguousFrame (LogInfoPtr lip, SeqFeatPtr sfp)
7098 {
7099   CharPtr loc_str;
7100   
7101   if (lip == NULL || lip->fp == NULL || sfp == NULL) {
7102     return;
7103   }
7104   
7105   loc_str = SeqLocPrintUseBestID (sfp->location);
7106   fprintf (lip->fp, "Ambiguous frames detected for coding region at %s\n", loc_str);
7107   loc_str = MemFree (loc_str);
7108   lip->data_in_log = TRUE;
7109 }
7110 
7111 static void FeatureToCDSBioseqCheckCallback (BioseqPtr bsp, Pointer userdata)
7112 
7113 {
7114   FeatureToCDSFormPtr fp;
7115   CharPtr             last_prot_name = NULL, new_prot_name;
7116   SeqMgrFeatContext   feature_context, cds_context;
7117   SeqFeatPtr          sfp, cds;
7118 
7119   if (bsp == NULL || userdata == NULL) return;
7120   fp = (FeatureToCDSFormPtr) userdata;
7121   fp->sep = SeqMgrGetSeqEntryForData (bsp);
7122   
7123   /* if we are fusing features, find all the features on this Bioseq for
7124    * our type.
7125    */
7126   sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &feature_context);
7127   while (sfp != NULL)
7128   {
7129     if (sfp->idx.subtype == fp->featdef_choice)
7130     {
7131       if (fp->makemRNA) {
7132         cds = SeqMgrGetOverlappingmRNA (sfp->location, &cds_context);
7133       } else {
7134         cds = SeqMgrGetOverlappingCDS (sfp->location, &cds_context);
7135       }
7136       if (cds == NULL) 
7137       {
7138         new_prot_name = GetNewProteinName (sfp, fp);
7139         if (!fp->fuse_multiple)
7140         {
7141           if (new_prot_name == NULL)
7142           {
7143             LogFeatureToCDSNoProtein (fp, feature_context.label, SeqLocId (sfp->location));
7144           }
7145         }
7146         else if (last_prot_name == NULL && new_prot_name != NULL)
7147         {
7148           if (new_prot_name == NULL)
7149           {
7150             LogFeatureToCDSNoProtein (fp, feature_context.label, SeqLocId (sfp->location));
7151           }
7152           else
7153           {
7154             last_prot_name = new_prot_name;
7155           }
7156         }
7157         else if (new_prot_name == NULL)
7158         {
7159           /* do nothing - will use protein name from prior CDS */ 
7160         }
7161         else if (StringCmp (last_prot_name, new_prot_name) == 0)
7162         {
7163           /* no conflict */
7164           MemFree (new_prot_name);
7165         }
7166         else
7167         {
7168           LogFeatureToCDSMismatchProtein (fp, SeqLocId (sfp->location));
7169           MemFree (last_prot_name);
7170           last_prot_name = new_prot_name;
7171         }
7172       }
7173     }
7174     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, fp->featdef_choice, &feature_context);
7175   }
7176 }
7177 
7178 static void FeatureToCDSBioseqActCallback (BioseqPtr bsp, Pointer userdata)
7179 
7180 {
7181   FeatureToCDSFormPtr fp;
7182   SeqFeatPtr          first = NULL;
7183   CharPtr             new_prot_name;
7184   SeqMgrFeatContext   feature_context, cds_context;
7185   SeqFeatPtr          sfp, cds;
7186   SeqLocPtr           new_cds_location = NULL, slp, tmp_loc;
7187   Boolean             first_partial5, first_partial3;
7188   Int4                first_start_pos, first_stop_pos;
7189   Boolean             sfp_partial5, sfp_partial3;
7190   Int4                sfp_start_pos, sfp_stop_pos;
7191 
7192   if (bsp == NULL || userdata == NULL) return;
7193   fp = (FeatureToCDSFormPtr) userdata;
7194   fp->sep = SeqMgrGetSeqEntryForData (bsp);
7195   
7196   /* if we are fusing features, find all the features on this Bioseq for
7197    * our type.
7198    */
7199   sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &feature_context);
7200   while (sfp != NULL)
7201   {
7202     if (sfp->idx.subtype == fp->featdef_choice)
7203     {
7204       if (fp->makemRNA) {
7205         cds = SeqMgrGetOverlappingmRNA (sfp->location, &cds_context);
7206       } else {
7207         cds = SeqMgrGetOverlappingCDS (sfp->location, &cds_context);
7208       }
7209       if (cds == NULL) 
7210       {
7211         if (fp->fuse_multiple)
7212         {
7213           if (first == NULL)
7214           {
7215             new_prot_name = GetNewProteinName (sfp, fp);
7216             if (new_prot_name != NULL)
7217             {
7218               first = sfp;
7219               new_cds_location = (SeqLocPtr) AsnIoMemCopy ((Pointer) sfp->location,
7220                                                      (AsnReadFunc) SeqLocAsnRead,
7221                                                      (AsnWriteFunc) SeqLocAsnWrite);
7222               MemFree (new_prot_name);
7223             }
7224           }
7225           else
7226           {
7227             /* preserve partialness of ends */
7228             CheckSeqLocForPartial (new_cds_location, &first_partial5, &first_partial3);
7229             first_start_pos = SeqLocStart (new_cds_location);
7230             first_stop_pos = SeqLocStop (new_cds_location);
7231             CheckSeqLocForPartial (sfp->location, &sfp_partial5, &sfp_partial3);
7232             sfp_start_pos = SeqLocStart (sfp->location);
7233             sfp_stop_pos = SeqLocStop (sfp->location);
7234             if (first_start_pos > sfp_start_pos)
7235             {
7236               first_partial5 = sfp_partial5;
7237             }
7238             if (first_stop_pos < sfp_stop_pos)
7239             {
7240               first_partial3 = sfp_partial3;
7241             }
7242             
7243             slp = SeqLocMerge (bsp, sfp->location, new_cds_location, FALSE, TRUE, FALSE);
7244             new_cds_location = SeqLocFree (new_cds_location);
7245             new_cds_location = slp;
7246             SetSeqLocPartial (new_cds_location, first_partial5, first_partial3);            
7247             first_start_pos = SeqLocStart (new_cds_location);
7248             first_stop_pos = SeqLocStop (new_cds_location);
7249           }
7250         }
7251         else
7252         {
7253           FeatureToCDS (sfp, fp);
7254         }
7255       }
7256     }
7257     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, fp->featdef_choice, &feature_context);
7258   }
7259   if (fp->fuse_multiple && first != NULL)
7260   {
7261     tmp_loc = first->location;
7262     first->location = new_cds_location;
7263     cds = FeatureToCDS (first, fp);
7264     if (cds != NULL)
7265     {
7266       cds->partial = CheckSeqLocForPartial (cds->location, &first_partial5, &first_partial3);
7267     }
7268     first->location = tmp_loc;
7269     new_cds_location = SeqLocFree (new_cds_location);
7270   }
7271 }
7272 
7273 static void FeatureToCDSAccept (ButtoN b)
7274 {
7275   FeatureToCDSFormPtr    fp;
7276   Int4                   feature_choice;
7277   MsgAnswer              ans = ANS_YES;
7278 
7279   fp = (FeatureToCDSFormPtr) GetObjectExtra (b);
7280   if (fp == NULL)
7281   {
7282     return;
7283   }
7284   
7285   feature_choice = GetValue (fp->feature_choice);
7286   if (feature_choice == FEATURE_TO_CDS_GENE)
7287   {
7288     fp->featdef_choice = FEATDEF_GENE;
7289     fp->gene_field_list = DialogToPointer (fp->gene_field);
7290   }
7291   else if (feature_choice == FEATURE_TO_CDS_MRNA)
7292   {
7293     if (fp->makemRNA) {
7294       fp->featdef_choice = FEATDEF_CDS;
7295     } else {
7296       fp->featdef_choice = FEATDEF_mRNA;
7297     }
7298     fp->mrna_field_list = DialogToPointer (fp->mrna_field);
7299   }
7300   else if (feature_choice == FEATURE_TO_CDS_EXON)
7301   {
7302     fp->featdef_choice = FEATDEF_exon;
7303     fp->exon_field_list = DialogToPointer (fp->exon_field);
7304   }
7305   else
7306   {
7307     return;
7308   }
7309 
7310   TmpNam (fp->lid.path);
7311   fp->lid.fp = FileOpen (fp->lid.path, "wb");
7312   if (fp->lid.fp == NULL) return;
7313   fp->lid.display_title = "Name Problems";
7314   
7315   Hide (fp->form);
7316   WatchCursor ();
7317   Update ();
7318 
7319   fp->sep = GetTopSeqEntryForEntityID (fp->input_entityID);
7320   if (fp->sep == NULL) return;
7321   
7322   fp->caps_choice = GetValue (fp->qual_caps_grp);
7323   
7324   fp->append_string = JustSaveStringFromText (fp->append_text);
7325   
7326   fp->fuse_multiple = GetStatus (fp->fuse_multiple_btn);
7327   if (fp->makemRNA) {
7328     fp->include_utr = GetStatus (fp->include_utr_btn);
7329   }
7330 
7331   VisitBioseqsInSep (fp->sep, (Pointer) fp, FeatureToCDSBioseqCheckCallback);
7332 
7333   if (ans == ANS_YES)
7334   {
7335     fp->sep = GetTopSeqEntryForEntityID (fp->input_entityID);
7336     VisitBioseqsInSep (fp->sep, (Pointer) fp, FeatureToCDSBioseqActCallback);
7337   }
7338   
7339   CloseLog (&(fp->lid));
7340     
7341   ArrowCursor ();
7342   Update ();
7343 
7344   ObjMgrSetDirtyFlag (fp->input_entityID, TRUE);
7345   ObjMgrSendMsg (OM_MSG_UPDATE, fp->input_entityID, 0, 0); 
7346   if (GetStatus (fp->leave_dlg_up)) {
7347     Show (fp->form);
7348   } else {
7349     Remove (fp->form);
7350   }
7351 }
7352 
7353 static void FeatureToCDSormRNA (IteM i, Boolean makemRNA)
7354 
7355 {
7356   BaseFormPtr            bfp;
7357   FeatureToCDSFormPtr    fp;
7358   WindoW                 w;
7359   GrouP                  h, g, m, c;
7360   CharPtr                title, grp_title;
7361 
7362 #ifdef WIN_MAC
7363   bfp = currentFormDataPtr;
7364 #else
7365   bfp = GetObjectExtra (i);
7366 #endif
7367   if (bfp == NULL) {
7368     Message (MSG_ERROR, "FeatureToCDS error");
7369     return;
7370   }
7371   
7372   fp = (FeatureToCDSFormPtr) MemNew (sizeof (FeatureToCDSFormData));
7373   if (fp == NULL) return;
7374   fp->input_entityID = bfp->input_entityID;
7375   fp->input_itemID = bfp->input_itemID;
7376   fp->input_itemtype = bfp->input_itemtype;
7377   
7378   fp->makemRNA = makemRNA;
7379   
7380   if (makemRNA) {
7381     title = "Feature to mRNA";
7382   } else {
7383     title = "Feature to CDS";
7384   }
7385   w = FixedWindow (-50, -33, -10, -10, title, StdCloseWindowProc);
7386   SetObjectExtra (w, fp, CleanupFeatureToCDSPage);
7387   fp->form = (ForM) w;
7388 
7389   h = HiddenGroup (w, -1, 0, NULL);
7390   SetGroupSpacing (h, 10, 10);
7391   
7392   fp->feature_choice = PopupList (h, TRUE, ChangeFeatureToCDS);
7393   PopupItem (fp->feature_choice, "Gene");
7394   if (makemRNA) {
7395     PopupItem (fp->feature_choice, "CDS");
7396   } else {
7397     PopupItem (fp->feature_choice, "mRNA");
7398   }
7399   PopupItem (fp->feature_choice, "exon");
7400   SetValue (fp->feature_choice, FEATURE_TO_CDS_GENE);
7401   SetObjectExtra (fp->feature_choice, fp, NULL);
7402 
7403   if (makemRNA) {
7404     grp_title = "Source for new mRNA name";
7405   } else {
7406     grp_title = "Source for new CDS protein name";
7407   }
7408   g = NormalGroup (h, 0, 0, grp_title, NULL, NULL);
7409   fp->gene_field = FeatureFieldChoiceDialog (g, GeneFieldSelectionDialog, TRUE, EnableFeatureToCDSControls, fp);
7410   fp->mrna_field = FeatureFieldChoiceDialog (g, MRNAFieldSelectionDialog, TRUE, EnableFeatureToCDSControls, fp);
7411   fp->exon_field = FeatureFieldChoiceDialog (g, ExonFieldSelectionDialog, TRUE, EnableFeatureToCDSControls, fp);
7412   Hide (fp->mrna_field);
7413   Hide (fp->exon_field);
7414   AlignObjects (ALIGN_CENTER, (HANDLE) fp->gene_field,
7415                               (HANDLE) fp->mrna_field, 
7416                               (HANDLE) fp->exon_field, 
7417                               NULL);
7418   
7419   fp->qual_caps_grp = NormalGroup (h, 3, 0,
7420                      "Capitalization for field in name", NULL, NULL);
7421   RadioButton (fp->qual_caps_grp, "As is");
7422   RadioButton (fp->qual_caps_grp, "Capitalize first initial");
7423   RadioButton (fp->qual_caps_grp, "Capitalize all");
7424   SetValue (fp->qual_caps_grp, 1);
7425   
7426   m = HiddenGroup (h, 0, 2, NULL);
7427   StaticPrompt (m, "Append text to name", 0, 0, programFont, 'c');
7428   fp->append_text = DialogText (m, "", 14, EnableFeatureToCDSControlsText); 
7429   SetObjectExtra (fp->append_text, fp, NULL);
7430   
7431   if(makemRNA) {
7432     fp->fuse_multiple_btn = CheckBox (h, "Fuse multiple intervals for new mRNA", NULL);
7433     fp->include_utr_btn = CheckBox (h, "Include UTR regions in mRNA location", NULL);
7434   } else {
7435     fp->fuse_multiple_btn = CheckBox (h, "Fuse multiple intervals for new CDS", NULL);
7436     fp->include_utr_btn = NULL;
7437   }
7438    
7439   c = HiddenGroup (h, 4, 0, NULL); 
7440   fp->accept_btn = PushButton (c, "Accept", FeatureToCDSAccept);
7441   SetObjectExtra (fp->accept_btn, fp, NULL);
7442   EnableFeatureToCDSControls (fp);
7443   
7444   PushButton (c, "Cancel", StdCancelButtonProc);
7445   fp->leave_dlg_up = CheckBox (c, "Leave Dialog Up", NULL);
7446 
7447   AlignObjects (ALIGN_CENTER, (HANDLE) fp->feature_choice,
7448                               (HANDLE) g,
7449                               (HANDLE) fp->qual_caps_grp,
7450                               (HANDLE) m, 
7451                               (HANDLE) fp->fuse_multiple_btn, 
7452                               (HANDLE) c, 
7453                               (HANDLE) fp->include_utr_btn,
7454                               NULL);
7455                 
7456   RealizeWindow (w);
7457   Show (w);
7458   Update ();
7459   
7460 }
7461 
7462 static void FeatureToCds (IteM i)
7463 {
7464   FeatureToCDSormRNA (i, FALSE);
7465 }
7466 
7467 
7468 static void FeatureTomRNA (IteM i)
7469 {
7470   FeatureToCDSormRNA (i, TRUE);
7471 }
7472 
7473 
7474 static void AddFeatureToBioseq (SeqFeatPtr sfp, BioseqPtr bsp)
7475 
7476 {
7477   SeqFeatPtr   prev;
7478   SeqAnnotPtr  sap;
7479 
7480   if (sfp == NULL || bsp == NULL) return;
7481   sap = bsp->annot;
7482   while (sap != NULL && (sap->name != NULL || sap->desc != NULL || sap->type != 1)) {
7483     sap = sap->next;
7484   }
7485   if (sap == NULL) {
7486     sap = SeqAnnotNew ();
7487     if (sap != NULL) {
7488       sap->type = 1;
7489       sap->next = bsp->annot;
7490       bsp->annot = sap;
7491     }
7492   }
7493   sap = bsp->annot;
7494   if (sap != NULL) {
7495     if (sap->data != NULL) {
7496       prev = sap->data;
7497       while (prev->next != NULL) {
7498         prev = prev->next;
7499       }
7500       prev->next = sfp;
7501     } else {
7502       sap->data = (Pointer) sfp;
7503     }
7504   }
7505 }
7506 
7507 static void PackageFeatureCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
7508 
7509 {
7510   BaseFormPtr    bfp;
7511   BioseqPtr      bsp = NULL;
7512   BioseqSetPtr   bssp = NULL;
7513   SeqAnnotPtr    nextsap;
7514   SeqFeatPtr     nextsfp;
7515   Pointer PNTR   prevsap;
7516   Pointer PNTR   prevsfp;
7517   SeqAnnotPtr    sap;
7518   SeqFeatPtr     sfp;
7519   BioseqPtr      target;
7520 
7521   if (sep == NULL || sep->data.ptrvalue == NULL) return;
7522   bfp = (BaseFormPtr) mydata;
7523   if (bfp == NULL) return;
7524   if (IS_Bioseq (sep)) {
7525     bsp = (BioseqPtr) sep->data.ptrvalue;
7526     sap = bsp->annot;
7527     prevsap = (Pointer PNTR) &(bsp->annot);
7528   } else if (IS_Bioseq_set (sep)) {
7529     bssp = (BioseqSetPtr) sep->data.ptrvalue;
7530     sap = bssp->annot;
7531     prevsap = (Pointer PNTR) &(bssp->annot);
7532   } else return;
7533   while (sap != NULL) {
7534     nextsap = sap->next;
7535     if (sap->type == 1) {
7536       sfp = (SeqFeatPtr) sap->data;
7537       prevsfp = (Pointer PNTR) &(sap->data);
7538       while (sfp != NULL) {
7539         nextsfp = sfp->next;
7540         target = GetBioseqGivenSeqLoc (sfp->location, bfp->input_entityID);
7541         if (target != bsp) {
7542           *(prevsfp) = sfp->next;
7543           sfp->next = NULL;
7544           AddFeatureToBioseq (sfp, target);
7545         } else {
7546           prevsfp = (Pointer PNTR) &(sfp->next);
7547         }
7548         sfp = nextsfp;
7549       }
7550     }
7551     if (sap->data == NULL) {
7552       *(prevsap) = sap->next;
7553       sap->next = NULL;
7554       SeqAnnotFree (sap);
7555     } else {
7556       prevsap = (Pointer PNTR) &(sap->next);
7557     }
7558     sap = nextsap;
7559   }
7560 }
7561 
7562 static void PackageOnParts (IteM i)
7563 
7564 {
7565   BaseFormPtr  bfp;
7566   SeqEntryPtr  sep;
7567 
7568 #ifdef WIN_MAC
7569   bfp = currentFormDataPtr;
7570 #else
7571   bfp = GetObjectExtra (i);
7572 #endif
7573   if (bfp == NULL) return;
7574   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
7575   if (sep == NULL) return;
7576   WatchCursor ();
7577   Update ();
7578   SeqEntryExplore (sep, bfp, PackageFeatureCallback);
7579   ArrowCursor ();
7580   Update ();
7581   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
7582   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
7583 }
7584 
7585 static void ForcePackageFeatureCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
7586 
7587 {
7588   BaseFormPtr    bfp;
7589   BioseqPtr      bsp = NULL;
7590   BioseqSetPtr   bssp = NULL;
7591   SeqAnnotPtr    firstsap;
7592   SeqAnnotPtr    nextsap;
7593   SeqFeatPtr     nextsfp;
7594   Pointer PNTR   prevsap;
7595   Pointer PNTR   prevsfp;
7596   SeqAnnotPtr    sap;
7597   SeqFeatPtr     sfp;
7598   BioseqPtr      target;
7599 
7600   if (sep == NULL || sep->data.ptrvalue == NULL) return;
7601   bfp = (BaseFormPtr) mydata;
7602   if (bfp == NULL) return;
7603   if (IS_Bioseq (sep)) {
7604     bsp = (BioseqPtr) sep->data.ptrvalue;
7605     sap = bsp->annot;
7606     prevsap = (Pointer PNTR) &(bsp->annot);
7607   } else if (IS_Bioseq_set (sep)) {
7608     bssp = (BioseqSetPtr) sep->data.ptrvalue;
7609     sap = bssp->annot;
7610     prevsap = (Pointer PNTR) &(bssp->annot);
7611   } else return;
7612   firstsap = sap;
7613   while (sap != NULL) {
7614     nextsap = sap->next;
7615     if (sap->type == 1) {
7616       sfp = (SeqFeatPtr) sap->data;
7617       prevsfp = (Pointer PNTR) &(sap->data);
7618       while (sfp != NULL) {
7619         nextsfp = sfp->next;
7620         target = GetBioseqGivenSeqLoc (sfp->location, bfp->input_entityID);
7621         if (target != bsp || sap != firstsap) {
7622           *(prevsfp) = sfp->next;
7623           sfp->next = NULL;
7624           AddFeatureToBioseq (sfp, target);
7625         } else {
7626           prevsfp = (Pointer PNTR) &(sfp->next);
7627         }
7628         sfp = nextsfp;
7629       }
7630     }
7631     if (sap->data == NULL) {
7632       *(prevsap) = sap->next;
7633       sap->next = NULL;
7634       SeqAnnotFree (sap);
7635     } else {
7636       prevsap = (Pointer PNTR) &(sap->next);
7637     }
7638     sap = nextsap;
7639   }
7640 }
7641 
7642 static void ForceRepackage (IteM i)
7643 
7644 {
7645   BaseFormPtr  bfp;
7646   SeqEntryPtr  sep;
7647 
7648 #ifdef WIN_MAC
7649   bfp = currentFormDataPtr;
7650 #else
7651   bfp = GetObjectExtra (i);
7652 #endif
7653   if (bfp == NULL) return;
7654   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
7655   if (sep == NULL) return;
7656   WatchCursor ();
7657   Update ();
7658   SeqEntryExplore (sep, bfp, ForcePackageFeatureCallback);
7659   ArrowCursor ();
7660   Update ();
7661   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
7662   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
7663 }
7664 
7665 static BioseqSetPtr GetParentNPS (BioseqPtr bsp)
7666 {
7667   BioseqSetPtr  bssp;
7668 
7669   if (bsp == NULL) return NULL;
7670   if (bsp->idx.parenttype != OBJ_BIOSEQSET) return NULL;
7671   bssp = (BioseqSetPtr) bsp->idx.parentptr;
7672   while (bssp != NULL && bssp->_class != BioseqseqSet_class_nuc_prot && bssp->idx.parenttype == OBJ_BIOSEQSET) {
7673     bssp = (BioseqSetPtr) bssp->idx.parentptr;
7674   }
7675   if (bssp->_class == BioseqseqSet_class_nuc_prot) return bssp;
7676   return NULL;
7677 }
7678 
7679 static Boolean NucAndProtNotInSameNPS (BioseqPtr nuc, BioseqPtr prt)
7680 {
7681   BioseqSetPtr    bssp;
7682 
7683   if (nuc == NULL || prt == NULL) return FALSE;
7684   bssp = GetParentNPS (nuc);
7685   if (bssp == NULL) return TRUE;
7686   if (GetParentNPS (prt) != bssp) return TRUE;
7687   return FALSE;
7688 }
7689 
7690 typedef struct nppack {
7691   BioseqPtr  nuc;
7692   BioseqPtr  prt;
7693 } NpPack, PNTR NpPackPtr;
7694 
7695 static void PackageProteinsCallback (SeqFeatPtr sfp, Pointer userdata)
7696 
7697 {
7698   BioseqSetPtr       bssp;
7699   SeqMgrDescContext  context;
7700   ValNodePtr PNTR    headp;
7701   MolInfoPtr         mip;
7702   NpPackPtr          npp;
7703   BioseqPtr          nuc, prt;
7704   SeqDescrPtr        sdp;
7705 
7706   if (sfp == NULL || sfp->data.choice != SEQFEAT_CDREGION || sfp->product == NULL) return;
7707   nuc = BioseqFindFromSeqLoc (sfp->location);
7708   prt = BioseqFindFromSeqLoc (sfp->product);
7709   if (nuc == NULL || prt == NULL) return;
7710 
7711   headp = (ValNodePtr PNTR) userdata;
7712 
7713   /* if CDS location is on genomic nucleotide in genomic product set, bail */
7714 
7715   if (nuc->idx.parenttype == OBJ_BIOSEQSET) {
7716     bssp = (BioseqSetPtr) nuc->idx.parentptr;
7717     if (bssp != NULL && bssp->_class == BioseqseqSet_class_gen_prod_set) {
7718       sdp = SeqMgrGetNextDescriptor (nuc, NULL, Seq_descr_molinfo, &context);
7719       if (sdp != NULL) {
7720         mip = (MolInfoPtr) sdp->data.ptrvalue;
7721         if (mip != NULL) {
7722           if (mip->biomol != MOLECULE_TYPE_MRNA) return;
7723         }
7724       }
7725     }
7726   }
7727 
7728   if (NucAndProtNotInSameNPS (nuc, prt)) {
7729     npp = (NpPackPtr) MemNew (sizeof (NpPack));
7730     if (npp == NULL) return;
7731     npp->nuc = nuc;
7732     npp->prt = (BioseqPtr) AsnIoMemCopy ((Pointer) prt,
7733                                          (AsnReadFunc) BioseqAsnRead,
7734                                          (AsnWriteFunc) BioseqAsnWrite);
7735     ValNodeAddPointer (headp, 0, (Pointer) npp);
7736     prt->idx.deleteme = TRUE;
7737   }
7738 }
7739 
7740 static void PackageOnNucs (IteM i)
7741 
7742 {
7743   BaseFormPtr    bfp;
7744   ValNodePtr     descr;
7745   ValNodePtr     head = NULL, vnp;
7746   NpPackPtr      npp;
7747   BioseqSetPtr   nps;
7748   SeqEntryPtr    nsep, psep;
7749   BioseqPtr      nuc, prt;
7750   SeqEntryPtr    sep;
7751 
7752 #ifdef WIN_MAC
7753   bfp = currentFormDataPtr;
7754 #else
7755   bfp = GetObjectExtra (i);
7756 #endif
7757   if (bfp == NULL) return;
7758   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
7759   if (sep == NULL) return;
7760   WatchCursor ();
7761   Update ();
7762 
7763   VisitFeaturesInSep (sep, &head, PackageProteinsCallback);
7764 
7765   DeleteMarkedObjects (bfp->input_entityID, 0, NULL);
7766   SeqMgrClearFeatureIndexes (bfp->input_entityID, NULL);
7767 
7768   for (vnp = head; vnp != NULL; vnp = vnp->next) {
7769     npp = (NpPackPtr) vnp->data.ptrvalue;
7770     if (npp == NULL) continue;
7771     nuc = npp->nuc;
7772     prt = npp->prt;
7773     if (nuc == NULL || prt == NULL) continue;
7774     nsep = nuc->seqentry;
7775     nps = GetParentNPS (nuc);
7776     if (nps != NULL) {
7777       nsep = nps->seqentry;
7778     }
7779     psep = SeqEntryNew ();
7780     if (nsep == NULL || psep == NULL) continue;
7781     psep->choice = 1;
7782     psep->data.ptrvalue = (Pointer) prt;
7783     SeqMgrSeqEntry (SM_BIOSEQ, (Pointer) prt, psep);
7784     descr = ExtractBioSourceAndPubs (nsep);
7785     AddSeqEntryToSeqEntry (nsep, psep, TRUE);
7786     ReplaceBioSourceAndPubs (nsep, descr);
7787     AssignIDsInEntity (bfp->input_entityID, 0, NULL);
7788   }
7789   ValNodeFreeData (head);
7790 
7791   ArrowCursor ();
7792   Update ();
7793   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
7794   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
7795 }
7796 
7797 extern EnumFieldAssoc  enum_bond_alist [];
7798 extern EnumFieldAssoc  enum_site_alist [];
7799 
7800 static Boolean            alistBoxUp;
7801 static Boolean            alistBoxAccept;
7802 static PopuP              alistBoxPopup;
7803 
7804 static void AcceptAlistMessage (ButtoN b)
7805 
7806 {
7807   alistBoxAccept = TRUE;
7808   alistBoxUp = FALSE;
7809 }
7810 
7811 static void CancelAlistMessage (ButtoN b)
7812 
7813 {
7814   alistBoxAccept = FALSE;
7815   alistBoxUp = FALSE;
7816 }
7817 
7818 extern Boolean AlistMessage (EnumFieldAssocPtr al, UIEnumPtr val, UIEnum dflt, CharPtr mssg)
7819 
7820 {
7821   GrouP   c;
7822   GrouP   g;
7823   PrompT  ppt;
7824   WindoW  w;
7825 
7826   if (al == NULL || val == NULL) return FALSE;
7827   alistBoxUp = TRUE;
7828   alistBoxAccept = FALSE;
7829   w = ModalWindow (-50, -20, -20, -20, NULL);
7830   if (w != NULL) {
7831     g = HiddenGroup (w, -1, 0, NULL);
7832     SetGroupSpacing (g, 10, 10);
7833     ppt = StaticPrompt (g, mssg, 0, 0, programFont, 'c');
7834     alistBoxPopup = PopupList (g, TRUE, NULL);
7835     InitEnumPopup (alistBoxPopup, al, NULL);
7836     SetEnumPopup (alistBoxPopup, al, dflt);
7837     c = HiddenGroup (g, 2, 0, NULL);
7838     DefaultButton (c, "Accept", AcceptAlistMessage);
7839     PushButton (c, "Cancel", CancelAlistMessage);
7840     AlignObjects (ALIGN_CENTER, (HANDLE) ppt, (HANDLE) alistBoxPopup, (HANDLE) c, NULL);
7841     RealizeWindow (w);
7842     Show (w);
7843     Select (w);
7844     while (alistBoxUp) {
7845       ProcessExternalEvent ();
7846       Update ();
7847     }
7848     ProcessAnEvent ();
7849     if (! GetEnumPopup (alistBoxPopup, al, val)) {
7850       alistBoxAccept = FALSE;
7851     }
7852     Remove (w);
7853   }
7854   return alistBoxAccept;
7855 } 
7856 
7857 static void DefaultMessageProc (ForM f, Int2 mssg)
7858 
7859 {
7860   StdEditorProcsPtr  sepp;
7861 
7862   sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
7863   if (sepp != NULL) {
7864     if (sepp->handleMessages != NULL) {
7865       sepp->handleMessages (f, mssg);
7866     }
7867   }
7868 }
7869 
7870 typedef struct multtransformdata {
7871   FEATURE_FORM_BLOCK
7872 
7873   Uint1          type;
7874   LisT           fromfeatlist;
7875   PopuP          siteorbondlist;
7876   Uint1          feattype;
7877   Int4           siteorbondtype;
7878 } MultTransFormData, PNTR MultTransFormPtr;
7879 
7880 static void ProcessMultiTrans (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
7881 
7882 {
7883   BioseqPtr         bsp;
7884   BioseqSetPtr      bssp;
7885   SeqFeatPtr        cds;
7886   MultTransFormPtr  mfp;
7887   SeqFeatPtr        newsfp;
7888   BioseqPtr         pbsp;
7889   SeqEntryPtr       psep;
7890   SeqAnnotPtr       sap;
7891   SeqBondPtr        sbp;
7892   SeqFeatPtr        sfp;
7893   SeqIdPtr          sip;
7894   SeqLocPtr         slp;
7895   SeqPntPtr         spp;
7896   Uint1             subtype;
7897 
7898   mfp = (MultTransFormPtr) mydata;
7899   if (sep == NULL || mfp == NULL) return;
7900   if (IS_Bioseq (sep)) {
7901     bsp = (BioseqPtr) sep->data.ptrvalue;
7902     sap = bsp->annot;
7903   } else if (IS_Bioseq_set (sep)) {
7904     bssp = (BioseqSetPtr) sep->data.ptrvalue;
7905     sap = bssp->annot;
7906   } else return;
7907   while (sap != NULL) {
7908     if (sap->type == 1) {
7909       sfp = (SeqFeatPtr) sap->data;
7910       while (sfp != NULL) {
7911         subtype = FindFeatDefType (sfp);
7912         if (subtype == mfp->feattype) {
7913           cds = SeqMgrGetOverlappingCDS (sfp->location, NULL);
7914           if (cds != NULL) {
7915             slp = dnaLoc_to_aaLoc (cds, sfp->location, TRUE, NULL, FALSE);
7916             if (slp != NULL) {
7917               pbsp = BioseqFindFromSeqLoc (slp);
7918               if (pbsp != NULL) {
7919                 psep = SeqMgrGetSeqEntryForData (pbsp);
7920                 if (psep != NULL) {
7921                   newsfp = SeqFeatNew ();
7922                   if (newsfp != NULL) {
7923                     newsfp->data.choice = mfp->type;
7924                     if (mfp->type == SEQFEAT_BOND || mfp->type == SEQFEAT_SITE) {
7925                       newsfp->data.value.intvalue = (Int4) mfp->siteorbondtype;
7926                     } else if (mfp->type == SEQFEAT_REGION) {
7927                       newsfp->data.value.ptrvalue = sfp->comment;
7928                       sfp->comment = NULL;
7929                     }
7930                     CreateNewFeature (psep, NULL, mfp->type, newsfp);
7931                     newsfp->location = slp;
7932                     newsfp->comment = sfp->comment;
7933                     sfp->comment = NULL;
7934                     SeqFeatDataFree (&sfp->data);            /* free duplicate feature data */
7935                     sfp->data.choice = SEQFEAT_GENE;         /* fake as empty gene, to be removed */
7936                     sfp->data.value.ptrvalue = GeneRefNew ();
7937                     if (mfp->type == SEQFEAT_BOND) {
7938                       if (slp->choice != SEQLOC_BOND) {
7939                         sip = SeqLocId (slp);
7940                         if (sip != NULL) {
7941                           sbp = SeqBondNew ();
7942                           if (sbp != NULL) {
7943                             slp = ValNodeNew (NULL);
7944                             if (slp != NULL) {
7945                               slp->choice = SEQLOC_BOND;
7946                               slp->data.ptrvalue = (Pointer) sbp;
7947                               spp = SeqPntNew ();
7948                               if (spp != NULL) {
7949                                 spp->strand = SeqLocStrand (newsfp->location);
7950                                 spp->id = SeqIdStripLocus (SeqIdDup (SeqIdFindBest (sip, 0)));
7951                                 spp->point = SeqLocStart (newsfp->location);
7952                                 sbp->a = spp;
7953                               }
7954                               spp = SeqPntNew ();
7955                               if (spp != NULL) {
7956                                 spp->strand = SeqLocStrand (newsfp->location);
7957                                 spp->id = SeqIdStripLocus (SeqIdDup (SeqIdFindBest (sip, 0)));
7958                                 spp->point = SeqLocStop (newsfp->location);
7959                                 sbp->b = spp;
7960                               }
7961                               newsfp->location = SeqLocFree (newsfp->location);
7962                               newsfp->location = slp;
7963                             }
7964                           }
7965                         }
7966                       }
7967                     }
7968                   }
7969                 }
7970               }
7971             }
7972           }
7973         }
7974         sfp = sfp->next;
7975       }
7976     }
7977     sap = sap->next;
7978   }
7979 }
7980 
7981 static void DoMultiTransform (ButtoN b)
7982 
7983 {
7984   UIEnum            enumval;
7985   Int2              feattype;
7986   MultTransFormPtr  mfp;
7987   SeqEntryPtr       sep;
7988   Int2              siteorbondtype = 0;
7989   UIEnumPtr         uptr;
7990 
7991   mfp = (MultTransFormPtr) GetObjectExtra (b);
7992   if (mfp == NULL) return;
7993   sep = GetTopSeqEntryForEntityID (mfp->input_entityID);
7994   if (sep == NULL) return;
7995   Hide (mfp->form);
7996   WatchCursor ();
7997   Update ();
7998   uptr = (UIEnumPtr) DialogToPointer ((DialoG) mfp->fromfeatlist);
7999   if (uptr != NULL) {
8000     enumval = *uptr;
8001     feattype = (Int2) enumval;
8002     uptr = (UIEnumPtr) DialogToPointer ((DialoG) mfp->siteorbondlist);
8003     if (uptr != NULL) {
8004       enumval = *uptr;
8005       siteorbondtype = (Int2) enumval;
8006     }
8007     if (feattype > 0) {
8008       mfp->feattype = (Uint1) feattype;
8009       mfp->siteorbondtype = (Int4) siteorbondtype;
8010       if (siteorbondtype > 0 || mfp->type == SEQFEAT_REGION) {
8011         SeqEntryExplore (sep, (Pointer) mfp, ProcessMultiTrans);
8012       }
8013     }
8014   }
8015   ArrowCursor ();
8016   Update ();
8017   SeqEntryExplore (sep, NULL, CleanupEmptyFeatCallback);
8018   SeqEntryExplore (sep, NULL, MergeAdjacentAnnotsCallback);
8019   ObjMgrSetDirtyFlag (mfp->input_entityID, TRUE);
8020   ObjMgrSendMsg (OM_MSG_UPDATE, mfp->input_entityID, 0, 0);
8021   Remove (mfp->form);
8022 }
8023 
8024 static void MultiTransformProc (IteM i, Uint1 targettype)
8025 
8026 {
8027   EnumFieldAssocPtr  ap;
8028   ButtoN             b;
8029   BaseFormPtr        bfp;
8030   GrouP              c;
8031   GrouP              g;
8032   GrouP              h;
8033   GrouP              k;
8034   Int2               listHeight;
8035   MultTransFormPtr   mfp;
8036   EnumFieldAssocPtr  realalist;
8037   SeqEntryPtr        sep;
8038   StdEditorProcsPtr  sepp;
8039   CharPtr            title = "?";
8040   WindoW             w;
8041 
8042 #ifdef WIN_MAC
8043   bfp = currentFormDataPtr;
8044 #else
8045   bfp = GetObjectExtra (i);
8046 #endif
8047   if (bfp == NULL) return;
8048   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
8049   if (sep == NULL) return;
8050   mfp = (MultTransFormPtr) MemNew (sizeof (MultTransFormData));
8051   if (mfp == NULL) return;
8052 
8053   if (targettype == SEQFEAT_BOND) {
8054     title = "Transform to Bond";
8055   } else if (targettype == SEQFEAT_SITE) {
8056     title = "Transform to Site";
8057   } else if (targettype == SEQFEAT_REGION) {
8058     title = "Transform to Region";
8059   }
8060 
8061   w = FixedWindow (-50, -33, -10, -10, title, StdCloseWindowProc);
8062   SetObjectExtra (w, mfp, StdCleanupFormProc);
8063   mfp->form = (ForM) w;
8064   mfp->formmessage = DefaultMessageProc;
8065 
8066   sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
8067   if (sepp != NULL) {
8068     SetActivate (w, sepp->activateForm);
8069     mfp->appmessage = sepp->handleMessages;
8070   }
8071 
8072   mfp->type = targettype;
8073 
8074   mfp->input_entityID = bfp->input_entityID;
8075   mfp->input_itemID = bfp->input_itemID;
8076   mfp->input_itemtype = bfp->input_itemtype;
8077 
8078   h = HiddenGroup (w, -1, 0, NULL);
8079   SetGroupSpacing (h, 10, 10);
8080 
8081   g = HiddenGroup (h, 0, 2, NULL);
8082 
8083   ap = import_featdef_alist (TRUE, FALSE, TRUE);
8084   realalist = ap;
8085   ap++;
8086   StaticPrompt (g, "From Feature", 0, 0, programFont, 'c');
8087   if (indexerVersion) {
8088     listHeight = 16;
8089   } else {
8090     listHeight = 8;
8091   }
8092   mfp->fromfeatlist = CreateEnumListDialog (g, 10, listHeight, NULL, ap, 0, NULL);
8093   FreeEnumFieldAlist (realalist);
8094 
8095   k = NULL;
8096   if (targettype != SEQFEAT_REGION) {
8097     k = HiddenGroup (h, 0, 2, NULL);
8098 
8099     if (targettype == SEQFEAT_BOND) {
8100       StaticPrompt (k, "Select type of bond", 0, 0, programFont, 'c');
8101       mfp->siteorbondlist = CreateEnumPopupDialog (k, TRUE, NULL, enum_bond_alist, 0, NULL);
8102     } else if (targettype == SEQFEAT_SITE) {
8103       StaticPrompt (k, "Select type of site", 0, 0, programFont, 'c');
8104       mfp->siteorbondlist = CreateEnumPopupDialog (k, TRUE, NULL, enum_site_alist, 0, NULL);
8105     }
8106   }
8107 
8108   c = HiddenGroup (h, 4, 0, NULL);
8109   b = DefaultButton (c, "Accept", DoMultiTransform);
8110   SetObjectExtra (b, mfp, NULL);
8111   PushButton (c, "Cancel", StdCancelButtonProc);
8112 
8113   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, (HANDLE) k, NULL);
8114   RealizeWindow (w);
8115   Show (w);
8116   Update ();
8117 }
8118 
8119 static Boolean UnlinkPubDesc (GatherContextPtr gcp)
8120 
8121 {
8122   ValNodePtr       sdp;
8123   ValNodePtr PNTR  vnpp;
8124 
8125   if (gcp->thistype != OBJ_SEQDESC) return TRUE;
8126   sdp = (ValNodePtr) gcp->thisitem;
8127   if (sdp == NULL || sdp->choice != Seq_descr_pub) return TRUE;
8128   vnpp = (ValNodePtr PNTR) gcp->userdata;
8129   if (vnpp == NULL) return TRUE;
8130   *(gcp->prevlink) = sdp->next;
8131   sdp->next = NULL;
8132   *vnpp = sdp;
8133   return TRUE;
8134 }
8135 
8136 static void AddConvertedDescFeat (SeqEntryPtr sep, ValNodePtr vnp)
8137 {
8138   BioseqSetPtr  bssp;
8139   BioseqPtr     bsp;
8140   SeqFeatPtr    sfp;
8141 
8142   if (sep == NULL || vnp == NULL) return;
8143   if (IS_Bioseq_set (sep)) {
8144     bssp = (BioseqSetPtr) sep->data.ptrvalue;
8145         for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
8146       AddConvertedDescFeat (sep, vnp);
8147         }
8148   } else {
8149     bsp = (BioseqPtr) sep->data.ptrvalue;
8150     if (ISA_aa (bsp->mol)) return;
8151     sfp = CreateNewFeature (sep, NULL, SEQFEAT_PUB, NULL);
8152     if (sfp != NULL) {
8153       sfp->data.value.ptrvalue = AsnIoMemCopy ((Pointer) vnp->data.ptrvalue,
8154                                                (AsnReadFunc) PubdescAsnRead,
8155                                                (AsnWriteFunc) PubdescAsnWrite);
8156     }
8157   }
8158 }
8159 
8160 static void CommonConvertDescToFeat (BaseFormPtr bfp, Boolean pub, Boolean src, Boolean com, CharPtr findstring)
8161 
8162 {
8163   SeqEntryPtr   sep;
8164   SelStructPtr  sel;
8165   ValNodePtr    vnp;
8166   Boolean       asked_about_prop = FALSE;
8167   Boolean       propagate_descriptors = FALSE;
8168 
8169   if (bfp == NULL) return;
8170   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
8171   if (sep == NULL) return;
8172   sel = ObjMgrGetSelected ();
8173   if (pub && sel != NULL) {
8174     if (sel->entityID == bfp->input_entityID &&
8175         sel->next == NULL && sel->itemtype == OBJ_SEQDESC) {
8176       vnp = NULL;
8177       sep = GetBestTopParentForItemID (sel->entityID, sel->itemID, sel->itemtype);
8178       if (sep != NULL) {
8179         /* unlink changes itemID, so sep must be determined first */
8180         GatherItem (sel->entityID, sel->itemID, sel->itemtype, (Pointer) &vnp, UnlinkPubDesc);
8181         if (vnp != NULL) {
8182           AddConvertedDescFeat (sep, vnp);
8183           ValNodeFree (vnp);
8184         }
8185       }
8186     }
8187     ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
8188     ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
8189     return;
8190   }
8191   if (ConvertPubSrcComDescsToFeats (sep, pub, src, com, FALSE, &asked_about_prop, &propagate_descriptors, findstring)) {
8192     ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
8193     ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
8194   }
8195 }
8196 
8197 
8198 static void CommonConvertDescToFeatMenuItem (IteM i, Boolean pub, Boolean src, Boolean com)
8199 {
8200   BaseFormPtr   bfp;
8201 
8202 #ifdef WIN_MAC
8203   bfp = currentFormDataPtr;
8204 #else
8205   bfp = GetObjectExtra (i);
8206 #endif
8207   if (bfp == NULL) return;
8208   CommonConvertDescToFeat (bfp, pub, src, com, NULL);
8209 }
8210 
8211 static void ConvertPubDescToFeat (IteM i)
8212 
8213 {
8214   CommonConvertDescToFeatMenuItem (i, TRUE, FALSE, FALSE);
8215 }
8216 
8217 static void ConvertSrcDescToFeat (IteM i)
8218 
8219 {
8220   CommonConvertDescToFeatMenuItem (i, FALSE, TRUE, FALSE);
8221 }
8222 
8223 static void ConvertComDescToFeat (IteM i)
8224 
8225 {
8226   CommonConvertDescToFeatMenuItem (i, FALSE, FALSE, TRUE);
8227 }
8228 
8229 typedef struct convertpubdescdata {
8230   DESCRIPTOR_FORM_BLOCK
8231   BaseFormPtr bfp;
8232   TexT    findthis;
8233   Char    findString [255];
8234 } ConvertPubDescData, PNTR ConvertPubDescPtr;
8235 
8236 
8237 static void DoConvertPubDescStringConstraint (ButtoN b)
8238 {
8239   ConvertPubDescPtr cpdp;
8240 
8241   cpdp = (ConvertPubDescPtr) GetObjectExtra (b);
8242   if (cpdp == NULL) return;
8243   Hide (cpdp->form);
8244 
8245   GetTitle (cpdp->findthis, cpdp->findString, sizeof (cpdp->findString) - 1);
8246   if (StringHasNoText (cpdp->findString)) {
8247     CommonConvertDescToFeat (cpdp->bfp, TRUE, FALSE, FALSE, NULL);
8248   } else {
8249         CommonConvertDescToFeat (cpdp->bfp, TRUE, FALSE, FALSE, cpdp->findString);
8250   }
8251 
8252   ObjMgrSetDirtyFlag (cpdp->input_entityID, TRUE);
8253   ObjMgrSendMsg (OM_MSG_UPDATE, cpdp->input_entityID, 0, 0);
8254   Remove (cpdp->form);
8255 }
8256 
8257 static void CreateConvertPubDescStringConstraintDialogX (IteM i)
8258 {
8259   BaseFormPtr       bfp;
8260   ConvertPubDescPtr cpdp;
8261   WindoW            w;
8262   GrouP             h, g, c;
8263   ButtoN            b;
8264 
8265 #ifdef WIN_MAC
8266   bfp = currentFormDataPtr;
8267 #else
8268   bfp = GetObjectExtra (i);
8269 #endif
8270   if (bfp == NULL) return;
8271 
8272   cpdp = (ConvertPubDescPtr) MemNew (sizeof (ConvertPubDescData));
8273   if (cpdp == NULL) return;
8274   cpdp->bfp = bfp;
8275 
8276   w = FixedWindow (-50, -33, -10, -10, "Convert Pub Descriptors", StdCloseWindowProc);
8277   SetObjectExtra (w, cpdp, StdCleanupFormProc);
8278   cpdp->form = (ForM) w;
8279   cpdp->formmessage = NULL;
8280 
8281   cpdp->input_entityID = bfp->input_entityID;
8282 
8283   h = HiddenGroup (w, 0, 2, NULL);
8284   g = HiddenGroup (h, 2, 0, NULL);
8285   StaticPrompt (g, "Optional string constraint", 0, dialogTextHeight, programFont, 'c');
8286   cpdp->findthis = DialogText (g, "", 14, NULL);
8287 
8288   c = HiddenGroup (h, 2, 0, NULL);
8289   b = DefaultButton (c, "Accept", DoConvertPubDescStringConstraint);
8290   SetObjectExtra (b, cpdp, NULL);
8291   PushButton (c, "Cancel", StdCancelButtonProc);
8292 
8293   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL);
8294   RealizeWindow (w);
8295   Show (w);
8296   Update ();
8297 }
8298 
8299 
8300 typedef struct feattodesc {
8301   Boolean pub;
8302   Boolean src;
8303   Boolean com;
8304 } FeatToDescData, PNTR FeatToDescPtr;
8305 
8306 static void ConvertOneFeatToDesc (SeqFeatPtr sfp, Pointer userdata)
8307 {
8308   SeqDescPtr sdp;
8309   SeqEntryPtr sep;
8310   SeqIdPtr    sip;
8311   BioseqPtr   bsp;
8312   ValNode     vn;
8313   FeatToDescPtr fdp;
8314   BioSourcePtr  biop;
8315   SubSourcePtr  ssp, last_ssp = NULL;
8316   CharPtr       new_note;
8317   
8318   if (sfp == NULL || (fdp = (FeatToDescPtr) userdata) == NULL
8319       || (sfp->data.choice == SEQFEAT_PUB && !fdp->pub)
8320       || (sfp->data.choice == SEQFEAT_BIOSRC && !fdp->src)
8321       || (sfp->data.choice == SEQFEAT_COMMENT && !fdp->com)
8322       || (sfp->data.choice != SEQFEAT_PUB
8323           && sfp->data.choice != SEQFEAT_BIOSRC
8324           && sfp->data.choice != SEQFEAT_COMMENT)) {
8325     return;
8326   }
8327 
8328   /* perform only if feature is full-length */  
8329   sip = SeqLocId (sfp->location);
8330   bsp = BioseqFind (sip);
8331   if (bsp == NULL) return;
8332   sip = SeqIdFindBest(bsp->id, 0);
8333   if (sip == NULL) return;
8334   vn.choice = SEQLOC_WHOLE;
8335   vn.extended = 0;
8336   vn.data.ptrvalue = (Pointer) sip;
8337   vn.next = NULL;
8338   /* is feature full length? */
8339   if (SeqLocCompare (sfp->location, &vn) != SLC_A_EQ_B) return;
8340   
8341   sep = GetBestTopParentForItemID (sfp->idx.entityID, sfp->idx.itemID, OBJ_SEQFEAT);
8342   if (sep == NULL) return;
8343   
8344   if (sfp->data.choice == SEQFEAT_PUB) {
8345     sdp = CreateNewDescriptor (sep, Seq_descr_pub);
8346     sdp->data.ptrvalue = AsnIoMemCopy ((Pointer) sfp->data.value.ptrvalue,
8347                                        (AsnReadFunc) PubdescAsnRead,
8348                                        (AsnWriteFunc) PubdescAsnWrite);
8349   } else if (sfp->data.choice == SEQFEAT_BIOSRC) {
8350     sdp = CreateNewDescriptor (sep, Seq_descr_source);
8351     sdp->data.ptrvalue = AsnIoMemCopy ((Pointer) sfp->data.value.ptrvalue,
8352                                        (AsnReadFunc) BioSourceAsnRead,
8353                                        (AsnWriteFunc) BioSourceAsnWrite);
8354     if (!StringHasNoText (sfp->comment)) {
8355       biop = (BioSourcePtr) sdp->data.ptrvalue;
8356       ssp = biop->subtype;
8357       while (ssp != NULL && ssp->subtype != 255) {
8358         last_ssp = ssp;
8359         ssp = ssp->next;
8360       }
8361       if (ssp == NULL) {
8362         ssp = SubSourceNew ();
8363         ssp->subtype = 255;
8364         ssp->name = StringSave (sfp->comment);
8365         if (last_ssp == NULL) {
8366           biop->subtype = ssp;
8367         } else {
8368           last_ssp->next = ssp;
8369         }
8370       } else if (StringHasNoText (ssp->name)) {
8371         ssp->name = MemFree (ssp->name);
8372         ssp->name = StringSave (sfp->comment);
8373       } else {
8374         new_note = (CharPtr) MemNew (sizeof(Char) * (StringLen (ssp->name) + StringLen (sfp->comment) + 2));
8375         sprintf (new_note, "%s;%s", ssp->name, sfp->comment);
8376         ssp->name = MemFree (ssp->name);
8377         ssp->name = new_note;
8378       }
8379     }
8380   } else if (sfp->data.choice == SEQFEAT_COMMENT) {
8381     sdp = CreateNewDescriptor (sep, Seq_descr_comment);
8382     sdp->data.ptrvalue = StringSave (sfp->comment);
8383   }
8384   
8385   sfp->idx.deleteme = TRUE;  
8386 }
8387 
8388 
8389 static void CommonConvertFeatToDesc (IteM i, Boolean pub, Boolean src, Boolean com)
8390 
8391 {
8392   SeqEntryPtr   sep;
8393   SelStructPtr  sel;
8394   SeqFeatPtr    sfp;
8395   FeatToDescData fdd;
8396   BaseFormPtr   bfp;
8397   SeqMgrFeatContext fcontext;
8398 
8399 #ifdef WIN_MAC
8400   bfp = currentFormDataPtr;
8401 #else
8402   bfp = GetObjectExtra (i);
8403 #endif
8404   if (bfp == NULL) return;
8405   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
8406   if (sep == NULL) return;
8407   
8408   fdd.pub = pub;
8409   fdd.src = src;
8410   fdd.com = com;
8411   
8412   sel = ObjMgrGetSelected ();  
8413   if (sel != NULL) {
8414     while (sel != NULL) {    
8415       if (sel->entityID == bfp->input_entityID && sel->itemtype == OBJ_SEQFEAT) {
8416         sfp = SeqMgrGetDesiredFeature (bfp->input_entityID, NULL, sel->itemID, 0, NULL, &fcontext);
8417         ConvertOneFeatToDesc (sfp, &fdd);
8418       }
8419       sel = sel->next;
8420     }
8421   } else {
8422     VisitFeaturesInSep (sep, &fdd, ConvertOneFeatToDesc);
8423   }
8424   DeleteMarkedObjects (bfp->input_entityID, 0, NULL);
8425   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
8426   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
8427 }
8428 
8429 
8430 static void ConvertPubFeatToDesc (IteM i)
8431 {
8432   CommonConvertFeatToDesc (i, TRUE, FALSE, FALSE);
8433 }
8434 
8435 
8436 static void ConvertSrcFeatToDesc (IteM i)
8437 {
8438   CommonConvertFeatToDesc (i, FALSE, TRUE, FALSE);
8439 }
8440 
8441 
8442 static void ConvertCommentFeatToDesc (IteM i)
8443 {
8444   CommonConvertFeatToDesc (i, FALSE, FALSE, TRUE);
8445 }
8446 
8447 
8448 
8449 static void MoveSecondProtName (SeqFeatPtr sfp, Pointer userdata)
8450 
8451 {
8452   ValNodePtr  nxt;
8453   ProtRefPtr  prp;
8454   ValNodePtr  vnp;
8455  
8456   if (sfp == NULL || sfp->data.choice != SEQFEAT_PROT) return;
8457   prp = (ProtRefPtr) sfp->data.value.ptrvalue;
8458   if (prp == NULL || prp->desc != NULL) return;
8459   vnp = prp->name;
8460   if (vnp == NULL) return;
8461   nxt = vnp->next;
8462   if (nxt == NULL || nxt->next != NULL) return;
8463   vnp->next = NULL;
8464   prp->desc = nxt->data.ptrvalue;
8465   nxt->data.ptrvalue = NULL;
8466   ValNodeFree (nxt);
8467 }
8468 
8469 static void SecondProtNameToDesc (IteM i)
8470 
8471 {
8472   BaseFormPtr  bfp;
8473   SeqEntryPtr  sep;
8474 
8475 #ifdef WIN_MAC
8476   bfp = currentFormDataPtr;
8477 #else
8478   bfp = GetObjectExtra (i);
8479 #endif
8480   if (bfp == NULL) return;
8481   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
8482   if (sep == NULL) return;
8483   VisitFeaturesInSep (sep, NULL, MoveSecondProtName);
8484   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
8485   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
8486 }
8487 
8488 static void MoveProtDesc (SeqFeatPtr sfp, Pointer userdata)
8489 
8490 {
8491   ProtRefPtr  prp;
8492   CharPtr     str;
8493   ValNodePtr  vnp;
8494  
8495   if (sfp == NULL || sfp->data.choice != SEQFEAT_PROT) return;
8496   prp = (ProtRefPtr) sfp->data.value.ptrvalue;
8497   if (prp == NULL || prp->desc == NULL) return;
8498   vnp = prp->name;
8499   if (vnp == NULL) return;
8500   str = prp->desc;
8501   prp->desc = NULL;
8502   ValNodeAddStr (&(prp->name), 0, str);
8503 }
8504 
8505 static void ProtDescToSecondName (IteM i)
8506 
8507 {
8508   BaseFormPtr  bfp;
8509   SeqEntryPtr  sep;
8510 
8511 #ifdef WIN_MAC
8512   bfp = currentFormDataPtr;
8513 #else
8514   bfp = GetObjectExtra (i);
8515 #endif
8516   if (bfp == NULL) return;
8517   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
8518   if (sep == NULL) return;
8519   VisitFeaturesInSep (sep, NULL, MoveProtDesc);
8520   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
8521   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
8522 }
8523 
8524 typedef struct ecrepdata {
8525   CharPtr  before;
8526   CharPtr  after;
8527 } EcRepData, PNTR EcRepPtr;
8528 
8529 static ValNodePtr     ec_rep_list = NULL;
8530 static EcRepPtr PNTR  ec_rep_data = NULL;
8531 static Int4           ec_rep_len = 0;
8532 
8533 static int LIBCALLBACK SortVnpByEcBefore (VoidPtr ptr1, VoidPtr ptr2)
8534 
8535 {
8536   EcRepPtr    erp1, erp2;
8537   CharPtr     str1, str2;
8538   ValNodePtr  vnp1, vnp2;
8539 
8540   if (ptr1 == NULL || ptr2 == NULL) return 0;
8541   vnp1 = *((ValNodePtr PNTR) ptr1);
8542   vnp2 = *((ValNodePtr PNTR) ptr2);
8543   if (vnp1 == NULL || vnp2 == NULL) return 0;
8544   erp1 = (EcRepPtr) vnp1->data.ptrvalue;
8545   erp2 = (EcRepPtr) vnp2->data.ptrvalue;
8546   if (erp1 == NULL || erp2 == NULL) return 0;
8547   str1 = erp1->before;
8548   str2 = erp2->before;
8549   if (str1 == NULL || str2 == NULL) return 0;
8550   return StringCmp (str1, str2);
8551 }
8552 
8553 static void SetupECReplacementTable (CharPtr file)
8554 
8555 {
8556   EcRepPtr    erp;
8557   FileCache   fc;
8558   FILE        *fp = NULL;
8559   Int4        i;
8560   ValNodePtr  last = NULL;
8561   Char        line [512];
8562   Char        path [PATH_MAX];
8563   CharPtr     ptr;
8564   ErrSev      sev;
8565   CharPtr     str;
8566   ValNodePtr  vnp;
8567 
8568   if (ec_rep_data != NULL) return;
8569 
8570   if (FindPath ("ncbi", "ncbi", "data", path, sizeof (path))) {
8571     FileBuildPath (path, NULL, file);
8572     sev = ErrSetMessageLevel (SEV_ERROR);
8573     fp = FileOpen (path, "r");
8574     ErrSetMessageLevel (sev);
8575     if (fp != NULL) {
8576       FileCacheSetup (&fc, fp);
8577   
8578       str = FileCacheReadLine (&fc, line, sizeof (line), NULL);
8579       while (str != NULL) {
8580         if (StringDoesHaveText (str)) {
8581           ptr = StringChr (str, '\t');
8582           if (ptr != NULL) {
8583             *ptr = '\0';
8584             ptr++;
8585             erp = (EcRepPtr) MemNew (sizeof (EcRepData));
8586             if (erp != NULL) {
8587               erp->before = StringSave (str);
8588               erp->after = StringSave (ptr);
8589               vnp = ValNodeAddPointer (&last, 0, (Pointer) erp);
8590               if (ec_rep_list == NULL) {
8591                 ec_rep_list = vnp;
8592               }
8593               last = vnp;
8594             }
8595           }
8596         }
8597         str = FileCacheReadLine (&fc, line, sizeof (line), NULL);
8598       }
8599 
8600       FileClose (fp);
8601       ec_rep_len = ValNodeLen (ec_rep_list);
8602       if (ec_rep_len > 0) {
8603         ec_rep_list = ValNodeSort (ec_rep_list, SortVnpByEcBefore);
8604         ec_rep_data = (EcRepPtr PNTR) MemNew (sizeof (EcRepPtr) * (ec_rep_len + 1));
8605         if (ec_rep_data != NULL) {
8606           for (vnp = ec_rep_list, i = 0; vnp != NULL; vnp = vnp->next, i++) {
8607             erp = (EcRepPtr) vnp->data.ptrvalue;
8608             ec_rep_data [i] = erp;
8609           }
8610         }
8611       }
8612     }
8613   }
8614 }
8615 
8616 static void UpdateProtEC (SeqFeatPtr sfp, Pointer userdata)
8617 
8618 {
8619   EcRepPtr    erp;
8620   Int4        L, R, mid;
8621   ProtRefPtr  prp;
8622   CharPtr     str;
8623   ValNodePtr  vnp;
8624  
8625   if (sfp == NULL || sfp->data.choice != SEQFEAT_PROT) return;
8626   prp = (ProtRefPtr) sfp->data.value.ptrvalue;
8627   if (prp == NULL || prp->ec == NULL) return;
8628   for (vnp = prp->ec; vnp != NULL; vnp = vnp->next) {
8629     str = (CharPtr) vnp->data.ptrvalue;
8630     if (StringHasNoText (str)) continue;
8631     L = 0;
8632     R = ec_rep_len - 1;
8633     while (L < R) {
8634       mid = (L + R) / 2;
8635       erp = ec_rep_data [(int) mid];
8636       if (erp != NULL && StringCmp (erp->before, str) < 0) {
8637         L = mid + 1;
8638       } else {
8639         R = mid;
8640       }
8641     }
8642     erp = ec_rep_data [(int) R];
8643     if (erp != NULL && StringCmp (erp->before, str) == 0) {
8644       vnp->data.ptrvalue = MemFree (vnp->data.ptrvalue);
8645       vnp->data.ptrvalue = StringSave (erp->after);
8646     }
8647   }
8648 }
8649 
8650 static void UpdateECNumbersBaseForm (BaseFormPtr bfp)
8651 {
8652   SeqEntryPtr  sep;
8653 
8654   if (bfp == NULL) return;
8655   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
8656   if (sep == NULL) return;
8657   SetupECReplacementTable ("ecnum_replaced.txt");
8658   if (ec_rep_data != NULL && ec_rep_len > 0) {
8659     VisitFeaturesInSep (sep, NULL, UpdateProtEC);
8660   }
8661   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
8662   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
8663 }
8664 
8665 static void UpdateECnumbers (IteM i)
8666 
8667 {
8668   BaseFormPtr  bfp;
8669 
8670 #ifdef WIN_MAC
8671   bfp = currentFormDataPtr;
8672 #else
8673   bfp = GetObjectExtra (i);
8674 #endif
8675 
8676   UpdateECNumbersBaseForm (bfp);
8677 }
8678 
8679 
8680 typedef struct icrepdata {
8681   CharPtr  code;
8682   CharPtr  name;
8683 } IcRepData, PNTR IcRepPtr;
8684 
8685 static ValNodePtr     ic_rep_list = NULL;
8686 static IcRepPtr PNTR  ic_rep_data = NULL;
8687 static Int4           ic_rep_len = 0;
8688 
8689 static int LIBCALLBACK SortVnpByInstituteName (VoidPtr ptr1, VoidPtr ptr2)
8690 
8691 {
8692   int         compare;
8693   IcRepPtr    irp1, irp2;
8694   CharPtr     str1, str2;
8695   ValNodePtr  vnp1, vnp2;
8696 
8697   if (ptr1 == NULL || ptr2 == NULL) return 0;
8698   vnp1 = *((ValNodePtr PNTR) ptr1);
8699   vnp2 = *((ValNodePtr PNTR) ptr2);
8700   if (vnp1 == NULL || vnp2 == NULL) return 0;
8701   irp1 = (IcRepPtr) vnp1->data.ptrvalue;
8702   irp2 = (IcRepPtr) vnp2->data.ptrvalue;
8703   if (irp1 == NULL || irp2 == NULL) return 0;
8704   str1 = irp1->name;
8705   str2 = irp2->name;
8706   if (str1 == NULL || str2 == NULL) return 0;
8707   compare = StringCmp (str1, str2);
8708   if (compare > 0) {
8709     return 1;
8710   } else if (compare < 0) {
8711     return -1;
8712   }
8713   str1 = irp1->code;
8714   str2 = irp2->code;
8715   if (str1 == NULL || str2 == NULL) return 0;
8716   compare = StringCmp (str1, str2);
8717   if (compare > 0) {
8718     return 1;
8719   } else if (compare < 0) {
8720     return -1;
8721   }
8722   return 0;
8723 }
8724 
8725 static void SetupInstituteCodeNameTable (void)
8726 
8727 {
8728   FileCache   fc;
8729   CharPtr     file = "institution_codes.txt";
8730   FILE        *fp = NULL;
8731   Int4        i;
8732   IcRepPtr    irp;
8733   ValNodePtr  last = NULL;
8734   Char        line [512];
8735   Char        path [PATH_MAX];
8736   CharPtr     ptr;
8737   ErrSev      sev;
8738   CharPtr     str;
8739   ValNodePtr  vnp;
8740 
8741   if (ic_rep_data != NULL) return;
8742 
8743   if (FindPath ("ncbi", "ncbi", "data", path, sizeof (path))) {
8744     FileBuildPath (path, NULL, file);
8745     sev = ErrSetMessageLevel (SEV_ERROR);
8746     fp = FileOpen (path, "r");
8747     ErrSetMessageLevel (sev);
8748     if (fp != NULL) {
8749       FileCacheSetup (&fc, fp);
8750   
8751       str = FileCacheReadLine (&fc, line, sizeof (line), NULL);
8752       while (str != NULL) {
8753         if (StringDoesHaveText (str)) {
8754           ptr = StringChr (str, '\t');
8755           if (ptr != NULL) {
8756             *ptr = '\0';
8757             ptr++;
8758             ptr = StringChr (ptr, '\t');
8759             if (ptr != NULL) {
8760               *ptr = '\0';
8761               ptr++;
8762               irp = (IcRepPtr) MemNew (sizeof (IcRepData));
8763               if (irp != NULL) {
8764                 TrimSpacesAroundString (str);
8765                 TrimSpacesAroundString (ptr);
8766                 irp->code = StringSave (str);
8767                 irp->name = StringSave (ptr);
8768                 vnp = ValNodeAddPointer (&last, 0, (Pointer) irp);
8769                 if (ic_rep_list == NULL) {
8770                   ic_rep_list = vnp;
8771                 }
8772                 last = vnp;
8773               }
8774             }
8775           }
8776         }
8777         str = FileCacheReadLine (&fc, line, sizeof (line), NULL);
8778       }
8779 
8780       FileClose (fp);
8781       ic_rep_len = ValNodeLen (ic_rep_list);
8782       if (ic_rep_len > 0) {
8783         ic_rep_list = ValNodeSort (ic_rep_list, SortVnpByInstituteName);
8784         ic_rep_data = (IcRepPtr PNTR) MemNew (sizeof (IcRepPtr) * (ic_rep_len + 1));
8785         if (ic_rep_data != NULL) {
8786           for (vnp = ic_rep_list, i = 0; vnp != NULL; vnp = vnp->next, i++) {
8787             irp = (IcRepPtr) vnp->data.ptrvalue;
8788             ic_rep_data [i] = irp;
8789           }
8790         }
8791       }
8792     }
8793   }
8794 }
8795 
8796 static CharPtr CheckForInstitutionFullName (CharPtr name, BoolPtr ambigP)
8797 
8798 {
8799   CharPtr   code = NULL;
8800   IcRepPtr  irp;
8801   Int4      L, R, mid;
8802 
8803   if (ambigP != NULL) {
8804     *ambigP = FALSE;
8805   }
8806   if (StringHasNoText (name)) return NULL;
8807   L = 0;
8808   R = ic_rep_len - 1;
8809   while (L < R) {
8810     mid = (L + R) / 2;
8811     irp = ic_rep_data [(int) mid];
8812     if (irp != NULL && StringCmp (irp->name, name) < 0) {
8813       L = mid + 1;
8814     } else {
8815       R = mid;
8816     }
8817   }
8818   irp = ic_rep_data [(int) R];
8819   if (irp != NULL && StringCmp (irp->name, name) == 0) {
8820     code = irp->code;
8821     /* need to check for uniqueness */
8822     if (R < ic_rep_len - 1) {
8823       irp = ic_rep_data [(int) R + 1];
8824       if (irp != NULL && StringCmp (irp->name, name) == 0) {
8825         if (ambigP != NULL) {
8826           *ambigP = TRUE;
8827         }
8828         return NULL;
8829       }
8830     }
8831   }
8832   return code;
8833 }
8834 
8835 static void ConvertInstitutionName (OrgModPtr mod)
8836 
8837 {
8838