NCBI C Toolkit Cross Reference

C/sequin/sequin9.c


  1 /*   sequin9.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:  sequin9.c
 27 *
 28 * Author:  Jonathan Kans
 29 *
 30 * Version Creation Date:   4/20/99
 31 *
 32 * $Revision: 6.480 $
 33 *
 34 * File Description: 
 35 *
 36 * Modifications:  
 37 * --------------------------------------------------------------------------
 38 * Date     Name        Description of modification
 39 * -------  ----------  -----------------------------------------------------
 40 *
 41 *
 42 * ==========================================================================
 43 */
 44 
 45 #include <subutil.h>
 46 #include <explore.h>
 47 #include <alignmgr.h>
 48 #include <urkptpf.h>
 49 #include <entrez.h>
 50 #include <accentr.h>
 51 #include <urlquery.h>
 52 #include <vecscrn.h>
 53 #include <vecscnapi.h>
 54 #include <qblastapi.h>
 55 #include <edutil.h>
 56 #include <actutils.h>
 57 #include <findrepl.h>
 58 #include <rpsutil.h>
 59 #include "sequin.h"
 60 #include <seqpanel.h>
 61 #include <salpanel.h>
 62 #include <assert.h>
 63 #include <pmfapi.h>
 64 #include <vsm.h>
 65 
 66 /*-------------------*/
 67 /* Defined Constants */
 68 /*-------------------*/
 69 
 70 #define MAX_ID_LEN 41
 71 #define FASTA_READ_OK     0
 72 #define FASTA_READ_ERROR -1
 73 #define FASTA_READ_DONE   1
 74 
 75 #define CONVERTPUBS_NOT_SET 0
 76 #define CONVERTPUBS_YES     1
 77 #define CONVERTPUBS_NO      2
 78 
 79 /* constants for update sequence */
 80 #define UPDATE_CHOICE_NOT_SET        0
 81 #define UPDATE_SEQUENCE_ONLY         1
 82 #define UPDATE_FEATURES_ONLY         2
 83 #define UPDATE_SEQUENCE_AND_FEATURES 3
 84 
 85 #define UPDATE_REPLACE               1
 86 #define UPDATE_EXTEND5               2
 87 #define UPDATE_EXTEND3               3
 88 #define UPDATE_PATCH                 4
 89 
 90 enum update_dup_feat_type
 91 {
 92   UPDATE_FEAT_DUP_NOT_SET = 0,
 93   UPDATE_FEAT_DUP_USE_NEW,
 94   UPDATE_FEAT_DUP_USE_OLD,
 95   UPDATE_FEAT_DUP_USE_BOTH,
 96   UPDATE_FEAT_DUP_MERGE,
 97   UPDATE_FEAT_DUP_REPLACE
 98 };
 99 
100 
101 /*-----------------*/
102 /* Data Structures */
103 /*-----------------*/
104 
105 typedef struct {
106   Char       newId[MAX_ID_LEN];
107   BioseqPtr  matchingBsp;
108 } UpdateData, PNTR UpdateDataPtr;
109 
110 typedef struct upsdata {
111   FORM_MESSAGE_BLOCK
112   ButtoN              accept;
113   ButtoN              acceptAll;
114   CharPtr             aln1;
115   CharPtr             aln2;
116   Int4                aln_length;
117   Int2                charwidth;
118   Int2                convertPubs;
119   VieweR              details;
120   Boolean             diffOrgs;
121   SegmenT             dtpict;
122   FILE                *fp;
123   ValNodePtr          indels;
124   Boolean             isSet;
125   ButtoN              keepProteinIDs;
126   PaneL               letters;
127   Int2                lineheight;
128   Int4                log10_aln_length;
129   Int2                maxchars;
130   ValNodePtr          mismatches;
131   Int4                new3;
132   Int4                new5;
133   Int4                newa;
134   BioseqPtr           newbsp;
135   ButtoN              replace_all;
136   GrouP               nobm;
137   Int4                old3;
138   Int4                old5;
139   Int4                olda;
140   BioseqPtr           oldbsp;
141   VieweR              overview;
142   SegmenT             ovpict;
143   Int4                recomb1;
144   Int4                recomb2;
145   Boolean             revcomp;
146   GrouP               rmc;
147   SeqAlignPtr         salp;
148   Int4                scaleX;
149   CharPtr             seq1;
150   CharPtr             seq2;
151   GrouP               sfb;
152   Int4                startmax;
153   Int4                stopmax;
154   Uint1               strandnew;
155   Uint1               strandold;
156   Boolean             useGUI;
157   Boolean             do_update;
158   ButtoN              add_cit_subs;
159   ButtoN              update_proteins;
160   Boolean             suppress_continue_msg;
161   Boolean             suppress_instant_refresh;
162   ButtoN              update_quality_scores_btn;
163   FILE                *log_fp;
164   Char                log_path [PATH_MAX];
165   Boolean             data_in_log;
166   ButtoN              truncate_proteins_btn;
167   ButtoN              extend_proteins5_btn;
168   ButtoN              extend_proteins3_btn;
169   ButtoN              correct_cds_genes_btn;
170   Boolean             truncate_proteins;
171   Boolean             extend_proteins5;
172   Boolean             extend_proteins3;
173   Boolean             correct_cds_genes;
174   ValNodePtr          transl_except_list;
175   Int2                rmcval;      /* This is the choice selected from the
176                                     * rmc radio button group.
177                                     * We store it so that we can use it in
178                                     * Accept All.
179                                     */
180   
181   SeqEntryPtr         seqsubsep;   /* when we are updating from a Sequin record
182                                     * that contains a set, store the set here.
183                                     */
184   Int4                seqsubpos;   /* when we are updating from a Sequin record
185                                     * that contains a set, store the number of
186                                     * Bioseqs already processed here.
187                                     */
188                                     
189   Int2                no_aln_choice; /* what to do when updating a set and no
190                                       * alignment is found.
191                                       */
192   
193   ValNodePtr          affected_variation_features;   /* list of variation features
194                                                       * affected by this update.
195                                                       * by "affected" we mean that
196                                                       * an insertion, deletion,
197                                                       * or replacement takes place
198                                                       * either inside the variation
199                                                       * location, or immediately
200                                                       * to the left or right of the
201                                                       * location.
202                                                       */
203 } UpsData, PNTR UpsDataPtr;
204 
205 /*---------------------*/
206 /* Function prototypes */
207 /*---------------------*/
208 
209 static Int2 UpdateNextBioseqInFastaSet (UpsDataPtr udp);
210 static void FreeUdpFields (UpsDataPtr udp);
211 static void TruncateCDS (SeqFeatPtr sfp, Uint1 frame, BioseqPtr pbsp);
212 
213 extern void SubmitToNCBI (IteM i);
214 extern void QuitProc (void);
215 extern void NewFeaturePropagate (IteM i);
216 extern void FixCdsAfterPropagate (IteM i);
217 extern void MakeRedundantGPSwithProp (IteM i);
218 extern void MakeRedundantGPSnoProp (IteM i);
219 extern void MakeRedundantGPSjustXref (IteM i);
220 extern void FuseSlpJoins (IteM i);
221 
222 /*-----------*/
223 /* Functions */
224 /*-----------*/
225 
226 /*
227  * This function is called by HandleOneNewAsnProc, CommonHandleMultBioseqs,
228  * and DoReadAnythingLoop in sequin1.c
229  */
230 extern void HandleProjectAsn (ProjectPtr proj, Uint2 entityID)
231 
232 {
233   Int2              db = -1;
234   EntrezGlobalsPtr  egp;
235   Int4              i;
236   ValNodePtr        list;
237   Int4              num;
238   ValNodePtr        pip;
239   Int4Ptr           uids;
240   ValNodePtr        vnp;
241 
242   if (proj == NULL) return;
243   if (! useEntrez) return;
244   egp = (EntrezGlobalsPtr) GetAppProperty ("EntrezGlobals");
245   if (egp == NULL) return;
246   pip = proj->data;
247   if (pip == NULL) return;
248   list = (ValNodePtr) pip->data.ptrvalue;
249   if (list == NULL) return;
250   if (pip->choice >= ProjectItem_protent && pip->choice <= ProjectItem_genomeent) {
251     if (egp->retrieveProjectProc == NULL) return;
252     /*
253     if (! EntrezIsInited ()) {
254       SequinEntrezInit ("Sequin", FALSE, NULL);
255     }
256     */
257     egp->retrieveProjectProc (NULL, (Pointer) proj);
258     Update ();
259     return;
260   }
261   if (egp->retrieveDocsProc == NULL) return;
262   switch (pip->choice) {
263     case ProjectItem_pmuid :
264       db = 0;
265       break;
266     case ProjectItem_protuid :
267       db = 1;
268       break;
269     case ProjectItem_nucuid :
270       db = 2;
271       break;
272     case ProjectItem_genomeuid :
273       db = 4;
274       break;
275     case ProjectItem_structuid :
276       db = 3;
277       break;
278     default :
279       break;
280   }
281   if (db == -1) return;
282   /*
283   if (! EntrezIsInited ()) {
284     SequinEntrezInit ("Sequin", FALSE, NULL);
285   }
286   */
287   num = ValNodeLen (list);
288   uids = MemNew ((size_t) (num * sizeof (Int4)));
289   if (uids == NULL) return;
290   for (i = 0, vnp = list; i < 32766 && vnp != NULL; i++, vnp = vnp->next) {
291     uids [i] = vnp->data.intvalue;
292   }
293   if (egp->retrieveDocsProc != NULL) {
294     egp->retrieveDocsProc (NULL, (Int2) num, 0, uids, db);
295   }
296   MemFree (uids);
297   Update ();
298 }
299 
300 /* BioseqViewOrDocSumChoice allows a single callback for each analysis item */
301 static Int2 BioseqViewOrDocSumChoice (NewObjectPtr nop)
302 
303 {
304   Int2  which = 0;   /* 1 = bioseq viewer, 2 = docsum window */
305 
306   if (nop == NULL) return 0;
307 #ifdef WIN_MAC
308   if (bioseqViewUp) {
309     which = 1;
310   } else if (docSumUp) {
311     which = 2;
312   }
313 #else
314   if (nop->bspOK) {
315     which = 1;
316   } else if (nop->dsmOK) {
317     which = 2;
318   }
319 #endif
320   return which;
321 }
322 
323 /*
324 #define TEST_APPLE_EVENT_MESSAGING
325 */
326 
327 #ifndef TEST_APPLE_EVENT_MESSAGING
328 static void AddRestrictionSite (SeqAnnotPtr annot, PackSeqPntPtr pspp, CharPtr name)
329 
330 {
331   DbtagPtr     dbt;
332   ObjectIdPtr  oip;
333   RsiteRefPtr  rrp;
334   SeqFeatPtr   sfp, lastsfp;
335   SeqLocPtr    slp;
336 
337   if (annot == NULL || pspp == NULL || name == NULL) return;
338   slp = ValNodeNew (NULL);
339   if (slp == NULL) return;
340   slp->choice = SEQLOC_PACKED_PNT;
341   slp->data.ptrvalue = (Pointer) pspp;
342   sfp = SeqFeatNew ();
343   if (sfp == NULL) return;
344 
345   sfp->data.choice = SEQFEAT_RSITE;
346   sfp->location = slp;
347   dbt = DbtagNew ();
348   if (dbt != NULL) {
349     dbt->db = StringSave ("REBASE");
350     oip = ObjectIdNew ();
351     if (oip != NULL) {
352       oip->str = StringSave (name);
353     }
354     dbt->tag = oip;
355   }
356   rrp = ValNodeNew (NULL);
357   if (rrp != NULL) {
358     rrp->choice = 2;
359     rrp->data.ptrvalue = dbt;
360   }
361   sfp->data.value.ptrvalue = (Pointer) rrp;
362 
363   if (annot->data == NULL) {
364     annot->data = (Pointer) sfp;
365   } else {
366     lastsfp = (SeqFeatPtr) annot->data;
367     while (lastsfp->next != NULL) {
368       lastsfp = lastsfp->next;
369     }
370     lastsfp->next = sfp;
371   }
372 }
373 
374 static void RestrictionSearchProc (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
375 
376 {
377   SeqAnnotPtr    annot;
378   BioseqPtr      bsp;
379   ComPatPtr      cpp, cpph;
380   ValNodePtr     desc;
381   SeqAnnotPtr    lastannot;
382   PackSeqPntPtr  pspp;
383   Int4           pt;
384   SeqAlignPtr    sap;
385   SeqLocPtr      slp, slpn;
386 
387   if (sep == NULL) return;
388   if (! IS_Bioseq (sep)) return;
389   bsp = (BioseqPtr) sep->data.ptrvalue;
390   if (bsp == NULL) return;
391   if (! ISA_na (bsp->mol)) return;
392 
393   desc = SeqDescrNew (NULL);
394   desc->choice = Annot_descr_name;
395   desc->data.ptrvalue = StringSave ("cutsites");
396 
397   annot = SeqAnnotNew ();
398   annot->type = 1;
399   annot->desc = desc;
400   annot->data = NULL;
401 
402   cpph = (ComPatPtr) mydata;
403   cpp = cpph;
404   while (cpp != NULL) {
405     sap = PatternMatchBioseq (bsp, cpp, 0);
406     slp = MatchSa2Sl (&sap);
407     if (slp != NULL) {
408       pspp = PackSeqPntNew ();
409       pspp->id = SeqIdDup (SeqIdFindBest (bsp->id, 0));
410       while (slp != NULL) {
411         pt = SeqLocStart (slp);
412         PackSeqPntPut (pspp, pt);
413         slpn = slp->next;
414         SeqLocFree (slp);
415         slp = slpn;
416       }
417       AddRestrictionSite (annot, pspp, cpp->name);
418     }
419     cpp = cpp->nextpattern;
420   }
421 
422   if (annot->data == NULL) {
423     SeqAnnotFree (annot);
424     return;
425   }
426   if (bsp->annot == NULL) {
427     bsp->annot = annot;
428   } else {
429     lastannot = bsp->annot;
430     while (lastannot->next != NULL) {
431       lastannot = lastannot->next;
432     }
433     lastannot->next = annot;
434   }
435 }
436 #endif
437 
438 static void SimpleRsiteProc (IteM i)
439 
440 {
441   BaseFormPtr   bfp;
442   BioseqPtr     bsp;
443   NewObjectPtr  nop;
444   SeqEntryPtr   sep = NULL;
445   Int2          which;
446 #ifdef TEST_APPLE_EVENT_MESSAGING
447   AsnIoPtr      aip;
448   Char          tmp [PATH_MAX];
449 #else
450   ComPatPtr     cpph;
451   Char          enzyme [64];
452   Int2          j;
453   Char          temp [32];
454   ValNodePtr    enzymes;
455 #endif
456 
457   nop = (NewObjectPtr) GetObjectExtra (i);
458   if (nop == NULL) return;
459 #ifdef WIN_MAC
460   bfp = (BaseFormPtr) currentFormDataPtr;
461 #else
462   bfp = nop->bfp;
463 #endif
464   if (bfp == NULL) return;
465   which = BioseqViewOrDocSumChoice (nop);
466   if (which != 1) return;
467   bsp =  GetBioseqGivenIDs (bfp->input_entityID, bfp->input_itemID, bfp->input_itemtype);
468   if (bsp != NULL) {
469     sep = SeqMgrGetSeqEntryForData (bsp);
470   } else {
471     sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
472   }
473   if (sep == NULL) return;
474 
475 #ifdef TEST_APPLE_EVENT_MESSAGING
476   TmpNam (tmp);
477   aip = AsnIoOpen (tmp, "w");
478   if (aip != NULL) {
479     SeqEntryAsnWrite (sep, aip, NULL);
480     AsnIoClose (aip);
481     /* Nlm_SendOpenDocAppleEventEx (tmp, "REST", NULL, TRUE); */
482     Nlm_SendOpenDocAppleEventEx (tmp, NULL, "RsiteFind", TRUE);
483   }
484 #else
485   enzymes = NULL;
486   j = 1;
487   sprintf (temp, "ENZ_%d", (int) j);
488   while (GetAppParam ("SEQNCGIS", "ENZYMES", temp, NULL, enzyme, sizeof (enzyme) - 1)) {
489     ValNodeCopyStr (&enzymes, 0, enzyme);
490     j++;
491     sprintf (temp, "ENZ_%d", (int) j);
492   }
493   if (enzymes == NULL) {
494     ValNodeCopyStr (&enzymes, 0, "BamHI");
495     ValNodeCopyStr (&enzymes, 0, "EcoRI");
496     ValNodeCopyStr (&enzymes, 0, "HindIII");
497   }
498   cpph = ReadRENPattern ("ncbiren.dat", FALSE, enzymes);
499   /* PalindromeCheck (cpph); */
500   SeqEntryExplore (sep, (Pointer) cpph, RestrictionSearchProc);
501   ComPatFree (cpph);
502   ValNodeFreeData (enzymes);
503 
504   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
505   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
506   Update ();
507 #endif
508 }
509 
510 static VQUEUE  vsquerylist = NULL;
511 
512 static Int2 vsquerynum = 0;
513 
514 /*
515 static void LIBCALLBACK AnnounceCallback (CharPtr requestID, CharPtr seqID, Int2 estimatedSeconds)
516 
517 {
518   if (StringHasNoText (requestID)) {
519     requestID = "?";
520   }
521   if (StringHasNoText (seqID)) {
522     seqID = "?";
523   }
524   Message (MSG_POST, "Queued rID %s, seqID %s, estimated seconds = %d",
525            requestID, seqID, (int) estimatedSeconds);
526 
527   vsquerynum++;
528 }
529 
530 static Boolean LIBCALLBACK VecScreenCallback (
531   CharPtr filename,
532   VoidPtr userdata,
533   CharPtr requestID,
534   CharPtr seqID,
535   Boolean success
536 )
537 
538 {
539   if (StringHasNoText (requestID)) {
540     requestID = "?";
541   }
542   if (StringHasNoText (seqID)) {
543     seqID = "?";
544   }
545   if (success) {
546     if (! SequinHandleNetResults (filename)) {
547     }
548   } else {
549     Message (MSG_POST, "Failure of rID '%s', seqID %s", requestID, seqID);
550   }
551   return TRUE;
552 }
553 
554 static void DoVecScreens (BioseqPtr bsp, Pointer userdata)
555 
556 {
557   CharPtr  service;
558 
559   if (bsp == NULL || ISA_aa (bsp->mol)) return;
560   service = (CharPtr) userdata;
561   VecScreenAsynchronousRequest (service, bsp, &vsquerylist, VecScreenCallback, AnnounceCallback, NULL);
562 }
563 
564 static void SimpleVecScreenCommon (IteM i, CharPtr service)
565 
566 {
567   BaseFormPtr   bfp;
568   BioseqPtr     bsp;
569   NewObjectPtr  nop;
570   SeqEntryPtr   sep = NULL;
571   Int2          which;
572 
573   nop = (NewObjectPtr) GetObjectExtra (i);
574   if (nop == NULL) return;
575 #ifdef WIN_MAC
576   bfp = (BaseFormPtr) currentFormDataPtr;
577 #else
578   bfp = nop->bfp;
579 #endif
580   if (bfp == NULL) return;
581   which = BioseqViewOrDocSumChoice (nop);
582   if (which != 1) return;
583   bsp =  GetBioseqGivenIDs (bfp->input_entityID, bfp->input_itemID, bfp->input_itemtype);
584   if (bsp != NULL) {
585     sep = SeqMgrGetSeqEntryForData (bsp);
586     if (sep == NULL) return;
587     VecScreenAsynchronousRequest (service, bsp, &vsquerylist, VecScreenCallback, AnnounceCallback, NULL);
588   } else {
589     sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
590     if (sep == NULL) return;
591     VisitBioseqsInSep (sep, (Pointer) service, DoVecScreens);
592   }
593 }
594 */
595 
596 typedef struct vsdata {
597   CharPtr     date;
598   CharPtr     path;
599   CharPtr     database;
600   Boolean     changed;
601   Int4        count;
602   MonitorPtr  mon;
603 } VsData, PNTR VsDataPtr;
604 
605 static CharPtr vectorStrengths [6] = {
606   NULL,
607   "Strong match",
608   "Moderate match",
609   "Weak match",
610   "Suspect origin",
611   "Unknown vector match"
612 };
613 
614 static void CountVecScreens (BioseqPtr bsp, Pointer userdata)
615 
616 {
617   Int4Ptr  maxp;
618 
619   if (bsp == NULL || ISA_aa (bsp->mol)) return;
620   maxp = (Int4Ptr) userdata;
621   (*maxp)++;
622 }
623 
624 static void DoVecScreens (BioseqPtr bsp, Pointer userdata)
625 
626 {
627   AnnotDescrPtr   desc;
628   GeneRefPtr      grp;
629   Int2            hits;
630   ImpFeatPtr      ifp;
631   ValNodePtr      locs = NULL;
632   Char            note [128];
633   SeqAnnotPtr     prevsap;
634   SeqFeatPtr      prevsfp;
635   SeqAnnotPtr     sap = NULL;
636   SeqFeatPtr      sfp = NULL;
637   SeqIdPtr        sip;
638   SeqLocPtr       slp;
639   Int4            start;
640   Int4            stop;
641   Uint1           strength;
642   SeqLocPtr       tmp;
643   VsDataPtr       vsp;
644   ValNodePtr      vnp;
645   SeqFeatXrefPtr  xref;
646 
647   if (bsp == NULL || ISA_aa (bsp->mol)) return;
648   vsp = (VsDataPtr) userdata;
649   if (vsp == NULL) return;
650   sip = SeqIdFindBest (bsp->id, 0);
651   if (sip == NULL) return;
652 
653   if (vsp->mon != NULL) {
654     MonitorIntValue (vsp->mon, vsp->count);
655   }
656   (vsp->count)++;
657 
658   hits = VSScreenSequence (bsp, NULL, vsp->path, NULL, &locs, NULL, NULL);
659   for (vnp = locs; vnp != NULL; vnp = vnp->next) {
660     strength = vnp->choice;
661     if (strength < 1 || strength > 4) {
662       strength = 5;
663     }
664     slp = (SeqLocPtr) vnp->data.ptrvalue;
665     if (slp == NULL) continue;
666     if (slp->choice == SEQLOC_PACKED_INT) {
667       for (tmp = (SeqLocPtr) slp->data.ptrvalue; tmp != NULL; tmp = tmp->next) {
668         start = SeqLocStart (tmp);
669         stop = SeqLocStop (tmp);
670         if (start < 0 || stop < 0) continue;
671         vsp->changed = TRUE;
672 
673         if (sap == NULL) {
674           sap = SeqAnnotNew ();
675           if (sap != NULL) {
676             sap->type = 1;
677             desc = AnnotDescrNew (NULL);
678             if (desc != NULL) {
679               desc->choice = Annot_descr_name;
680               desc->data.ptrvalue = StringSave ("VecScreen");
681               sap->desc = desc;
682             }
683           }
684         }
685 
686         sfp = SeqFeatNew ();
687         if (sfp != NULL) {
688 
689           /* make misc_feature for now */
690 
691           sfp->data.choice = SEQFEAT_IMP;
692           ifp = ImpFeatNew ();
693           if (ifp != NULL) {
694             ifp->key = StringSave ("misc_feature");
695           }
696           AddQualifierToFeature (sfp, "standard_name", "Vector Contamination");
697           AddQualifierToFeature (sfp, "phenotype", vectorStrengths [(int) strength]);
698 
699           sprintf (note, "Screened against %s using VecScreen on %s", vsp->database, vsp->date);
700           sfp->comment = StringSave (note);
701 
702           /* suppress /gene */
703 
704           grp = GeneRefNew ();
705           if (grp != NULL) {
706             xref = SeqFeatXrefNew ();
707             sfp->xref = xref;
708             if (xref != NULL) {
709               xref->data.choice = SEQFEAT_GENE;
710               xref->data.value.ptrvalue = (Pointer) grp;
711             }
712           }
713 
714           sfp->data.value.ptrvalue = (Pointer) ifp;
715 
716           if (sap != NULL) {
717             if (sap->data != NULL) {
718               prevsfp = sap->data;
719               while (prevsfp->next != NULL) {
720                 prevsfp = prevsfp->next;
721               }
722               prevsfp->next = sfp;
723             } else {
724               sap->data = (Pointer) sfp;
725             }
726           }
727 
728           sfp->location = AddIntervalToLocation (NULL, sip, (Int4) start, (Int4) stop, FALSE, FALSE);
729         }
730       }
731     }
732     SeqLocFree (slp);
733   }
734   locs = ValNodeFree (locs);
735 
736   if (sap != NULL) {
737     if (bsp->annot != NULL) {
738       prevsap = bsp->annot;
739       while (prevsap->next != NULL) {
740         prevsap = prevsap->next;
741       }
742       prevsap->next = sap;
743     } else {
744       bsp->annot = sap;
745     }
746   }
747 }
748 
749 static void SimpleVecScreenCommon (IteM i, CharPtr database)
750 
751 {
752   BaseFormPtr   bfp;
753   BioseqPtr     bsp;
754   Char          date [32];
755   DatePtr       dp;
756   Int4          max;
757   Char          path [PATH_MAX];
758   CharPtr       pathplusone;
759   Char          quote [4];
760   SeqEntryPtr   sep;
761   VsData        vsd;
762 
763 #ifdef WIN_MAC
764   bfp = (BaseFormPtr) currentFormDataPtr;
765 #else
766   bfp = (BaseFormPtr) GetObjectExtra (i);
767 #endif
768   if (bfp == NULL) return;
769 
770   path [0] = '"';
771   path [1] = '\0';
772   pathplusone = &(path [1]);
773   GetAppParam ("NCBI", "NCBI", "DATA", "", pathplusone, sizeof (path) - 1);
774 
775   /*
776   if (StringChr (path, ' ') != NULL) {
777     Message (MSG_OK, "Unable to process because vector database file\npath must not have a space character.  Path is:\n'%s'", path);
778     return;
779   }
780   */
781 
782   FileBuildPath (pathplusone, NULL, database);
783   quote [0] = '"';
784   quote [1] = '\0';
785   StringCat (pathplusone, quote);
786 
787   date [0] = '\0';
788   dp = DateCurr ();
789   DatePrint (dp, date);
790   DateFree (dp);
791 
792   vsd.date = date;
793   vsd.path = path;
794   vsd.database = database;
795   vsd.changed = FALSE;
796   vsd.count = 0;
797   vsd.mon = NULL;
798 
799   bsp =  GetBioseqGivenIDs (bfp->input_entityID, bfp->input_itemID, bfp->input_itemtype);
800   if (bsp != NULL) {
801     DoVecScreens (bsp, (Pointer) &vsd);
802   } else {
803     sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
804     if (sep == NULL) return;
805     max = 0;
806     VisitBioseqsInSep (sep, (Pointer) &max, CountVecScreens);
807     if (max > 2) {
808       vsd.mon = MonitorIntNewEx ("VecScreen Progress", 0, max - 1, FALSE);
809     }
810     VisitBioseqsInSep (sep, (Pointer) &vsd, DoVecScreens);
811     if (vsd.mon != NULL) {
812       vsd.mon = MonitorFree (vsd.mon);
813       Update ();
814     }
815   }
816 
817   if (vsd.changed) {
818     ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
819     ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
820     Update ();
821   } else {
822     Message (MSG_POST, "No vector contamination found");
823   }
824 }
825 
826 extern void SimpleUniVecScreenProc (IteM i)
827 
828 {
829   SimpleVecScreenCommon (i, "UniVec");
830 }
831 
832 extern void SimpleUniVecCoreScreenProc (IteM i)
833 
834 {
835   SimpleVecScreenCommon (i, "UniVec_Core");
836 }
837 
838 static QBQUEUE  qbquerylist = NULL;
839 
840 static void LIBCALLBACK QBAnnounceCallback (CharPtr requestID, CharPtr seqID, Int2 estimatedSeconds)
841 
842 {
843   if (StringHasNoText (requestID)) {
844     requestID = "?";
845   }
846   if (StringHasNoText (seqID)) {
847     seqID = "?";
848   }
849   Message (MSG_POST, "Queued rID %s, seqID %s, estimated seconds = %d",
850            requestID, seqID, (int) estimatedSeconds);
851 }
852 
853 static Boolean LIBCALLBACK QBCallback (
854   CharPtr filename,
855   VoidPtr userdata,
856   CharPtr requestID,
857   CharPtr seqID,
858   Boolean success
859 )
860 
861 {
862   if (StringHasNoText (requestID)) {
863     requestID = "?";
864   }
865   if (StringHasNoText (seqID)) {
866     seqID = "?";
867   }
868   if (success) {
869     if (! SequinHandleNetResults (filename)) {
870       /* LaunchGeneralTextViewer (path, "QueueFastaQueryToURL failed"); */
871     }
872   } else {
873     Message (MSG_POST, "Failure of rID '%s', seqID %s", requestID, seqID);
874   }
875   return TRUE;
876 }
877 
878 static void SimpleQBlastProc (IteM i)
879 
880 {
881   BaseFormPtr   bfp;
882   BioseqPtr     bsp;
883   NewObjectPtr  nop;
884   SeqEntryPtr   sep = NULL;
885   Int2          which;
886 
887   nop = (NewObjectPtr) GetObjectExtra (i);
888   if (nop == NULL) return;
889 #ifdef WIN_MAC
890   bfp = (BaseFormPtr) currentFormDataPtr;
891 #else
892   bfp = nop->bfp;
893 #endif
894   if (bfp == NULL) return;
895   which = BioseqViewOrDocSumChoice (nop);
896   if (which != 1) return;
897   bsp =  GetBioseqGivenIDs (bfp->input_entityID, bfp->input_itemID, bfp->input_itemtype);
898   if (bsp != NULL) {
899     sep = SeqMgrGetSeqEntryForData (bsp);
900   } else {
901     sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
902   }
903   if (sep == NULL) return;
904 
905   QBlastAsynchronousRequest ("nr", "blastn", bsp, &qbquerylist, QBCallback, QBAnnounceCallback, NULL);
906 }
907 
908 /* Analysis menu can launch external programs or use Web services */
909 
910 static QUEUE  urlquerylist = NULL;
911 
912 static Int4 pendingqueries = 0;
913 
914 static Boolean LIBCALLBACK SubmitToNCBIResultProc (CONN conn, VoidPtr userdata, EIO_Status status)
915 
916 {
917   AsnIoPtr     aop;
918   FILE         *fp;
919   Char         path [PATH_MAX];
920   SeqEntryPtr  sep;
921 
922   TmpNam (path);
923   fp = FileOpen (path, "wb");
924   QUERY_CopyResultsToFile (conn, fp);
925   FileClose (fp);
926   aop = AsnIoOpen (path, "rb");
927   sep = SeqEntryAsnRead (aop, NULL);
928   AsnIoClose (aop);
929   aop = AsnIoOpen (path, "w");
930   SeqEntryAsnWrite (sep, aop, NULL);
931   AsnIoFlush (aop);
932   AsnIoClose (aop);
933   LaunchGeneralTextViewer (path, "Echo binary transformation of Seq-entry");
934   FileRemove (path);
935   return TRUE;
936 }
937 
938 extern void SubmitToNCBI (IteM i)
939 
940 {
941   AsnIoPtr     aop;
942   BaseFormPtr  bfp;
943   CONN         conn;
944   FILE         *fp;
945   Char         path [PATH_MAX];
946   Char         progname [64];
947   SeqEntryPtr  sep;
948 
949 #ifdef WIN_MAC
950   bfp = currentFormDataPtr;
951 #else
952   bfp = GetObjectExtra (i);
953 #endif
954   if (bfp == NULL) return;
955   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
956   if (sep == NULL) return;
957 
958   sprintf (progname, "Sequin/%s", SEQUIN_APPLICATION);
959 
960   TmpNam (path);
961 
962   aop = AsnIoOpen (path, "wb");
963   SeqEntryAsnWrite (sep, aop, NULL);
964   AsnIoFlush (aop);
965   AsnIoClose (aop);
966 
967   conn = QUERY_OpenUrlQuery ("cruncher.nlm.nih.gov", 80,
968                              "/cgi-bin/Sequin/testcgi.cgi", "request=echo",
969                              progname, 30, eMIME_T_NcbiData, eMIME_AsnBinary,
970                              eENCOD_Url,
971                              fHCC_UrlDecodeInput | fHCC_UrlEncodeOutput);
972 
973   fp = FileOpen (path, "rb");
974   QUERY_CopyFileToQuery (conn, fp);
975   FileClose (fp);
976 
977   QUERY_SendQuery (conn);
978 
979   QUERY_AddToQueue (&urlquerylist, conn, SubmitToNCBIResultProc, NULL, TRUE);
980 
981   pendingqueries++;
982 
983   FileRemove (path);
984 }
985 
986 static QUEUE  cddquerylist = NULL;
987 
988 static Int2  cddquerynum = 0;
989 
990 #include <cddapi.h>
991 
992 #define CDD_EXPECT_VALUE 0.01
993 
994 static Boolean LIBCALLBACK CddProc (
995   CONN conn,
996   VoidPtr userdata,
997   EIO_Status status
998 )
999 
1000 {
1001   BioseqPtr    bsp;
1002   SeqAnnotPtr  prev;
1003   SeqAnnotPtr  sap;
1004 
1005   if (conn == NULL || userdata == NULL) return TRUE;
1006   if (status != eIO_Success) return TRUE;
1007   sap = CddReadReply (conn, status);
1008   if (sap == NULL) return FALSE;
1009 
1010   bsp = (BioseqPtr) userdata;
1011   CddCorrectIDs (bsp, sap);
1012 
1013   prev = bsp->annot;
1014   if (prev == NULL) {
1015     bsp->annot = sap;
1016   } else {
1017     while (prev->next != NULL) {
1018       prev = prev->next;
1019     }
1020     prev->next = sap;
1021   }
1022 
1023   ObjMgrSetDirtyFlag (bsp->idx.entityID, TRUE);
1024   ObjMgrSendMsg (OM_MSG_UPDATE, bsp->idx.entityID, 0, 0);
1025 
1026   return TRUE;
1027 }
1028 
1029 static void SearchCDD (BioseqPtr bsp, Pointer userdata)
1030 
1031 {
1032   BoolPtr  dofeats;
1033 
1034   if (bsp == NULL) return;
1035   if (! ISA_aa (bsp->mol)) return;
1036 
1037   dofeats = (BoolPtr) userdata;
1038   if (! CddAsynchronousQuery (bsp, CDD_EXPECT_VALUE, TRUE, TRUE, *dofeats, "cdd", FALSE, &cddquerylist, CddProc, (Pointer) bsp)) {
1039     ErrPostEx (SEV_ERROR, 0, 0, "Unable to run CDD search");
1040   } else {
1041     cddquerynum++;
1042   }
1043 }
1044 
1045 /*
1046 static void SearchCDD (BioseqPtr bsp, Pointer userdata)
1047 
1048 {
1049   BoolPtr      dofeats;
1050   SeqAnnotPtr  prev;
1051   SeqAnnotPtr  sap;
1052 
1053   if (bsp == NULL) return;
1054   if (! ISA_aa (bsp->mol)) return;
1055 
1056   dofeats = (BoolPtr) userdata;
1057   sap = CddSynchronousQuery (bsp, CDD_EXPECT_VALUE, TRUE, TRUE, *dofeats, "cdd", FALSE);
1058   if (sap == NULL) return;
1059   CddCorrectIDs (bsp, sap);
1060 
1061   prev = bsp->annot;
1062   if (prev == NULL) {
1063     bsp->annot = sap;
1064   } else {
1065     while (prev->next != NULL) {
1066       prev = prev->next;
1067     }
1068     prev->next = sap;
1069   }
1070 }
1071 */
1072 
1073 static void SimpleCDDSearchCommonProc (IteM i, Boolean makeFeats)
1074 
1075 {
1076   BaseFormPtr  bfp;
1077   Boolean      dofeats;
1078   SeqEntryPtr  sep;
1079 
1080 #ifdef WIN_MAC
1081   bfp = currentFormDataPtr;
1082 #else
1083   bfp = GetObjectExtra (i);
1084 #endif
1085   if (bfp == NULL) return;
1086   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1087   if (sep == NULL) return;
1088 
1089   WatchCursor ();
1090   Update ();
1091 
1092   if (makeFeats) {
1093     FreeCDDRegions (sep);
1094   } else {
1095     FreeCDDAligns (sep);
1096   }
1097 
1098   dofeats = makeFeats;
1099   VisitBioseqsInSep (sep, (Pointer) &dofeats, SearchCDD);
1100 
1101   /*
1102   RemoveDuplicateCDDs (sep);
1103 
1104   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1105   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1106   */
1107   ArrowCursor ();
1108   Update ();
1109  }
1110 
1111 void SimpleCDDSearchFeatProc (IteM i)
1112 
1113 {
1114   SimpleCDDSearchCommonProc (i, TRUE);
1115 }
1116 
1117 void SimpleCDDSearchAlignProc (IteM i)
1118 
1119 {
1120   SimpleCDDSearchCommonProc (i, FALSE);
1121 }
1122 
1123 extern void SequinCheckSocketsProc (void)
1124 
1125 {
1126   Int4  remaining;
1127 
1128   remaining = QUERY_CheckQueue (&urlquerylist);
1129   if (remaining < pendingqueries) {
1130     Beep ();
1131     pendingqueries--;
1132   }
1133   remaining = VecScreenCheckQueue (&vsquerylist);
1134   if (remaining < vsquerynum) {
1135     vsquerynum = remaining;
1136     Message (MSG_POST, "There are %d vector screens remaining", (int) vsquerynum);
1137   }
1138   remaining = QBlastCheckQueue (&qbquerylist);
1139   remaining = CddCheckQueue (&cddquerylist);
1140   if (remaining < cddquerynum) {
1141     cddquerynum = remaining;
1142     Message (MSG_POST, "There are %d cdd searches remaining", (int) cddquerynum);
1143   }
1144 }
1145 
1146 static Boolean LIBCALLBACK DemoModeResultProc (CONN conn, VoidPtr userdata, EIO_Status status)
1147 
1148 {
1149   FILE  *fp;
1150   Char  path [PATH_MAX];
1151 
1152   TmpNam (path);
1153   fp = FileOpen (path, "w");
1154   QUERY_CopyResultsToFile (conn, fp);
1155   FileClose (fp);
1156   LaunchGeneralTextViewer (path, "QueueFastaQueryToURL results");
1157   FileRemove (path);
1158   return TRUE;
1159 }
1160 
1161 static Boolean LIBCALLBACK SequinHandleURLResults (CONN conn, VoidPtr userdata, EIO_Status status)
1162 
1163 {
1164   FILE  *fp;
1165   Char  path [PATH_MAX];
1166 
1167   TmpNam (path);
1168   fp = FileOpen (path, "w");
1169   QUERY_CopyResultsToFile (conn, fp);
1170   FileClose (fp);
1171   if (! SequinHandleNetResults (path)) {
1172     /* LaunchGeneralTextViewer (path, "QueueFastaQueryToURL failed"); */
1173   }
1174   FileRemove (path);
1175   return TRUE;
1176 }
1177 
1178 static void FinishURLProc (NewObjectPtr nop, CharPtr arguments, CharPtr path)
1179 
1180 {
1181   CONN             conn;
1182   FILE             *fp;
1183   Char             progname [64];
1184   QueryResultProc  resultproc;
1185   EMIME_SubType    subtype;
1186 
1187   sprintf (progname, "Sequin/%s", SEQUIN_APPLICATION);
1188 
1189   if (nop->demomode) {
1190     resultproc = DemoModeResultProc;
1191   } else {
1192     resultproc = nop->resultproc;
1193   }
1194   if (nop->format == 1) {
1195     subtype = eMIME_Fasta;
1196   } else if (nop->format == 2) {
1197     subtype = eMIME_AsnText;
1198   } else {
1199     subtype = eMIME_Unknown;
1200   }
1201 
1202   conn = QUERY_OpenUrlQuery (nop->host_machine, nop->host_port,
1203                              nop->host_path, arguments,
1204                              progname, nop->timeoutsec,
1205                              eMIME_T_NcbiData, subtype, eENCOD_Url,
1206                              fHCC_UrlDecodeInput | fHCC_UrlEncodeOutput);
1207   if (conn == NULL) return;
1208 
1209   fp = FileOpen (path, "r");
1210   QUERY_CopyFileToQuery (conn, fp);
1211   FileClose (fp);
1212 
1213   QUERY_SendQuery (conn);
1214 
1215   QUERY_AddToQueue (&urlquerylist, conn, resultproc, NULL, TRUE);
1216 
1217   pendingqueries++;
1218 }
1219 
1220 static void DoAnalysisProc (NewObjectPtr nop, BaseFormPtr bfp, Int2 which, CharPtr arguments, ResultProc dotheanalysis)
1221 
1222 {
1223   AsnIoPtr     aop;
1224   BioseqPtr    bsp;
1225   Char         path1 [PATH_MAX];
1226   SeqEntryPtr  sep;
1227 
1228   if (nop == NULL || bfp == NULL) return;
1229   switch (which) {
1230     case 1 :
1231       if (BioseqViewCanSaveFasta (bfp->form, nop->fastaNucOK, nop->fastaProtOK, nop->onlyBspTarget)) {
1232         TmpNam (path1);
1233         switch (nop->format) {
1234           case 1 :
1235             ExportBioseqViewFasta (bfp->form, path1, nop->fastaNucOK, nop->fastaProtOK, nop->onlyBspTarget);
1236             break;
1237           case 2 :
1238             sep = NULL;
1239             if (nop->onlyBspTarget) {
1240               bsp =  GetBioseqGivenIDs (bfp->input_entityID, bfp->input_itemID, bfp->input_itemtype);
1241               sep = SeqMgrGetSeqEntryForData (bsp);
1242             } else {
1243               sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1244             }
1245             if (sep != NULL) {
1246               aop = AsnIoOpen (path1, "w");
1247               SeqEntryAsnWrite (sep, aop, NULL);
1248               AsnIoFlush (aop);
1249               AsnIoClose (aop);
1250             }
1251             break;
1252           default :
1253             break;
1254         }
1255         if (dotheanalysis != NULL) {
1256           dotheanalysis (path1);
1257         } else {
1258           FinishURLProc (nop, arguments, path1);
1259         }
1260         FileRemove (path1);
1261       } else {
1262         ErrPostEx (SEV_ERROR, 0, 0, "BioseqView cannot save fasta format");
1263       }
1264       break;
1265     case 2 :
1266       /*
1267       if (DocSumCanSaveFasta (bfp->form, nop->fastaNucOK, nop->fastaProtOK)) {
1268         TmpNam (path1);
1269         ExportDocSumFasta (bfp->form, path1, nop->fastaNucOK, nop->fastaProtOK);
1270         if (dotheanalysis != NULL) {
1271           dotheanalysis (path1);
1272         } else {
1273           FinishURLProc (nop, arguments, path1);
1274         }
1275         FileRemove (path1);
1276       } else {
1277         ErrPostEx (SEV_ERROR, 0, 0, "DocSum cannot save fasta format");
1278       }
1279       */
1280       ErrPostEx (SEV_ERROR, 0, 0, "DocSum cannot save fasta format");
1281       break;
1282     default :
1283       break;
1284   }
1285 }
1286 
1287 /* encodes spaces as %20 in URLs */
1288 static CharPtr StrSaveNoNullEncodeSpaces (CharPtr from)
1289 
1290 {
1291   Char     ch;
1292   size_t   len = 0;
1293   CharPtr  p;
1294   CharPtr  q;
1295   CharPtr  to;
1296 
1297   if (StringHasNoText (from)) return NULL;
1298   p = from;
1299   ch = *p;
1300   while (ch != '\0') {
1301     if (ch == ' ') {
1302       len += 3;
1303     } else {
1304       len++;
1305     }
1306     p++;
1307     ch = *p;
1308   }
1309   to = MemNew (len + 1);
1310   if (to == NULL) return NULL;
1311 
1312   q = to;
1313   p = from;
1314   ch = *p;
1315   while (ch != '\0') {
1316     if (ch == ' ') {
1317       *q = '%';
1318       q++;
1319       *q = '2';
1320       q++;
1321       *q = '0';
1322       q++;
1323     } else {
1324       *q = ch;
1325       q++;
1326     }
1327     p++;
1328     ch = *p;
1329   }
1330   *q = '\0';
1331   return to;
1332 }
1333 
1334 typedef struct urlargform {
1335   FORM_MESSAGE_BLOCK
1336 
1337   NewObjectPtr nop;
1338   BaseFormPtr  bfp;
1339   ValNodePtr   controls;
1340   ValNodePtr   helps;
1341   Int2         which;
1342 } UrlArgForm, PNTR UrlArgFormPtr;
1343 
1344 static void AcceptArgumentFormProc (ButtoN b)
1345 
1346 {
1347   CharPtr        args = NULL;
1348   CharPtr        arguments = NULL;
1349   ButtoN         btn;
1350   Char           ch;
1351   Int2           choice;
1352   Char           cpy [256];
1353   GrouP          grp;
1354   ValNodePtr     head = NULL;
1355   Int2           i;
1356   CharPtr        itms;
1357   CharPtr        last;
1358   size_t         len;
1359   LisT           lst;
1360   NewObjectPtr   nop;
1361   Boolean        notFirst = FALSE;
1362   PopuP          pop;
1363   ValNodePtr     ppt;
1364   CharPtr        ptr;
1365   CharPtr        str;
1366   Char           tmp [256];
1367   TexT           txt;
1368   UrlArgFormPtr  ufp;
1369   UrlParamPtr    upp;
1370   Int2           val;
1371   ValNodePtr     vnp;
1372 
1373   ufp = (UrlArgFormPtr) GetObjectExtra (b);
1374   if (ufp == NULL) return;
1375   Hide (ufp->form);
1376   Update ();
1377   nop = ufp->nop;
1378   if (nop != NULL) {
1379     if (! StringHasNoText (nop->prefix)) {
1380       ValNodeCopyStr (&head, 0, nop->prefix);
1381     }
1382     for (vnp = ufp->controls, ppt = nop->paramlist;
1383          vnp != NULL && ppt != NULL;
1384          vnp = vnp->next, ppt = ppt->next) {
1385       upp = (UrlParamPtr) ppt->data.ptrvalue;
1386       if (upp == NULL) continue;
1387       choice = vnp->choice;
1388       switch (upp->type) {
1389         case 1 :
1390           txt = (TexT) vnp->data.ptrvalue;
1391           str = SaveStringFromText (txt);
1392           if (str != NULL) {
1393             sprintf (tmp, "%s=%s", upp->param, str);
1394             ValNodeCopyStr (&head, ppt->choice, tmp);
1395             MemFree (str);
1396           }
1397           break;
1398         case 2 :
1399           btn = (ButtoN) vnp->data.ptrvalue;
1400           if (GetStatus (btn)) {
1401             sprintf (tmp, "%s=TRUE", upp->param);
1402           } else {
1403             sprintf (tmp, "%s=FALSE", upp->param);
1404           }
1405           ValNodeCopyStr (&head, ppt->choice, tmp);
1406           break;
1407         case 3 :
1408           pop = (PopuP) vnp->data.ptrvalue;
1409           val = GetValue (pop);
1410           if (val > 0) {
1411             i = 0;
1412             itms = upp->choices;
1413             StringNCpy_0 (tmp, itms, sizeof (tmp));
1414             last = tmp;
1415             ptr = last;
1416             ch = *ptr;
1417             while (ch != '\0') {
1418               if (ch == ',') {
1419                 *ptr = '\0';
1420                 i++;
1421                 if (val == i) {
1422                   sprintf (cpy, "%s=%s", upp->param, last);
1423                   ValNodeCopyStr (&head, ppt->choice, cpy);
1424                 }
1425                 ptr++;
1426                 last = ptr;
1427                 ch = *ptr;
1428               } else {
1429                 ptr++;
1430                 ch = *ptr;
1431               }
1432             }
1433             if (! StringHasNoText (last)) {
1434               i++;
1435               if (val == i) {
1436                 sprintf (cpy, "%s=%s", upp->param, last);
1437                 ValNodeCopyStr (&head, ppt->choice, cpy);
1438               }
1439             }
1440           }
1441           break;
1442         case 4 :
1443           grp = (GrouP) vnp->data.ptrvalue;
1444           val = GetValue (grp);
1445           if (val > 0) {
1446             i = 0;
1447             itms = upp->choices;
1448             StringNCpy_0 (tmp, itms, sizeof (tmp));
1449             last = tmp;
1450             ptr = last;
1451             ch = *ptr;
1452             while (ch != '\0') {
1453               if (ch == ',') {
1454                 *ptr = '\0';
1455                 i++;
1456                 if (val == i) {
1457                   sprintf (cpy, "%s=%s", upp->param, last);
1458                   ValNodeCopyStr (&head, ppt->choice, cpy);
1459                 }
1460                 ptr++;
1461                 last = ptr;
1462                 ch = *ptr;
1463               } else {
1464                 ptr++;
1465                 ch = *ptr;
1466               }
1467             }
1468             if (! StringHasNoText (last)) {
1469               i++;
1470               if (val == i) {
1471                 sprintf (cpy, "%s=%s", upp->param, last);
1472                 ValNodeCopyStr (&head, ppt->choice, cpy);
1473               }
1474             }
1475           }
1476           break;
1477         case 5 :
1478           lst = (LisT) vnp->data.ptrvalue;
1479           val = GetValue (lst);
1480           if (val > 0) {
1481             i = 0;
1482             itms = upp->choices;
1483             StringNCpy_0 (tmp, itms, sizeof (tmp));
1484             last = tmp;
1485             ptr = last;
1486             ch = *ptr;
1487             while (ch != '\0') {
1488               if (ch == ',') {
1489                 *ptr = '\0';
1490                 i++;
1491                 if (val == i) {
1492                   sprintf (cpy, "%s=%s", upp->param, last);
1493                   ValNodeCopyStr (&head, ppt->choice, cpy);
1494                 }
1495                 ptr++;
1496                 last = ptr;
1497                 ch = *ptr;
1498               } else {
1499                 ptr++;
1500                 ch = *ptr;
1501               }
1502             }
1503             if (! StringHasNoText (last)) {
1504               i++;
1505               if (val == i) {
1506                 sprintf (cpy, "%s=%s", upp->param, last);
1507                 ValNodeCopyStr (&head, ppt->choice, cpy);
1508               }
1509             }
1510           }
1511           break;
1512         default :
1513           break;
1514       }
1515     }
1516     head = SortValNode (head, SortByVnpChoice);
1517     if (! StringHasNoText (nop->suffix)) {
1518       ValNodeCopyStr (&head, 0, nop->suffix);
1519     }
1520     for (len = 0, vnp = head; vnp != NULL; vnp = vnp->next) {
1521       len += StringLen ((CharPtr) vnp->data.ptrvalue) + 1;
1522     }
1523     if (len > 0) {
1524       arguments = MemNew (len + 5);
1525       if (arguments != NULL) {
1526         vnp = head;
1527         notFirst = FALSE;
1528         while (vnp != NULL) {
1529           if (notFirst) {
1530             StringCat (arguments, "&");
1531           }
1532           StringCat (arguments, (CharPtr) vnp->data.ptrvalue);
1533           notFirst = TRUE;
1534           vnp = vnp->next;
1535         }
1536       }
1537     }
1538     args = /* StrSaveNoNullEncodeSpaces */ StringSave (arguments);
1539     MemFree (arguments);
1540     DoAnalysisProc (nop, ufp->bfp, ufp->which, args, NULL);
1541     MemFree (args);
1542   }
1543   Remove (ufp->form);
1544 }
1545 
1546 static void ShowArgumentHelp (ButtoN b)
1547 
1548 {
1549   NewObjectPtr   nop;
1550   ValNodePtr     ppt;
1551   CharPtr        str;
1552   UrlArgFormPtr  ufp;
1553   UrlParamPtr    upp;
1554   ValNodePtr     vnp;
1555 
1556   ufp = (UrlArgFormPtr) GetObjectExtra (b);
1557   if (ufp == NULL) return;
1558   nop = ufp->nop;
1559   if (nop == NULL) return;
1560   for (vnp = ufp->helps, ppt = nop->paramlist;
1561          vnp != NULL && ppt != NULL;
1562          vnp = vnp->next, ppt = ppt->next) {
1563     upp = (UrlParamPtr) ppt->data.ptrvalue;
1564     if (upp == NULL) continue;
1565     if ((Pointer) b == (Pointer) vnp->data.ptrvalue) {
1566       str = upp->help;
1567       Message (MSG_OK, "%s", str);
1568       return;
1569     }
1570   }
1571   Beep ();
1572 }
1573 
1574 static void ArgumentFormMessage (ForM f, Int2 mssg)
1575 
1576 {
1577   UrlArgFormPtr  ufp;
1578 
1579   ufp = (UrlArgFormPtr) GetObjectExtra (f);
1580   if (ufp != NULL) {
1581     switch (mssg) {
1582       case VIB_MSG_CLOSE :
1583         Remove (f);
1584         break;
1585       default :
1586         if (ufp->appmessage != NULL) {
1587           ufp->appmessage (f, mssg);
1588         }
1589         break;
1590     }
1591   }
1592 }
1593 
1594 static void CleanupArgumentForm (GraphiC g, VoidPtr data)
1595 
1596 {
1597   UrlArgFormPtr  ufp;
1598 
1599   ufp = (UrlArgFormPtr) data;
1600   if (ufp != NULL) {
1601     ValNodeFree (ufp->controls);
1602     ValNodeFree (ufp->helps);
1603   }
1604   StdCleanupFormProc (g, data);
1605 }
1606 
1607 static ValNodePtr RearrangeParamList (ValNodePtr paramlist)
1608 
1609 {
1610   ValNodePtr       curr;
1611   CharPtr          group;
1612   ValNodePtr       head = NULL;
1613   ValNodePtr       list;
1614   ValNodePtr       next;
1615   ValNodePtr PNTR  prev;
1616   ValNodePtr       ppt;
1617   UrlParamPtr      upp;
1618 
1619   ppt = paramlist;
1620   while (ppt != NULL) {
1621     list = ppt->next;
1622     ppt->next = NULL;
1623     ValNodeLink (&head, ppt);
1624     upp = (UrlParamPtr) ppt->data.ptrvalue;
1625     if (upp == NULL) {
1626       ppt = list;
1627       continue;
1628     }
1629     group = upp->group;
1630     curr = list;
1631     prev = &list;
1632     while (curr != NULL) {
1633       next = curr->next;
1634       upp = (UrlParamPtr) curr->data.ptrvalue;
1635       if (upp == NULL) {
1636         prev = &(curr->next);
1637         curr = next;
1638         continue;
1639       }
1640       if (StringICmp (upp->group, group) == 0) {
1641         *prev = next;
1642         curr->next = NULL;
1643         ValNodeLink (&head, curr);
1644       } else {
1645         prev = &(curr->next);
1646       }
1647       curr = next;
1648     }
1649     ppt = list;
1650   }
1651   return head;
1652 }
1653 
1654 static void BuildArgumentForm (NewObjectPtr nop, BaseFormPtr bfp, Int2 which)
1655 
1656 {
1657   ButtoN             b;
1658   ButtoN             btn;
1659   GrouP              c;
1660   Char               ch;
1661   CharPtr            def;
1662   Int2               delta;
1663   TexT               first = NULL;
1664   GrouP              g;
1665   GrouP              grp;
1666   GrouP              h;
1667   ValNodePtr         hlp;
1668   Int2               i;
1669   CharPtr            itms;
1670   CharPtr            last;
1671   CharPtr            lastGroup = " ";
1672   LisT               lst;
1673   GrouP              m;
1674   Int2               max;
1675   Int2               min;
1676   ValNodePtr         moveMe = NULL;
1677   Nlm_Handle         obj1, obj2;
1678   PopuP              pop;
1679   PrompT             prmpt;
1680   ValNodePtr         ppt;
1681   CharPtr            ptr;
1682   RecT               r;
1683   StdEditorProcsPtr  sepp;
1684   CharPtr            str;
1685   Char               tmp [128];
1686   TexT               txt;
1687   UrlArgFormPtr      ufp;
1688   UrlParamPtr        upp;
1689   Int2               val;
1690   ValNodePtr         vnp;
1691   WindoW             w;
1692 
1693   if (nop == NULL || bfp == NULL) return;
1694   ufp = (UrlArgFormPtr) MemNew (sizeof (UrlArgForm));
1695   if (ufp == NULL) return;
1696 
1697   nop->paramlist = RearrangeParamList (nop->paramlist);
1698 
1699   w = FixedWindow (-50, -33, -10, -10, "Arguments", NULL);
1700   SetObjectExtra (w, ufp, CleanupArgumentForm);
1701   ufp->form = (ForM) w;
1702   ufp->formmessage = ArgumentFormMessage;
1703 
1704   sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
1705   if (sepp != NULL) {
1706     SetActivate (w, sepp->activateForm);
1707     ufp->appmessage = sepp->handleMessages;
1708   }
1709 
1710   ufp->bfp = bfp;
1711   ufp->nop = nop;
1712   ufp->which = which;
1713 
1714   m = HiddenGroup (w, 1, 0, NULL);
1715 
1716   g = NULL;
1717   for (ppt = nop->paramlist;
1718        ppt != NULL;
1719        ppt = ppt->next) {
1720     upp = (UrlParamPtr) ppt->data.ptrvalue;
1721     if (upp == NULL) continue;
1722     if (StringICmp (upp->group, lastGroup) != 0) {
1723       if (StringHasNoText (upp->group)) {
1724         if (StringHasNoText (lastGroup)) {
1725           g = HiddenGroup (m, 3, 0, NULL);
1726         } else {
1727           g = NormalGroup (m, 3, 0, "", programFont, NULL);
1728         }
1729       } else {
1730         g = NormalGroup (m, 3, 0, upp->group, programFont, NULL);
1731       }
1732       lastGroup = upp->group;
1733     }
1734     if (g == NULL) {
1735       g = HiddenGroup (m, 3, 0, NULL);
1736     }
1737     switch (upp->type) {
1738       case 1 :
1739         str = upp->prompt;
1740         StaticPrompt (g, str, 0, dialogTextHeight, programFont, 'l');
1741         def = upp->dfault;
1742         if (StringHasNoText (def)) {
1743           def = "";
1744         }
1745         txt = DialogText (g, def, 10, NULL);
1746         if (first == NULL) {
1747           first = txt;
1748         }
1749         ValNodeAddPointer (&(ufp->controls), 1, (Pointer) txt);
1750         ValNodeAddPointer (&moveMe, 0, (Pointer) txt);
1751         b = PushButton (g, "?", ShowArgumentHelp);
1752         SetObjectExtra (b, ufp, NULL);
1753         ValNodeAddPointer (&(ufp->helps), 0, (Pointer) b);
1754         break;
1755       case 2 :
1756         str = upp->prompt;
1757         btn = CheckBox (g, str, NULL);
1758         def = upp->dfault;
1759         if (StringICmp (def, "TRUE") == 0) {
1760           SetStatus (btn, TRUE);
1761         }
1762         prmpt = StaticPrompt (g, "", 0, 0, programFont, 'l');
1763         ValNodeAddPointer (&moveMe, 0, (Pointer) prmpt);
1764         ValNodeAddPointer (&(ufp->controls), 2, (Pointer) btn);
1765         b = PushButton (g, "?", ShowArgumentHelp);
1766         SetObjectExtra (b, ufp, NULL);
1767         ValNodeAddPointer (&(ufp->helps), 0, (Pointer) b);
1768         break;
1769       case 3 :
1770         str = upp->prompt;
1771         StaticPrompt (g, str, 0, dialogTextHeight, programFont, 'l');
1772         h = HiddenGroup (g, 1, 0, NULL);
1773         pop = PopupList (h, TRUE, NULL);
1774         def = upp->dfault;
1775         val = 0;
1776         i = 0;
1777         itms = upp->choices;
1778         StringNCpy_0 (tmp, itms, sizeof (tmp));
1779         last = tmp;
1780         ptr = last;
1781         ch = *ptr;
1782         while (ch != '\0') {
1783           if (ch == ',') {
1784             *ptr = '\0';
1785             PopupItem (pop, last);
1786             i++;
1787             if (StringICmp (def, last) == 0) {
1788               val = i;
1789             }
1790             ptr++;
1791             last = ptr;
1792             ch = *ptr;
1793           } else {
1794             ptr++;
1795             ch = *ptr;
1796           }
1797         }
1798         if (! StringHasNoText (last)) {
1799           PopupItem (pop, last);
1800           i++;
1801           if (StringICmp (def, last) == 0) {
1802             val = i;
1803           }
1804         }
1805         if (val > 0) {
1806           SetValue (pop, val);
1807         }
1808         ValNodeAddPointer (&(ufp->controls), 3, (Pointer) pop);
1809         ValNodeAddPointer (&moveMe, 0, (Pointer) pop);
1810         b = PushButton (g, "?", ShowArgumentHelp);
1811         SetObjectExtra (b, ufp, NULL);
1812         ValNodeAddPointer (&(ufp->helps), 0, (Pointer) b);
1813         break;
1814       case 4 :
1815         str = upp->prompt;
1816         StaticPrompt (g, str, 0, dialogTextHeight, programFont, 'l');
1817         h = HiddenGroup (g, 1, 0, NULL);
1818         grp = HiddenGroup (h, -5, 0, NULL);
1819         def = upp->dfault;
1820         val = 0;
1821         i = 0;
1822         itms = upp->choices;
1823         StringNCpy_0 (tmp, itms, sizeof (tmp));
1824         last = tmp;
1825         ptr = last;
1826         ch = *ptr;
1827         while (ch != '\0') {
1828           if (ch == ',') {
1829             *ptr = '\0';
1830             RadioButton (grp, last);
1831             i++;
1832             if (StringICmp (def, last) == 0) {
1833               val = i;
1834             }
1835             ptr++;
1836             last = ptr;
1837             ch = *ptr;
1838           } else {
1839             ptr++;
1840             ch = *ptr;
1841           }
1842         }
1843         if (! StringHasNoText (last)) {
1844           RadioButton (grp, last);
1845           i++;
1846           if (StringICmp (def, last) == 0) {
1847             val = i;
1848           }
1849         }
1850         if (val > 0) {
1851           SetValue (grp, val);
1852         }
1853         ValNodeAddPointer (&(ufp->controls), 4, (Pointer) grp);
1854         ValNodeAddPointer (&moveMe, 0, (Pointer) grp);
1855         b = PushButton (g, "?", ShowArgumentHelp);
1856         SetObjectExtra (b, ufp, NULL);
1857         ValNodeAddPointer (&(ufp->helps), 0, (Pointer) b);
1858         break;
1859       case 5 :
1860         str = upp->prompt;
1861         StaticPrompt (g, str, 0, dialogTextHeight, programFont, 'l');
1862         h = HiddenGroup (g, 1, 0, NULL);
1863         lst = SingleList (h, 10, 3, NULL);
1864         def = upp->dfault;
1865         val = 0;
1866         i = 0;
1867         itms = upp->choices;
1868         StringNCpy_0 (tmp, itms, sizeof (tmp));
1869         last = tmp;
1870         ptr = last;
1871         ch = *ptr;
1872         while (ch != '\0') {
1873           if (ch == ',') {
1874             *ptr = '\0';
1875             ListItem (lst, last);
1876             i++;
1877             if (StringICmp (def, last) == 0) {
1878               val = i;
1879             }
1880             ptr++;
1881             last = ptr;
1882             ch = *ptr;
1883           } else {
1884             ptr++;
1885             ch = *ptr;
1886           }
1887         }
1888         if (! StringHasNoText (last)) {
1889           ListItem (lst, last);
1890           i++;
1891           if (StringICmp (def, last) == 0) {
1892             val = i;
1893           }
1894         }
1895         if (val > 0) {
1896           SetValue (lst, val);
1897         }
1898         ValNodeAddPointer (&(ufp->controls), 5, (Pointer) lst);
1899         ValNodeAddPointer (&moveMe, 0, (Pointer) lst);
1900         b = PushButton (g, "?", ShowArgumentHelp);
1901         SetObjectExtra (b, ufp, NULL);
1902         ValNodeAddPointer (&(ufp->helps), 0, (Pointer) b);
1903         break;
1904       default :
1905         break;
1906     }
1907   }
1908 
1909   min = 0;
1910   max = 0;
1911   for (vnp = moveMe; vnp != NULL; vnp = vnp->next) {
1912     obj1 = (Nlm_Handle) vnp->data.ptrvalue;
1913     GetPosition (obj1, &r);
1914     min = MAX (min, r.left);
1915   }
1916   for (vnp = moveMe; vnp != NULL; vnp = vnp->next) {
1917     obj1 = (Nlm_Handle) vnp->data.ptrvalue;
1918     GetPosition (obj1, &r);
1919     delta = min - r.left;
1920     OffsetRect (&r, delta, 0);
1921     SetPosition (obj1, &r);
1922     AdjustPrnt (obj1, &r, FALSE);
1923     max = MAX (max, r.right);
1924   }
1925   max += 3;
1926   for (vnp = moveMe, hlp = ufp->helps;
1927        vnp != NULL && hlp != NULL;
1928        vnp = vnp->next, hlp = hlp->next) {
1929     obj2 = (Nlm_Handle) hlp->data.ptrvalue;
1930     GetPosition (obj2, &r);
1931     delta = max - r.left;
1932     OffsetRect (&r, delta, 0);
1933     SetPosition (obj2, &r);
1934     AdjustPrnt (obj2, &r, TRUE);
1935   }
1936 
1937   c = HiddenGroup (w, 2, 0, NULL);
1938   SetGroupSpacing (c, 10, 3);
1939   b = DefaultButton (c, "Accept", AcceptArgumentFormProc);
1940   SetObjectExtra (b, ufp, NULL);
1941   PushButton (c, "Cancel", StdCancelButtonProc);
1942 
1943   AlignObjects (ALIGN_CENTER, (HANDLE) m, (HANDLE) c, NULL);
1944   RealizeWindow (w);
1945   Show (w);
1946   Select (w);
1947   if (first != NULL) {
1948     Select (first);
1949   }
1950 }
1951 
1952 static void DoURLProc (IteM i)
1953 
1954 {
1955   CharPtr       args = NULL;
1956   BaseFormPtr   bfp;
1957   size_t        len;
1958   NewObjectPtr  nop;
1959   Int2          which;
1960 
1961   nop = (NewObjectPtr) GetObjectExtra (i);
1962   if (nop == NULL) return;
1963 #ifdef WIN_MAC
1964   bfp = (BaseFormPtr) currentFormDataPtr;
1965 #else
1966   bfp = nop->bfp;
1967 #endif
1968   if (bfp == NULL) return;
1969   which = BioseqViewOrDocSumChoice (nop);
1970   if (nop->paramlist == NULL) {
1971     len = StringLen (nop->prefix) + StringLen (nop->suffix);
1972     if (len > 0) {
1973       args = MemNew (sizeof (Char) * (len + 2));
1974       StringCpy (args, nop->prefix);
1975       if (! StringHasNoText (nop->suffix)) {
1976         StringCat (args, "&");
1977         StringCat (args, nop->suffix);
1978       }
1979     }
1980     DoAnalysisProc (nop, bfp, which, args, NULL);
1981   } else {
1982     BuildArgumentForm (nop, bfp, which);
1983   }
1984 }
1985 
1986 extern void EnableAnalysisItems (BaseFormPtr bfp, Boolean isDocSum)
1987 
1988 {
1989   Boolean       hasFastaNuc;
1990   Boolean       hasFastaProt;
1991   NewObjectPtr  nop;
1992 
1993   if (bfp == NULL) return;
1994 #ifdef WIN_MAC
1995   nop = (NewObjectPtr) macUserDataPtr;
1996 #else
1997   nop = (NewObjectPtr) bfp->userDataPtr;
1998 #endif
1999   if (isDocSum) {
2000   } else {
2001   }
2002   while (nop != NULL) {
2003     if (nop->kind == 1) {
2004       /* annotate menu item, ignore it */
2005     } else if (isDocSum) {
2006       if (nop->dsmOK) {
2007         /*
2008         hasFastaNuc = DocSumCanSaveFasta (bfp->form, TRUE, FALSE);
2009         hasFastaProt = DocSumCanSaveFasta (bfp->form, FALSE, TRUE);
2010         if (nop->fastaNucOK && hasFastaNuc) {
2011           SafeEnable (nop->item);
2012         } else if (nop->fastaProtOK && hasFastaProt) {
2013           SafeEnable (nop->item);
2014         } else {
2015           SafeDisable (nop->item);
2016         }
2017         */
2018         SafeDisable (nop->item);
2019       } else {
2020         SafeDisable (nop->item);
2021       }
2022     } else {
2023       if (nop->bspOK) {
2024         hasFastaNuc = BioseqViewCanSaveFasta (bfp->form, TRUE, FALSE, nop->onlyBspTarget);
2025         hasFastaProt = BioseqViewCanSaveFasta (bfp->form, FALSE, TRUE, nop->onlyBspTarget);
2026         if (nop->fastaNucOK && hasFastaNuc) {
2027           SafeEnable (nop->item);
2028         } else if (nop->fastaProtOK && hasFastaProt) {
2029           SafeEnable (nop->item);
2030         } else {
2031           SafeDisable (nop->item);
2032         }
2033       } else {
2034         SafeDisable (nop->item);
2035       }
2036     }
2037     nop = nop->next;
2038   }
2039 }
2040 
2041 static VoidPtr LinkNewObjectLists (NewObjectPtr list1, NewObjectPtr list2)
2042 
2043 {
2044   NewObjectPtr  nop;
2045 
2046   if (list1 == NULL) return list2;
2047   nop = list1;
2048   while (nop->next != NULL) {
2049     nop = nop->next;
2050   }
2051   nop->next = list2;
2052   return list1;
2053 }
2054 
2055 static void CleanupAnalysisExtraProc (GraphiC g, VoidPtr data)
2056 
2057 {
2058   NewObjectPtr  nop;
2059   ValNodePtr    ppt;
2060   UrlParamPtr   upp;
2061 
2062   nop = (NewObjectPtr) data;
2063   if (nop != NULL) {
2064     MemFree (nop->host_machine);
2065     MemFree (nop->host_path);
2066     for (ppt = nop->paramlist; ppt != NULL; ppt = ppt->next) {
2067       upp = (UrlParamPtr) ppt->data.ptrvalue;
2068       if (upp == NULL) continue;
2069       MemFree (upp->param);
2070       MemFree (upp->prompt);
2071       MemFree (upp->dfault);
2072       MemFree (upp->choices);
2073       MemFree (upp->group);
2074       MemFree (upp->help);
2075     }
2076     ValNodeFreeData (nop->paramlist);
2077     MemFree (nop->prefix);
2078     MemFree (nop->suffix);
2079   }
2080   MemFree (data);
2081 }
2082 
2083 typedef struct sbstruc {
2084   CharPtr    name;
2085   MenU       menu;
2086 } Sbstruc, PNTR SbstrucPtr;
2087 
2088 static ValNodePtr  analysissubmenulist = NULL;
2089 
2090 static void AddAnalysisItem (MenU m, BaseFormPtr bfp,
2091                              Boolean bspviewOK, Boolean docsumOK,
2092                              Boolean nucOK, Boolean protOK, Boolean onlyBspTarget,
2093                              CharPtr host_machine, Uint2 host_port,
2094                              CharPtr host_path, CharPtr program,
2095                              Uint2 timeoutsec, Int2 format, Boolean demomode,
2096                              QueryResultProc resultproc, ValNodePtr paramlist,
2097                              CharPtr prefix, CharPtr suffix,
2098                              CharPtr title, CharPtr submenu,
2099                              ItmActnProc actn, NewObjectPtr PNTR head)
2100 
2101 {
2102   IteM          i;
2103   NewObjectPtr  last;
2104   size_t        len;
2105   NewObjectPtr  nop;
2106   SbstrucPtr    sbp;
2107   CharPtr       tmp;
2108   ValNodePtr    vnp;
2109   MenU          x;
2110 
2111   if (m == NULL || actn == NULL) return;
2112   x = NULL;
2113   if (! StringHasNoText (submenu)) {
2114     vnp = analysissubmenulist;
2115     while (vnp != NULL && x == NULL) {
2116       sbp = (SbstrucPtr) vnp->data.ptrvalue;
2117       if (sbp != NULL && StringICmp (sbp->name, submenu) == 0) {
2118         x = sbp->menu;
2119       }
2120       vnp = vnp->next;
2121     }
2122     if (x == NULL) {
2123       sbp = (SbstrucPtr) MemNew (sizeof (Sbstruc));
2124       if (sbp != NULL) {
2125         sbp->name = StringSave (submenu);
2126         sbp->menu = SubMenu (m, sbp->name);
2127         x = sbp->menu;
2128         ValNodeAddPointer (&analysissubmenulist, 0, (VoidPtr) sbp);
2129       }
2130     }
2131   }
2132   if (x == NULL) {
2133     x = m;
2134   }
2135   i = CommandItem (x, title, actn);
2136   nop = (NewObjectPtr) MemNew (sizeof (NewObjectData));
2137   if (nop != NULL) {
2138     nop->kind = 2; /* analysis menu item */
2139     nop->bfp = bfp;
2140     nop->item = i;
2141     nop->bspOK = bspviewOK;
2142     nop->dsmOK = docsumOK;
2143     nop->fastaNucOK = nucOK;
2144     nop->fastaProtOK = protOK;
2145     nop->onlyBspTarget = onlyBspTarget;
2146     nop->host_machine = /* StrSaveNoNullEncodeSpaces */ StringSave (host_machine);
2147     nop->host_port = host_port;
2148     len = StringLen (host_path);
2149     tmp = MemNew (len + StringLen (program) + 5);
2150     if (tmp != NULL) {
2151       StringCpy (tmp, host_path);
2152       if (len > 1 && tmp [len - 1] != '/') {
2153         StringCat (tmp, "/");
2154       }
2155       StringCat (tmp, program);
2156     }
2157     nop->host_path = /* StrSaveNoNullEncodeSpaces */ StringSave (tmp);
2158     MemFree (tmp);
2159     nop->query = NULL;
2160     /*
2161     nop->host_path = StrSaveNoNullEncodeSpaces (host_path);
2162     nop->query = StrSaveNoNullEncodeSpaces (program);
2163     */
2164     nop->timeoutsec = timeoutsec;
2165     nop->format = format;
2166     nop->demomode = demomode;
2167     nop->resultproc = resultproc;
2168     nop->paramlist = paramlist;
2169     nop->prefix = StringSaveNoNull (prefix);
2170     nop->suffix = StringSaveNoNull (suffix);
2171   }
2172   SetObjectExtra (i, (Pointer) nop, CleanupAnalysisExtraProc);
2173   if (head == NULL) return;
2174   last = *head;
2175   if (last != NULL) {
2176     while (last->next != NULL) {
2177      last = last->next;
2178     }
2179     last->next = nop;
2180   } else {
2181     *head = nop;
2182   }
2183 }
2184 
2185 /* Sample seqncgis.cnf/seqncgis.ini/.seqncgisrc/sequincgi.cfg config file.
2186    PATH can contain query (separated by ? symbol), or separate QUERY item can
2187    be used, or multiple QUERY and TITLE items can also be used.
2188 
2189 [SERVICES]
2190 PATH=mydisk:Common Files:services:
2191 
2192 [ORDER]
2193 ORDER_1=tRNAscan
2194 ORDER_2=Seg
2195 
2196 [tRNAscan]
2197 PROGRAM=testcgi.cgi?request=trnascan
2198 HOST=www.myserver.myschool.edu
2199 PORT=80
2200 PATH=/MyServices/cgi-bin/testcgi.cgi
2201 SUBMENU=Search
2202 FORMATIN=FASTA
2203 FLAGS=SEQ,NUC,TRG
2204 TIMEOUT=30
2205 
2206 [Seg]
2207 PROGRAM=segify
2208 HOST=www.myserver.myschool.edu
2209 PORT=80
2210 PATH=/MyServices/cgi-bin/testcgi.cgi
2211 FORMATIN=fasta
2212 FLAGS=SEQ,DOC,PRT,TRG
2213 SUBMENU=Secondary structure prediction
2214 PROMPT_1=Window Size
2215 PARAM_1=window
2216 DESCRIPTION_1=window size for determining low-complexity segments
2217 TYPE_1=text
2218 DEFAULT_1=12
2219 REQUIRED_1=FALSE
2220 IMPORTANCE_1=
2221 GROUP_1=Algorithm
2222 HELP_1=window size for determining low-complexity segments
2223 PROMPT_2=Trigger Complexity
2224 PARAM_2=trigger
2225 DESCRIPTION_2=trigger complexity for determining low-complexity segments
2226 TYPE_2=text
2227 DEFAULT_2=2.2
2228 REQUIRED_2=FALSE
2229 IMPORTANCE_2=
2230 GROUP_2=Algorithm
2231 HELP_2=trigger complexity for determining low-complexity segments
2232 ...
2233 
2234 [ENZYMES]
2235 ENZ_1=BamHI
2236 ENZ_2=EcoRI
2237 ENZ_3=HindIII
2238 
2239 */
2240 
2241 static Int2 GetServiceParam (ValNodePtr head, CharPtr type, CharPtr buf, Int2 buflen)
2242 
2243 {
2244   size_t      len;
2245   Boolean     seenBracket = FALSE;
2246   CharPtr     str;
2247   ValNodePtr  vnp;
2248 
2249   if (buf == NULL || buflen <= 0) return 0;
2250   *buf = '\0';
2251   len = StringLen (type);
2252   for (vnp = head; vnp != NULL; vnp = vnp->next) {
2253     str = (CharPtr) vnp->data.ptrvalue;
2254     if (str != NULL) {
2255       if (str [0] == '[') {
2256         if (seenBracket) return 0;
2257         seenBracket = TRUE;
2258       } else if (StringNICmp (str, type, len) == 0) {
2259         str += len;
2260         StringNCpy_0 (buf, str, buflen);
2261         return (Int2) StringLen (buf);
2262       }
2263     }
2264   }
2265   return 0;
2266 }
2267 
2268 static ValNodePtr GetConfigParamAndPromptLists (CharPtr sect)
2269 
2270 {
2271   Int2         i;
2272   ValNodePtr   paramlist = NULL;
2273   Uint1        paramtype;
2274   Char         title [512];
2275   Char         tmp [32];
2276   UrlParamPtr  upp;
2277 
2278   if (sect == NULL) return NULL;
2279   i = 1;
2280   sprintf (tmp, "PARAM_%d", (int) i);
2281   while (GetAppParam ("SEQNCGIS", sect, tmp, NULL, title, sizeof (title) - 1)) {
2282     upp = (UrlParamPtr) MemNew (sizeof (UrlParamData));
2283     if (upp == NULL) continue;
2284     upp->param = StringSave (title);
2285     sprintf (tmp, "TYPE_%d", (int) i);
2286     paramtype = 1;
2287     if (GetAppParam ("SEQNCGIS", sect, tmp, NULL, title, sizeof (title) - 1)) {
2288       if (StringICmp (title, "text") == 0) {
2289         paramtype = 1;
2290       } else if (StringICmp (title, "checkbox") == 0) {
2291         paramtype = 2;
2292       } else if (StringICmp (title, "popup") == 0) {
2293         paramtype = 3;
2294       } else if (StringICmp (title, "radio") == 0) {
2295         paramtype = 4;
2296       } else if (StringICmp (title, "list") == 0) {
2297         paramtype = 5;
2298       }
2299     }
2300     upp->type = paramtype;
2301     sprintf (tmp, "PROMPT_%d", (int) i);
2302     if (GetAppParam ("SEQNCGIS", sect, tmp, NULL, title, sizeof (title) - 1)) {
2303       upp->prompt = StringSave (title);
2304     } else {
2305       upp->prompt = StringSave (upp->param);
2306     }
2307     sprintf (tmp, "DEFAULT_%d", (int) i);
2308     if (GetAppParam ("SEQNCGIS", sect, tmp, NULL, title, sizeof (title) - 1)) {
2309       upp->dfault = StringSave (title);
2310     } else {
2311       upp->dfault = StringSave (" ");
2312     }
2313     sprintf (tmp, "CHOICES_%d", (int) i);
2314     if (GetAppParam ("SEQNCGIS", sect, tmp, NULL, title, sizeof (title) - 1)) {
2315       upp->choices = StringSave (title);
2316     } else {
2317       upp->choices = StringSave (" ");
2318     }
2319     sprintf (tmp, "GROUP_%d", (int) i);
2320     if (GetAppParam ("SEQNCGIS", sect, tmp, NULL, title, sizeof (title) - 1)) {
2321       upp->group = StringSave (title);
2322     } else {
2323       upp->group = StringSave (" ");
2324     }
2325     sprintf (tmp, "HELP_%d", (int) i);
2326     if (GetAppParam ("SEQNCGIS", sect, tmp, NULL, title, sizeof (title) - 1)) {
2327       upp->help = StringSave (title);
2328     } else {
2329       upp->help = StringSave (" ");
2330     }
2331     ValNodeAddPointer (&paramlist, i, (Pointer) upp);
2332     i++;
2333     sprintf (tmp, "PARAM_%d", (int) i);
2334   }
2335   return paramlist;
2336 }
2337 
2338 static ValNodePtr GetServiceParamAndPromptLists (ValNodePtr list)
2339 
2340 {
2341   Int2         i;
2342   ValNodePtr   paramlist = NULL;
2343   Uint1        paramtype;
2344   Char         title [512];
2345   Char         tmp [32];
2346   UrlParamPtr  upp;
2347 
2348   if (list == NULL) return NULL;
2349   i = 1;
2350   sprintf (tmp, "PARAM_%d=", (int) i);
2351   while (GetServiceParam (list, tmp, title, sizeof (title) - 1)) {
2352     upp = (UrlParamPtr) MemNew (sizeof (UrlParamData));
2353     if (upp == NULL) continue;
2354     upp->param = StringSave (title);
2355     sprintf (tmp, "TYPE_%d", (int) i);
2356     paramtype = 1;
2357     if (GetServiceParam (list, tmp, title, sizeof (title) - 1)) {
2358       if (StringICmp (title, "text") == 0) {
2359         paramtype = 1;
2360       } else if (StringICmp (title, "checkbox") == 0) {
2361         paramtype = 2;
2362       } else if (StringICmp (title, "popup") == 0) {
2363         paramtype = 3;
2364       } else if (StringICmp (title, "radio") == 0) {
2365         paramtype = 4;
2366       } else if (StringICmp (title, "list") == 0) {
2367         paramtype = 5;
2368       }
2369     }
2370     upp->type = paramtype;
2371     sprintf (tmp, "PROMPT_%d=", (int) i);
2372     if (GetServiceParam (list, tmp, title, sizeof (title) - 1)) {
2373       upp->prompt = StringSave (title);
2374     } else {
2375       upp->prompt = StringSave (upp->param);
2376     }
2377     sprintf (tmp, "DEFAULT_%d=", (int) i);
2378     if (GetServiceParam (list, tmp, title, sizeof (title) - 1)) {
2379       upp->dfault = StringSave (title);
2380     } else {
2381       upp->dfault = StringSave (" ");
2382     }
2383     sprintf (tmp, "CHOICES_%d=", (int) i);
2384     if (GetServiceParam (list, tmp, title, sizeof (title) - 1)) {
2385       upp->choices = StringSave (title);
2386     } else {
2387       upp->choices = StringSave (" ");
2388     }
2389     sprintf (tmp, "GROUP_%d=", (int) i);
2390     if (GetServiceParam (list, tmp, title, sizeof (title) - 1)) {
2391       upp->group = StringSave (title);
2392     } else {
2393       upp->group = StringSave (" ");
2394     }
2395     sprintf (tmp, "HELP_%d=", (int) i);
2396     if (GetServiceParam (list, tmp, title, sizeof (title) - 1)) {
2397       upp->help = StringSave (title);
2398     } else {
2399       upp->help = StringSave (" ");
2400     }
2401     ValNodeAddPointer (&paramlist, i, (Pointer) upp);
2402     i++;
2403     sprintf (tmp, "PARAM_%d=", (int) i);
2404   }
2405   return paramlist;
2406 }
2407 
2408 static void ReadAnalysisConfigFile (CharPtr sect, MenU m, BaseFormPtr bfp,
2409                                     Boolean bspviewOK, Boolean docsumOK,
2410                                     NewObjectPtr PNTR head)
2411 
2412 {
2413   Boolean     demomode = FALSE;
2414   Int2        format = 1;
2415   Char        host [128];
2416   Boolean     nucOK = FALSE;
2417   Boolean     onlyBspTarget = FALSE;
2418   ValNodePtr  paramlist = NULL;
2419   Char        program [128];
2420   Char        path [256];
2421   Uint2       port = 80;
2422   Char        prefix [128];
2423   Boolean     protOK = FALSE;
2424   Char        submenu [128];
2425   Char        suffix [128];
2426   Uint2       timeoutsec = 30;
2427   Char        title [128];
2428   Char        tmp [32];
2429   unsigned    int  val;
2430 
2431   if (! GetAppParam ("SEQNCGIS", sect, "TITLE", NULL, title, sizeof (title) - 1)) {
2432     StringNCpy_0 (title, sect, sizeof (title));
2433   }
2434   if (GetAppParam ("SEQNCGIS", sect, "HOST", NULL, host, sizeof (host) - 1)) {
2435     if (GetAppParam ("SEQNCGIS", sect, "FLAGS", NULL, tmp, sizeof (tmp) - 1)) {
2436       if (StringStr (tmp, "SEQ") == NULL) {
2437         bspviewOK = FALSE;
2438       }
2439       if (StringStr (tmp, "DOC") == NULL) {
2440         docsumOK = FALSE;
2441       }
2442       if (StringStr (tmp, "NUC") != NULL) {
2443         nucOK = TRUE;
2444       }
2445       if (StringStr (tmp, "PRT") != NULL) {
2446         protOK = TRUE;
2447       }
2448       if (StringStr (tmp, "TRG") != NULL) {
2449         onlyBspTarget = TRUE;
2450       }
2451     }
2452 
2453     if ((! bspviewOK) && (! docsumOK)) return;
2454 
2455     if (GetAppParam ("SEQNCGIS", sect, "PORT", NULL, tmp, sizeof (tmp) - 1) && 
2456         sscanf (tmp, "%u", &val) == 1) {
2457       port = (Uint2) val;
2458     } else {
2459       port = 80;
2460     }
2461     if (GetAppParam ("SEQNCGIS", sect, "FORMATIN", NULL, tmp, sizeof (tmp) - 1)) {
2462       if (StringICmp (tmp, "FASTA") == 0) {
2463         format = 1;
2464       } else if (StringICmp (tmp, "ASN.1") == 0) {
2465         format = 2;
2466       }
2467     }
2468     if (GetAppParam ("SEQNCGIS", sect, "TIMEOUT", NULL, tmp, sizeof (tmp) - 1) && 
2469         sscanf (tmp, "%u", &val) == 1) {
2470       timeoutsec = (Uint2) val;
2471     } else {
2472       timeoutsec = 30;
2473     }
2474     submenu [0] = '\0';
2475     GetAppParam ("SEQNCGIS", sect, "SUBMENU", NULL, submenu, sizeof (submenu) - 1);
2476     if (GetAppParam ("SEQNCGIS", sect, "DEMO", NULL, tmp, sizeof (tmp) - 1)) {
2477       if (StringICmp (tmp, "TRUE") == 0) {
2478         demomode = TRUE;
2479       }
2480     }
2481 
2482     if (GetAppParam ("SEQNCGIS", sect, "PATH", NULL, path, sizeof (path) - 1)) {
2483       if (GetAppParam ("SEQNCGIS", sect, "PROGRAM", NULL, program, sizeof (program) - 1)) {
2484         paramlist = GetConfigParamAndPromptLists (sect);
2485         prefix [0] = '\0';
2486         GetAppParam ("SEQNCGIS", sect, "PREFIX", NULL, prefix, sizeof (prefix) - 1);
2487         suffix [0] = '\0';
2488         GetAppParam ("SEQNCGIS", sect, "SUFFIX", NULL, suffix, sizeof (suffix) - 1);
2489         AddAnalysisItem (m, bfp, bspviewOK, docsumOK,
2490                          nucOK, protOK, onlyBspTarget,
2491                          host, port, path, program, timeoutsec, format, demomode,
2492                          SequinHandleURLResults, paramlist, prefix, suffix,
2493                          title, submenu, DoURLProc, head);
2494       }
2495     }
2496   }
2497 }
2498 
2499 static void ReadServiceConfigFile (CharPtr pathbase, ValNodePtr config,
2500                                    MenU m, BaseFormPtr bfp,
2501                                    Boolean bspviewOK, Boolean docsumOK,
2502                                    NewObjectPtr PNTR head)
2503 
2504 {
2505   Char          ch;
2506   Boolean       demomode = FALSE;
2507   Int2          format = 1;
2508   FILE          *fp;
2509   Boolean       goOn = TRUE;
2510   Char          host [128];
2511   Boolean       keepGoing;
2512   ValNodePtr    list = NULL;
2513   Boolean       nucOK = FALSE;
2514   Boolean       onlyBspTarget = FALSE;
2515   ValNodePtr    paramlist = NULL;
2516   Char          program [128];
2517   Char          path [PATH_MAX];
2518   Uint2         port = 80;
2519   Char          prefix [128];
2520   Boolean       protOK = FALSE;
2521   CharPtr       ptr;
2522   Boolean       seenBracket;
2523   Char          str [256];
2524   Char          submenu [128];
2525   Char          suffix [128];
2526   Uint2         timeoutsec = 30;
2527   Char          title [128];
2528   Char          tmp [32];
2529   unsigned int  val;
2530   ValNodePtr    vnp;
2531 
2532   if (path == NULL || config == NULL || config->data.ptrvalue == NULL) return;
2533   StringNCpy_0 (path, pathbase, sizeof (path));
2534   FileBuildPath (path, NULL, (CharPtr) config->data.ptrvalue);
2535   fp = FileOpen (path, "r");
2536   if (fp == NULL) return;
2537   while (FileGets (str, sizeof (str), fp) != NULL) {
2538     ptr = str;
2539     ch = *ptr;
2540     while (ch != '\0' && ch != '\n' && ch != '\r') {
2541       ptr++;
2542       ch = *ptr;
2543     }
2544     *ptr = '\0';
2545     ValNodeCopyStr (&list, 1, str);
2546   }
2547   FileClose (fp);
2548   while (goOn) {
2549     goOn = FALSE;
2550     title [0] = '\0';
2551     if (GetServiceParam (list, "TITLE=", tmp, sizeof (tmp) - 1)) {
2552       StringNCpy_0 (title, tmp, sizeof (title));
2553     }
2554     if (StringHasNoText (title)) {
2555       if (GetServiceParam (list, "[", title, sizeof (title) - 1)) {
2556         ptr = StringChr (title, ']');
2557         if (ptr != NULL) {
2558           *ptr = '\0';
2559         }
2560       }
2561     }
2562     if (title [0] != '\0' && GetServiceParam (list, "HOST=", host, sizeof (host) - 1)) {
2563       if (GetServiceParam (list, "FLAGS=", tmp, sizeof (tmp) - 1)) {
2564         if (StringStr (tmp, "SEQ") == NULL) {
2565           bspviewOK= FALSE;
2566         }
2567         if (StringStr (tmp, "DOC") == NULL) {
2568           docsumOK= FALSE;
2569         }
2570         if (StringStr (tmp, "NUC") != NULL) {
2571           nucOK= TRUE;
2572         }
2573         if (StringStr (tmp, "PRT") != NULL) {
2574           protOK= TRUE;
2575         }
2576         if (StringStr (tmp, "TRG") != NULL) {
2577           onlyBspTarget= TRUE;
2578         }
2579       }
2580 
2581       if (bspviewOK || docsumOK) {
2582 
2583         if (GetServiceParam (list, "PORT=", tmp, sizeof (tmp) - 1) && 
2584             sscanf (tmp, "%u", &val) == 1) {
2585           port = (Uint2) val;
2586         } else {
2587           port = 80;
2588         }
2589         if (GetServiceParam (list, "FORMATIN=", tmp, sizeof (tmp) - 1)) {
2590           if (StringICmp (tmp, "FASTA") == 0) {
2591             format = 1;
2592           } else if (StringICmp (tmp, "ASN.1") == 0) {
2593             format = 2;
2594           }
2595         }
2596        if (GetServiceParam (list, "TIMEOUT=", tmp, sizeof (tmp) - 1) && 
2597             sscanf (tmp, "%u", &val) == 1) {
2598           timeoutsec = (Uint2) val;
2599         } else {
2600           timeoutsec = 30;
2601         }
2602         submenu [0] = '\0';
2603         GetServiceParam (list, "SUBMENU=", submenu, sizeof (submenu) - 1);
2604         if (GetServiceParam (list, "DEMO=", tmp, sizeof (tmp) - 1)) {
2605           if (StringICmp (tmp, "TRUE") == 0) {
2606             demomode = TRUE;
2607           }
2608         }
2609 
2610         if (GetServiceParam (list, "PATH=", path, sizeof (path) - 1)) {
2611           if (GetServiceParam (list, "PROGRAM=", program, sizeof (program) - 1)) {
2612             paramlist = GetServiceParamAndPromptLists (list);
2613             prefix [0] = '\0';
2614             GetServiceParam (list, "PREFIX=", prefix, sizeof (prefix) - 1);
2615             suffix [0] = '\0';
2616             GetServiceParam (list, "SUFFIX=", suffix, sizeof (suffix) - 1);
2617             AddAnalysisItem (m, bfp, bspviewOK, docsumOK,
2618                              nucOK, protOK, onlyBspTarget,
2619                              host, port, path, program, timeoutsec, format, demomode,
2620                              SequinHandleURLResults, paramlist, prefix, suffix,
2621                              title, submenu, DoURLProc, head);
2622           }
2623         }
2624 
2625       }
2626     }
2627 
2628     seenBracket = FALSE;
2629     keepGoing = TRUE;
2630     for (vnp = list; vnp != NULL && keepGoing; vnp = vnp->next) {
2631       ptr = (CharPtr) vnp->data.ptrvalue;
2632       if (ptr != NULL) {
2633         if (ptr [0] == '[') {
2634           if (seenBracket) {
2635             keepGoing = FALSE;
2636           } else {
2637             seenBracket = TRUE;
2638           }
2639         }
2640         if (keepGoing) {
2641           vnp->data.ptrvalue = MemFree (vnp->data.ptrvalue);
2642         }
2643       }
2644     }
2645 
2646   }
2647 
2648   ValNodeFreeData (list);
2649 }
2650 
2651 extern MenU CreateAnalysisMenu (WindoW w, BaseFormPtr bfp, Boolean bspviewOK, Boolean docsumOK)
2652 
2653 {
2654   NewObjectPtr  first;
2655   ValNodePtr    head1 = NULL, head2 = NULL;
2656   Int2          i;
2657   size_t        len;
2658   MenU          m;
2659   Char          path1 [PATH_MAX];
2660   Char          path2 [PATH_MAX];
2661   CharPtr       ptr;
2662   SbstrucPtr    sbp;
2663   Char          sect [256];
2664   Char          temp [32];
2665   ValNodePtr    vnp;
2666 
2667   ProgramPath (path1, sizeof (path1));
2668   ptr = StringRChr (path1, DIRDELIMCHR);
2669   if (ptr != NULL) {
2670     ptr++;
2671     *ptr = '\0';
2672   }
2673   FileBuildPath (path1, "services", NULL);
2674   head1 = DirCatalog (path1);
2675 
2676   if (GetAppParam ("SEQNCGIS", "SERVICES", "PATH", NULL, path2, sizeof (path2) - 1)) {
2677     len = StringLen (path2);
2678     if (path2 [len - 1] != DIRDELIMCHR) {
2679       StringCat (path2, DIRDELIMSTR);
2680     }
2681     if (StringCmp (path1, path2) != 0) {
2682       head2 = DirCatalog (path2);
2683     }
2684   }
2685 
2686   if ((! extraServices) && (! indexerVersion) && (! genomeCenter) &&
2687       head1 == NULL && head2 == NULL) {
2688     if (! GetAppParam ("SEQNCGIS", "ORDER", NULL, NULL, sect, sizeof (sect) - 1)) {
2689       return NULL;
2690     }
2691   }
2692   m = PulldownMenu (w, "Analysis");
2693   if (m == NULL) return NULL;
2694   analysissubmenulist = NULL;
2695   first = NULL;
2696   if (bspviewOK) {
2697     AddAnalysisItem (m, bfp, bspviewOK, FALSE, TRUE, FALSE, TRUE,
2698                      NULL, 0, NULL, NULL, 0, 0, FALSE, NULL, NULL, NULL, NULL,
2699                      "Restriction Search", "Search",
2700                      SimpleRsiteProc, &first);
2701     if (indexerVersion) {
2702       AddAnalysisItem (m, bfp, bspviewOK, FALSE, TRUE, FALSE, TRUE,
2703                        NULL, 0, NULL, NULL, 0, 0, FALSE, NULL, NULL, NULL, NULL,
2704                        "QBlast Test", "Search",
2705                        SimpleQBlastProc, &first);
2706     }
2707   }
2708   if (bspviewOK || docsumOK) {
2709     if (useEntrez) {
2710       i = 1;
2711       sprintf (temp, "ORDER_%d", (int) i);
2712       while (GetAppParam ("SEQNCGIS", "ORDER", temp, NULL, sect, sizeof (sect) - 1)) {
2713         ReadAnalysisConfigFile (sect, m, bfp, bspviewOK, docsumOK, &first);
2714         i++;
2715         sprintf (temp, "ORDER_%d", (int) i);
2716       }
2717       for (vnp = head1; vnp != NULL; vnp = vnp->next) {
2718         if (vnp->choice == 0) {
2719           ReadServiceConfigFile (path1, vnp, m, bfp, bspviewOK, docsumOK, &first);
2720         }
2721       }
2722       for (vnp = head2; vnp != NULL; vnp = vnp->next) {
2723         if (vnp->choice == 0) {
2724           ReadServiceConfigFile (path2, vnp, m, bfp, bspviewOK, docsumOK, &first);
2725         }
2726       }
2727     }
2728   }
2729   if (bspviewOK) {
2730   }
2731   if (docsumOK) {
2732   }
2733 #ifdef WIN_MAC
2734   macUserDataPtr = LinkNewObjectLists (macUserDataPtr, first);
2735 #else
2736   bfp->userDataPtr = LinkNewObjectLists (bfp->userDataPtr, first);
2737 #endif
2738   for (vnp = analysissubmenulist; vnp != NULL; vnp = vnp->next) {
2739     sbp = (SbstrucPtr) vnp->data.ptrvalue;
2740     if (sbp != NULL) {
2741       sbp->name = MemFree (sbp->name);
2742     }
2743   }
2744   analysissubmenulist = ValNodeFreeData (analysissubmenulist);
2745   ValNodeFreeData (head1);
2746   ValNodeFreeData (head2);
2747   return m;
2748 }
2749 
2750 /* NEW UPDATE SEQUENCE SECTION */
2751 
2752 
2753 #define SQN_LEFT    1
2754 #define SQN_RIGHT   2
2755 #define SQN_MIDDLE  3
2756 
2757 static Uint4 sqn_binary_search_on_uint4_list(Uint4Ptr list, Uint4 pos, Uint4 listlen)
2758 {
2759    Uint4  L;
2760    Uint4  mid;
2761    Uint4  R;
2762 
2763    if (list == NULL || listlen == 0)
2764       return 0;
2765    L = 0;
2766    R = listlen - 1;
2767    while (L < R)
2768    {
2769       mid = (L+R)/2;
2770       if (list[mid + 1] <= pos)
2771       {
2772          L = mid + 1;
2773       } else
2774       {
2775          R = mid;
2776       }
2777    }
2778    return R;
2779 }
2780 
2781 static Int4 MapRowCoordsSpecial(SeqAlignPtr sap, Uint4 pos, Int4 row, Int4 which_end)
2782 {
2783    DenseSegPtr  dsp;
2784    Int4         idx;
2785    Int4         offset;
2786    SAIndexPtr   saip;
2787    Int4         start;
2788 
2789    if (sap == NULL || row < 0)
2790       return -1;
2791    if (sap->saip == NULL)
2792       return -1;
2793    saip = (SAIndexPtr)sap->saip;
2794    dsp = (DenseSegPtr)sap->segs;
2795    start = sqn_binary_search_on_uint4_list(saip->aligncoords, pos, dsp->numseg);
2796    offset = pos - saip->aligncoords[start];
2797    idx = (dsp->dim*start) + row - 1;
2798    if (dsp->starts[idx] == -1)
2799    {
2800       if (which_end == SQN_RIGHT)
2801       {
2802          /* round down */
2803          while (start >= 0) {
2804             idx = (dsp->dim*start) + row - 1;
2805             if (dsp->starts[idx] != -1)
2806                return (dsp->starts[idx] + dsp->lens[start] - 1);
2807             start--;
2808          }
2809          return -2;
2810       } else if (which_end == SQN_LEFT)
2811       {
2812          /* round up */
2813          while (start < dsp->numseg) {
2814             idx = (dsp->dim*start) + row - 1;
2815             if (dsp->starts[idx] != -1)
2816                return (dsp->starts[idx]);
2817             start++;
2818          }
2819          return -2;
2820       }
2821    } else
2822    {
2823       idx = (dsp->dim*start) + row - 1;
2824       if (dsp->strands[idx] != Seq_strand_minus)
2825          return (dsp->starts[idx] + offset);
2826       else
2827          return (dsp->starts[idx] + dsp->lens[start] - 1 - offset);
2828    }
2829    return -1;
2830 }
2831 
2832 static Int4 MapBioseqToBioseqSpecial(SeqAlignPtr sap, Int4 begin, Int4 fin, Int4 pos, Int4 which_end)
2833 {
2834    Int4  bspos;
2835    Int4  sapos;
2836    Int4  start1;
2837    Int4  start2;
2838    Int4  stop1;
2839    Int4  stop2;
2840 
2841    if (sap == NULL || sap->saip == NULL)
2842       return -2;
2843    AlnMgr2GetNthSeqRangeInSA(sap, begin, &start1, &stop1);
2844    AlnMgr2GetNthSeqRangeInSA(sap, fin, &start2, &stop2);
2845    /* check to see whether the position is outside the alignment */
2846    if (pos < start1)
2847       return (start2 - (start1 - pos));
2848    else if (pos > stop1)
2849       return (stop2 + (pos-stop1));
2850    sapos = AlnMgr2MapBioseqToSeqAlign(sap, pos, begin);
2851    bspos = MapRowCoordsSpecial(sap, sapos, fin, which_end);
2852    if (bspos >= 0)
2853       return bspos;
2854    else if (which_end == SQN_LEFT)
2855       return (start2-1);
2856    else if (which_end == SQN_RIGHT)
2857       return (stop2+1);
2858    else
2859       return 0;
2860 }
2861 
2862 static void ListPhrapGraphsCallback (SeqGraphPtr sgp, Pointer userdata)
2863 {
2864   ValNodePtr PNTR vnpp;
2865   
2866   if (sgp == NULL || userdata == NULL) return;
2867   if (StringICmp (sgp->title, "Phrap Quality") == 0)
2868   {
2869     vnpp = (ValNodePtr PNTR) userdata;
2870     ValNodeAddPointer (vnpp, 0, sgp);
2871   }
2872 }
2873 
2874 /* THOUGHTS:
2875  * Can we/must we update quality scores before/after the old Bioseq has been replaced?
2876  * If we replace quality scores after the bioseq has been replaced, the oldbsp->length
2877  * is the length of the buffer we need to hold the quality scores,
2878  * otherwise use the newbsp->length.
2879  * Useful functions:
2880   aln_len = AlnMgr2GetAlnLength(salp, FALSE);
2881 
2882 NLM_EXTERN Int4 AlnMgr2GetNumAlnBlocks(SeqAlignPtr sap)
2883 NLM_EXTERN Boolean AlnMgr2GetNthBlockRange(SeqAlignPtr sap, Int4 n, Int4Ptr start, Int4Ptr stop)
2884   
2885   
2886  * Assumptions: data replacement has already taken place, oldbsp is in row 1 of salp,
2887  *              newbsp is in row 2 of salp.
2888  
2889  */
2890 static Boolean 
2891 ReplaceQualityScores
2892 (BioseqPtr   oldbsp,
2893  BioseqPtr   newbsp,
2894  FILE        *log_fp,
2895  BoolPtr     data_in_log)
2896 {
2897   ValNodePtr    oldhead = NULL, newhead = NULL, vnp;
2898   SeqGraphPtr   sgp, last_sgp = NULL, new_sgp;
2899   SeqAnnotPtr   sap, last_sap;
2900   Char          acc_str [256];
2901   
2902   if (oldbsp == NULL || newbsp == NULL
2903       || !ISA_na (oldbsp->mol) || !ISA_na (newbsp->mol))
2904   {
2905     return FALSE;
2906   }
2907 
2908   /* first, remove old scores */  
2909   VisitGraphsOnBsp (oldbsp, &oldhead, ListPhrapGraphsCallback);
2910   for (vnp = oldhead; vnp != NULL; vnp = vnp->next) 
2911   {
2912     sgp = vnp->data.ptrvalue;
2913     if (sgp != NULL)
2914     {
2915       sgp->idx.deleteme = TRUE;
2916     }
2917   }
2918   oldhead = ValNodeFree (oldhead);
2919   DeleteMarkedObjects (0, OBJ_BIOSEQ, (Pointer) oldbsp);
2920 
2921   /* now copy new quality scores to old sequence */
2922   VisitGraphsOnBsp (newbsp, &newhead, ListPhrapGraphsCallback);
2923   
2924   if (newhead == NULL)
2925   {
2926     if (log_fp != NULL && data_in_log != NULL) 
2927     {
2928       SeqIdWrite (oldbsp->id, acc_str, PRINTID_REPORT, sizeof (acc_str));
2929       fprintf (log_fp, "Quality scores cleared for %s\n", acc_str);
2930       *data_in_log = TRUE;
2931     }
2932   }
2933   else
2934   {
2935     /* now add in new phrap annotations */
2936     last_sap = NULL;
2937     last_sgp = NULL;
2938     for (sap = oldbsp->annot; sap != NULL && sap->type !=3; sap = sap->next) 
2939     {
2940       last_sap = sap;
2941     }
2942     
2943     if (sap == NULL)
2944     {
2945       sap = SeqAnnotNew ();
2946       sap->type = 3;
2947       sap->data = NULL;
2948       if (last_sap == NULL)
2949       {
2950         oldbsp->annot = sap;
2951       }
2952       else
2953       {
2954         last_sap->next = sap;
2955       }
2956     }
2957     
2958     
2959     for (sgp = (SeqGraphPtr) sap->data; sgp != NULL; sgp = sgp->next) 
2960     {
2961       last_sgp = sgp;  
2962     }
2963     for (vnp = newhead; vnp != NULL; vnp = vnp->next)
2964     {
2965       sgp = (SeqGraphPtr) vnp->data.ptrvalue;
2966       if (sgp != NULL) 
2967       {
2968         new_sgp = (SeqGraphPtr) AsnIoMemCopy (sgp, (AsnReadFunc) SeqGraphAsnRead, (AsnWriteFunc) SeqGraphAsnWrite);
2969         if (new_sgp != NULL) 
2970         {
2971           new_sgp->next = NULL;
2972           if (last_sgp == NULL) 
2973           {
2974             sap->data = new_sgp;
2975           }
2976           else
2977           {
2978             last_sgp->next = new_sgp;
2979           }
2980           last_sgp = new_sgp;
2981         }
2982       }
2983     }
2984     SeqIdWrite (oldbsp->id, acc_str, PRINTID_REPORT, sizeof (acc_str));
2985     fprintf (log_fp, "Replaced quality scores for %s\n", acc_str);
2986     *data_in_log = TRUE;
2987   }
2988 
2989   
2990   return TRUE;
2991 }
2992 
2993 
2994 extern void RemoveQualityScores 
2995 (BioseqPtr bsp, 
2996  FILE      *log_fp,
2997  BoolPtr   data_in_log)
2998 
2999 {
3000   ValNodePtr score_list = NULL, vnp;
3001   Char          acc_str [256];
3002   SeqGraphPtr   sgp;
3003 
3004   if (bsp == NULL) return;
3005 
3006   VisitGraphsOnBsp (bsp, &score_list, ListPhrapGraphsCallback);
3007   if (score_list == NULL) return;
3008 
3009   if (log_fp != NULL && data_in_log != NULL)
3010   {
3011     SeqIdWrite (bsp->id, acc_str, PRINTID_REPORT, sizeof (acc_str));
3012     fprintf (log_fp, "Quality scores cleared for %s\n", acc_str);
3013     *data_in_log = TRUE;
3014   }
3015 
3016   for (vnp = score_list; vnp != NULL; vnp = vnp->next) 
3017   {
3018     sgp = vnp->data.ptrvalue;
3019     if (sgp != NULL)
3020     {
3021       sgp->idx.deleteme = TRUE;
3022     }
3023   }
3024 
3025   score_list = ValNodeFree (score_list);
3026   DeleteMarkedObjects (0, OBJ_BIOSEQ, (Pointer) bsp);
3027 }
3028 
3029 
3030 #define SEQGRAPH_FloatHi    1
3031 #define SEQGRAPH_Int4       2
3032 #define SEQGRAPH_BS         3
3033 
3034 /* remove compression from SeqGraph */
3035 static Boolean ExpandSeqGraph (SeqGraphPtr sgp)
3036 {
3037   Int4    oldpos = 0, newpos = 0, i;
3038   Pointer new_values = NULL;
3039   Int4    new_numval;
3040   Int2    cur_byte;
3041 
3042   if (sgp == NULL || sgp->compr == 0 || sgp->compr == 1) {
3043     return TRUE;
3044   } else if (sgp->compr < 0) {
3045     return FALSE;
3046   }
3047 
3048   new_numval = sgp->numval * sgp->compr;
3049 
3050   /* allocate space for new values */
3051   switch (sgp->flags[2]) {
3052     case SEQGRAPH_FloatHi:
3053       new_values = MemNew (sizeof (FloatHi) * new_numval);
3054       break;
3055     case SEQGRAPH_Int4:
3056       new_values = MemNew (sizeof (Int4) * new_numval);
3057       break;
3058     case SEQGRAPH_BS:
3059       new_values = (Pointer) BSNew (new_numval);
3060       BSSeek ((ByteStorePtr)new_values, 0, SEEK_SET);
3061       BSSeek ((ByteStorePtr) sgp->values, 0, SEEK_SET);
3062       break;
3063   }
3064 
3065   /* copy and expand */
3066   while (oldpos < sgp->numval) {
3067     cur_byte = 0;
3068     if (sgp->flags[2] == SEQGRAPH_BS) {
3069       cur_byte = BSGetByte ((ByteStorePtr) sgp->values);
3070     }
3071     for (i = 0; i < sgp->compr; i++) {
3072       switch (sgp->flags[2]) {
3073         case SEQGRAPH_FloatHi:
3074           ((FloatHiPtr)new_values)[newpos++] = ((FloatHiPtr)sgp->values)[oldpos];
3075           break;
3076         case SEQGRAPH_Int4:
3077           ((Int4Ptr)new_values)[newpos++] = ((Int4Ptr)sgp->values)[oldpos];
3078           break;
3079         case SEQGRAPH_BS:
3080           BSPutByte ((ByteStorePtr) new_values, cur_byte);
3081           break;
3082       }
3083     }
3084     oldpos++;
3085   }
3086 
3087   /* free old values and replace with new */
3088   if (sgp->flags[2] == SEQGRAPH_BS) {
3089     sgp->values = BSFree ((ByteStorePtr) sgp->values);
3090   } else {    
3091     sgp->values = MemFree (sgp->values);    
3092   }
3093   sgp->values = new_values;
3094   sgp->numval = new_numval;
3095   sgp->compr = 0;
3096 
3097   return TRUE;
3098 }
3099 
3100 static Boolean TruncateSeqGraphValues (SeqGraphPtr sgp, Int4 len, Boolean onleft)
3101 {
3102   Int4    oldpos, newpos = 0;
3103   Pointer new_values = NULL;
3104   Int4    new_numval;
3105   Int2    cur_byte;
3106   Int4    imin = 0, imax = 0;
3107   FloatHi fmin, fmax;
3108 
3109   if (sgp == NULL) return TRUE;
3110   if (!ExpandSeqGraph (sgp)) return FALSE;
3111 
3112   new_numval = sgp->numval - len;
3113 
3114   /* allocate space for new values */
3115   switch (sgp->flags[2]) {
3116     case SEQGRAPH_FloatHi:
3117       new_values = MemNew (sizeof (FloatHi) * new_numval);
3118       fmin = ((FloatHiPtr)sgp->values)[0];
3119       fmax = fmin;
3120       break;
3121     case SEQGRAPH_Int4:
3122       new_values = MemNew (sizeof (Int4) * new_numval);
3123       imin = ((Int4Ptr)sgp->values)[0];
3124       imax = imin;
3125       break;
3126     case SEQGRAPH_BS:
3127       new_values = (Pointer) BSNew (new_numval);
3128       BSSeek ((ByteStorePtr)new_values, 0, SEEK_SET);
3129       if (onleft) {
3130         BSSeek ((ByteStorePtr) sgp->values, len, SEEK_SET);
3131       } else {
3132         BSSeek ((ByteStorePtr) sgp->values, 0, SEEK_SET);
3133       }
3134       imin = BSGetByte ((ByteStorePtr) sgp->values);
3135       imax = imin;
3136       /* put pointer back */
3137       if (onleft) {
3138         BSSeek ((ByteStorePtr) sgp->values, len, SEEK_SET);
3139       } else {
3140         BSSeek ((ByteStorePtr) sgp->values, 0, SEEK_SET);
3141       }
3142       break;
3143   }
3144 
3145   /* copy */
3146   if (onleft) {
3147     oldpos = len;
3148   } else {
3149     oldpos = 0;
3150   }
3151   while (oldpos < sgp->numval && newpos < new_numval) {
3152       switch (sgp->flags[2]) {
3153         case SEQGRAPH_FloatHi:
3154           ((FloatHiPtr)new_values)[newpos] = ((FloatHiPtr)sgp->values)[oldpos];
3155           if (((FloatHiPtr)new_values)[newpos] > fmax) {
3156             fmax = ((FloatHiPtr)new_values)[newpos];
3157           }
3158           if (((FloatHiPtr)new_values)[newpos] < fmin) {
3159             fmin = ((FloatHiPtr)new_values)[newpos];
3160           }
3161           break;
3162         case SEQGRAPH_Int4:
3163           ((Int4Ptr)new_values)[newpos] = ((Int4Ptr)sgp->values)[oldpos];
3164           if (((Int4Ptr)new_values)[newpos] > imax) {
3165             imax = ((Int4Ptr)new_values)[newpos];
3166           }
3167           if (((Int4Ptr)new_values)[newpos] < imin) {
3168             imin = ((Int4Ptr)new_values)[newpos];
3169           }
3170           break;
3171         case SEQGRAPH_BS:
3172           cur_byte = BSGetByte ((ByteStorePtr) sgp->values);
3173           BSPutByte ((ByteStorePtr) new_values, cur_byte);
3174           if (cur_byte > imax) {
3175             imax = cur_byte;
3176           }
3177           if (cur_byte < imin) {
3178             imin = cur_byte;
3179           }
3180           break;
3181     }
3182     oldpos++;
3183     newpos++;
3184   }
3185 
3186   /* free old values and replace with new */
3187   if (sgp->flags[2] == SEQGRAPH_BS) {
3188     sgp->values = BSFree ((ByteStorePtr) sgp->values);
3189   } else {    
3190     sgp->values = MemFree (sgp->values);    
3191   }
3192   sgp->values = new_values;
3193   sgp->numval = new_numval;
3194 
3195   /* replace mins and maxes */
3196   if (sgp->flags[2] == SEQGRAPH_FloatHi) {
3197     sgp->max.realvalue = fmax;
3198     sgp->min.realvalue = fmin;
3199   } else {
3200     sgp->max.intvalue = imax;
3201     sgp->min.intvalue = imin;
3202   }
3203   return TRUE;  
3204 }
3205 
3206   
3207 
3208 /* assume Bioseq has already been trimmed - length of old Bioseq was trim5 + bsp->length + trim3 */
3209 static Boolean 
3210 TrimQualityScoresForSequenceUpdate 
3211 (BioseqPtr bsp, 
3212  Int4      trim5,
3213  Int4      trim3,
3214  FILE      *log_fp,
3215  BoolPtr   data_in_log)
3216 {
3217   ValNodePtr    score_list = NULL, vnp;
3218   SeqGraphPtr   sgp;
3219   SeqIntPtr     sip;
3220   Int4          left, right;
3221   Boolean       rval = FALSE;
3222   Char          acc_str [256];
3223 
3224   if (bsp == NULL) return FALSE;
3225 
3226   VisitGraphsOnBsp (bsp, &score_list, ListPhrapGraphsCallback);
3227   if (score_list == NULL) return FALSE;
3228 
3229   for (vnp = score_list; vnp != NULL; vnp = vnp->next) {
3230     sgp = vnp->data.ptrvalue;
3231     if (sgp != NULL && sgp->loc != NULL && sgp->loc->choice == SEQLOC_INT) {
3232       sip = (SeqIntPtr) sgp->loc->data.ptrvalue;
3233       /* trim on right */
3234       if (sip->from > trim5 + bsp->length) {
3235         sgp->idx.deleteme = TRUE;
3236         rval = TRUE;
3237       } else if (sip->to > trim5 + bsp->length - 1) {
3238         right = sip->to - trim5 - bsp->length + 1;
3239         sip->to = trim5 + bsp->length - 1;
3240         TruncateSeqGraphValues (sgp, right, FALSE);
3241         rval = TRUE;
3242       }
3243       
3244       sip->from -= trim5;
3245       sip->to -= trim5;
3246       if (sip->to < 0) {
3247         sgp->idx.deleteme = TRUE;
3248         rval = TRUE;
3249       } else if (sip->from < 0) {
3250         left = 0 - sip->from;
3251         sip->from = 0;
3252         TruncateSeqGraphValues (sgp, left, TRUE);
3253         rval = TRUE;
3254       }
3255     }
3256   }  
3257 
3258   if (rval && log_fp != NULL && data_in_log != NULL) {
3259     SeqIdWrite (bsp->id, acc_str, PRINTID_REPORT, sizeof (acc_str));
3260     fprintf (log_fp, "Quality scores trimmed for %s\n", acc_str);
3261     *data_in_log = TRUE;
3262   }
3263   return rval;
3264 }
3265 
3266 
3267 static Boolean AdjustAlignment (
3268   UpsDataPtr udp,
3269   Int2 choice
3270 )
3271 
3272 {
3273   DenseSegPtr  dsp;
3274   Int2         j;
3275   SeqAlignPtr  sap;
3276 
3277   if (udp == NULL) return FALSE;
3278 
3279   sap = udp->salp;
3280   if (sap == NULL) return FALSE;
3281   AMFreeAllIndexes (sap);
3282 
3283   if (sap->segtype == SAS_DENSEG) {
3284     dsp = (DenseSegPtr) sap->segs;
3285 
3286     switch (choice) {
3287       case 2 :
3288         /* adjust alignment 5' */
3289         if (dsp != NULL && dsp->lens != NULL && dsp->numseg > 0) {
3290           dsp->lens [dsp->numseg - 1] += udp->old3;
3291         }
3292         break;
3293       case 3 :
3294         /* adjust alignment 3' */
3295         if (dsp != NULL && dsp->lens != NULL && dsp->starts != NULL && dsp->numseg > 0) {
3296           dsp->lens [0] += udp->old5;
3297           dsp->starts [0] = 0;
3298           dsp->starts [1] = 0;
3299           for (j = 1; j < dsp->numseg; j++) {
3300             if (dsp->starts [1 + j * 2] != -1) {
3301               dsp->starts [1 + j * 2] += udp->old5 - udp->new5;
3302             }
3303           }
3304         }
3305         break;
3306       case 4 :
3307         /* adjust alignment patch */
3308         if (dsp != NULL && dsp->lens != NULL && dsp->starts != NULL && dsp->numseg > 0) {
3309           dsp->lens [dsp->numseg - 1] += udp->old3;
3310           dsp->lens [0] += udp->old5;
3311           dsp->starts [0] = 0;
3312           dsp->starts [1] = 0;
3313           for (j = 1; j < dsp->numseg; j++) {
3314             if (dsp->starts [1 + j * 2] != -1) {
3315               dsp->starts [1 + j * 2] += udp->old5 - udp->new5;
3316             }
3317           }
3318         }
3319         break;
3320       default :
3321         break;
3322     }
3323   }
3324 
3325   AlnMgr2IndexSingleChildSeqAlign (sap);
3326 
3327   return TRUE;
3328 }
3329 
3330 static void OffsetLoc (SeqLocPtr slp, Int4 offset, SeqIdPtr sip)
3331 
3332 {
3333   PackSeqPntPtr  psp;
3334   SeqIntPtr      sinp;
3335   SeqPntPtr      spp;
3336   Uint1          used;
3337 
3338   if (slp == NULL) return;
3339   switch (slp->choice) {
3340     case SEQLOC_INT :
3341       sinp = (SeqIntPtr) slp->data.ptrvalue;
3342       if (sinp != NULL) {
3343         sinp->from += offset;
3344         sinp->to += offset;
3345         if (sip != NULL) {
3346           sinp->id = SeqIdFree (sinp->id);
3347           sinp->id = SeqIdDup (sip);
3348         }
3349       }
3350       break;
3351     case SEQLOC_PNT :
3352       spp = (SeqPntPtr) slp->data.ptrvalue;
3353       if (spp != NULL) {
3354         spp->point += offset;
3355         if (sip != NULL) {
3356           spp->id = SeqIdFree (spp->id);
3357           spp->id = SeqIdDup (sip);
3358         }
3359       }
3360       break;
3361     case SEQLOC_PACKED_PNT :
3362       psp = (PackSeqPntPtr) slp->data.ptrvalue;
3363       if (psp != NULL) {
3364         for (used = 0; used < psp->used; used++) {
3365           psp->pnts [used] += offset;
3366         }
3367         if (sip != NULL) {
3368           psp->id = SeqIdFree (psp->id);
3369           psp->id = SeqIdDup (sip);
3370         }
3371       }
3372       break;
3373     default :
3374       break;
3375   }
3376 }
3377 
3378 extern void OffsetLocation (SeqLocPtr loc, Int4 offset, SeqIdPtr sip)
3379 
3380 {
3381   SeqLocPtr  slp;
3382 
3383   slp = SeqLocFindNext (loc, NULL);
3384   while (slp != NULL) {
3385     OffsetLoc (slp, offset, sip);
3386     slp = SeqLocFindNext (loc, slp);
3387   }
3388 }
3389 
3390 static void PromoteSeqId (SeqIdPtr sip, Pointer userdata)
3391 
3392 {
3393   SeqIdPtr  bestid, newid, oldid;
3394 
3395   bestid = (SeqIdPtr) userdata;
3396 
3397   newid = SeqIdDup (bestid);
3398   if (newid == NULL) return;
3399 
3400   oldid = ValNodeNew (NULL);
3401   if (oldid == NULL) return;
3402 
3403   MemCopy (oldid, sip, sizeof (ValNode));
3404   oldid->next = NULL;
3405 
3406   sip->choice = newid->choice;
3407   sip->data.ptrvalue = newid->data.ptrvalue;
3408 
3409   SeqIdFree (oldid);
3410   ValNodeFree (newid);
3411 
3412   SeqIdStripLocus (sip);
3413 }
3414 
3415 static void CorrectFeatureSeqIds (
3416   SeqFeatPtr sfp,
3417   Pointer userdata
3418 )
3419 
3420 {
3421   VisitSeqIdsInSeqLoc (sfp->location, userdata, PromoteSeqId);
3422 }
3423 
3424 static Boolean DoFeaturePropWithOffset (
3425   UpsDataPtr udp,
3426   Int4 offset,
3427   SeqAnnotPtr PNTR sapp,
3428   Boolean patch
3429 )
3430 
3431 {
3432   BioseqPtr          bsp, newbsp, oldbsp;
3433   CodeBreakPtr       cbp;
3434   SeqMgrFeatContext  context;
3435   CdRegionPtr        crp;
3436   SeqFeatPtr         dup, sfp, last = NULL;
3437   Uint2              entityID;
3438   Boolean            keepProteinIDs;
3439   SeqEntryPtr        newsep, prdsep, top;
3440   RnaRefPtr          rrp;
3441   SeqAnnotPtr        sap = NULL, saptmp;
3442   SeqDescrPtr        sdp;
3443   SeqIdPtr           sip;
3444   tRNAPtr            trp;
3445 
3446   if (udp == NULL) return FALSE;
3447 
3448   SeqEntrySetScope (NULL);
3449 
3450   sfp = SeqMgrGetNextFeature (udp->newbsp, NULL, 0, 0, &context);
3451   if (sfp == NULL) return FALSE;
3452 
3453   if (udp->diffOrgs) {
3454     keepProteinIDs = FALSE;
3455   } else {
3456     keepProteinIDs = GetStatus (udp->keepProteinIDs);
3457   }
3458 
3459   oldbsp = udp->oldbsp;
3460 
3461   entityID = ObjMgrGetEntityIDForPointer (udp->oldbsp);
3462   top = GetBestTopParentForData (entityID, udp->oldbsp);
3463 
3464   sdp = ExtractBioSourceAndPubs (top);
3465 
3466   sip = SeqIdFindBest (oldbsp->id, 0);
3467 
3468   while (sfp != NULL) {
3469 
3470     if ((! patch) || (context.right >= udp->new5 && context.left <= udp->new5 + udp->newa)) {
3471 
3472     dup = AsnIoMemCopy ((Pointer) sfp,
3473                         (AsnReadFunc) SeqFeatAsnRead,
3474                         (AsnWriteFunc) SeqFeatAsnWrite);
3475 
3476     if (last == NULL) {
3477       sap = SeqAnnotNew ();
3478       if (oldbsp->annot == NULL) {
3479         oldbsp->annot = sap;
3480       } else {
3481         for (saptmp = oldbsp->annot; saptmp->next != NULL; saptmp = saptmp->next) continue;
3482         saptmp->next = sap;
3483       }
3484       sap->type = 1;
3485       sap->data = (Pointer) dup;
3486     } else {
3487       last->next = dup;
3488     }
3489     last = dup;
3490 
3491     /*
3492     sep = SeqMgrGetSeqEntryForData (oldbsp);
3493     CreateNewFeature (sep, NULL, dup->data.choice, dup);
3494     */
3495 
3496     OffsetLocation (dup->location, offset, sip);
3497     switch (dup->data.choice) {
3498       case SEQFEAT_CDREGION :
3499         crp = (CdRegionPtr) dup->data.value.ptrvalue;
3500         if (crp != NULL) {
3501           for (cbp = crp->code_break; cbp != NULL; cbp = cbp->next) {
3502             OffsetLocation (cbp->loc, offset, sip);
3503           }
3504         }
3505         break;
3506       case SEQFEAT_RNA :
3507         rrp = (RnaRefPtr) dup->data.value.ptrvalue;
3508         if (rrp != NULL && rrp->ext.choice == 2) {
3509           trp = (tRNAPtr) rrp->ext.value.ptrvalue;
3510           if (trp != NULL && trp->anticodon != NULL) {
3511             OffsetLocation (trp->anticodon, offset, sip);
3512           }
3513         }
3514         break;
3515       default :
3516         break;
3517     }
3518     if (dup->product != NULL) {
3519       SeqEntrySetScope (NULL);
3520       bsp = BioseqFindFromSeqLoc (dup->product);
3521       if (bsp != NULL) {
3522         prdsep = SeqMgrGetSeqEntryForData (bsp);
3523         if (prdsep != NULL) {
3524           newsep = AsnIoMemCopy ((Pointer) prdsep,
3525                                  (AsnReadFunc) SeqEntryAsnRead,
3526                                  (AsnWriteFunc) SeqEntryAsnWrite);
3527           if (newsep != NULL) {
3528             if (IS_Bioseq (newsep)) {
3529               newbsp = (BioseqPtr) newsep->data.ptrvalue;
3530               if (newbsp != NULL) {
3531                 if (! keepProteinIDs) {
3532                   newbsp->id = SeqIdSetFree (newbsp->id);
3533                   newbsp->id = MakeNewProteinSeqId (NULL, sip);
3534                   newbsp->hist = SeqHistFree (newbsp->hist);
3535                   VisitFeaturesOnBsp (newbsp, (Pointer) newbsp->id, CorrectFeatureSeqIds);
3536                   SetSeqFeatProduct (dup, newbsp);
3537                   /*
3538                   dup->product = SeqLocFree (dup->product);
3539                   dup->product = CreateWholeInterval (newsep);
3540                   */
3541                 }
3542                 SeqMgrReplaceInBioseqIndex (newbsp);
3543               }
3544             }
3545             AddSeqEntryToSeqEntry (top, newsep, TRUE);
3546           }
3547         }
3548       }
3549     }
3550     }
3551 
3552     sfp = SeqMgrGetNextFeature (udp->newbsp, sfp, 0, 0, &context);
3553   }
3554 
3555   ReplaceBioSourceAndPubs (top, sdp);
3556 
3557   if (sapp != NULL) {
3558     *sapp = sap;
3559   }
3560 
3561   return TRUE;
3562 }
3563 
3564 /* This function adjusts the endpoints of a location, as long as the
3565  * endpoints are in the area represented by the alignment.
3566  * When we are adjusting locations for an alignment of a part, we will 
3567  * be looking at all features indexed on the main segment, but we only
3568  * want to adjust feature endpoints located on the segment that we are
3569  * updating.
3570  */
3571 static Int4 AdjustEndpoint 
3572 (SeqAlignPtr salp,
3573  SeqLocPtr   slp, 
3574  Int4        max_length, 
3575  Int4        begin, 
3576  Int4        fin,
3577  Int4        endpoint,
3578  Int4        end)
3579 {
3580   BioseqPtr            slp_bsp, parent_bsp, old_bsp;
3581   SeqMgrSegmentContext segcontext; 
3582   SeqIdPtr             old_sip; 
3583   Int4                 pt;
3584   
3585   if (slp == NULL || salp == NULL)
3586   {
3587     return endpoint;
3588   }
3589   
3590   old_sip = AlnMgr2GetNthSeqIdPtr (salp, begin);
3591   old_bsp = BioseqFind (old_sip);
3592 
3593   parent_bsp = SeqMgrGetParentOfPart (old_bsp, &segcontext);
3594   
3595   slp_bsp = BioseqFind (SeqLocId (slp));
3596   if (slp_bsp == old_bsp
3597       || (slp_bsp == parent_bsp 
3598           && endpoint >= segcontext.cumOffset + segcontext.from
3599           && endpoint < segcontext.cumOffset + segcontext.to))
3600   {
3601     if (slp_bsp == parent_bsp)
3602     {
3603       endpoint -= segcontext.cumOffset + segcontext.from;
3604     }
3605     pt = MapBioseqToBioseqSpecial (salp, begin, fin, endpoint, end);
3606     if (pt < 0) {
3607       pt = 0;
3608     } else if (pt >= max_length) {
3609       pt = max_length - 1;
3610     }
3611     if (slp_bsp == parent_bsp)
3612     {
3613       pt += segcontext.cumOffset + segcontext.from;
3614     }
3615   }
3616   else
3617   {
3618     pt = endpoint;
3619   }
3620   
3621   return pt;  
3622 }
3623 
3624 static void ReplaceLocation (SeqAlignPtr salp, SeqLocPtr slp, Int4 length, Int4 begin, Int4 fin)
3625 
3626 {
3627   PackSeqPntPtr  psp;
3628   SeqIntPtr      sinp;
3629   SeqPntPtr      spp;
3630   Uint1          used;
3631 
3632   if (slp == NULL) return;
3633   switch (slp->choice) {
3634     case SEQLOC_INT :
3635       sinp = (SeqIntPtr) slp->data.ptrvalue;
3636       if (sinp != NULL) {
3637         sinp->from = AdjustEndpoint (salp, slp, length, begin, fin,
3638                                      sinp->from, SQN_LEFT);
3639         sinp->to = AdjustEndpoint (salp, slp, length, begin, fin,
3640                                    sinp->to, SQN_RIGHT);
3641       }
3642       break;
3643     case SEQLOC_PNT :
3644       spp = (SeqPntPtr) slp->data.ptrvalue;
3645       if (spp != NULL) {
3646         spp->point = AdjustEndpoint (salp, slp, length, begin, fin,
3647                                      spp->point, SQN_LEFT);
3648       }
3649       break;
3650     case SEQLOC_PACKED_PNT :
3651       psp = (PackSeqPntPtr) slp->data.ptrvalue;
3652       if (psp != NULL) {
3653         for (used = 0; used < psp->used; used++) {
3654           psp->pnts [used] = AdjustEndpoint (salp, slp, length, begin, fin,
3655                                              psp->pnts [used], SQN_LEFT);
3656         }
3657       }
3658       break;
3659     default :
3660       break;
3661   }
3662 }
3663 
3664 /* this function iterates through the pieces of a complex location
3665  * and calls ReplaceLocation for each one.  ReplaceLocation will only
3666  * act on SEQLOC_INT, SEQLOC_PNT, and SEQLOC_PACKED_PNT and will ignore
3667  * other types.
3668  */
3669 extern void 
3670 ReplaceComplexLocation 
3671 (SeqLocPtr   slp,
3672  SeqAlignPtr salp,
3673  Int4        new_len,
3674  Int4        begin,
3675  Int4        fin)
3676 {
3677   SeqLocPtr subslp;
3678   
3679   if (slp == NULL || salp == NULL)
3680   {
3681     return;
3682   }
3683   
3684   subslp = SeqLocFindNext (slp, NULL);
3685   while (subslp != NULL) {
3686     ReplaceLocation (salp, subslp, new_len, begin, fin);
3687     subslp = SeqLocFindNext (slp, subslp);
3688   }
3689 }
3690 
3691 static Int4 LengthForNewSequence (UpsDataPtr udp)
3692 {
3693   Int4 new_len = 0;
3694   
3695   if (udp == NULL)
3696   {
3697     return 0;
3698   }
3699   else if (GetValue (udp->sfb) == UPDATE_FEATURES_ONLY)
3700   {
3701     new_len = udp->oldbsp->length;
3702   }
3703   else if (udp->rmcval == UPDATE_PATCH)
3704   {
3705     new_len = udp->old5 + udp->newa + udp->old3;
3706   }
3707   else if (udp->rmcval == UPDATE_REPLACE)
3708   {
3709     new_len = udp->new5 + udp->newa + udp->new3;
3710   }
3711   else if (udp->rmcval == UPDATE_EXTEND5)
3712   {
3713     new_len = udp->new5 + udp->olda + udp->old3;
3714   }
3715   else if (udp->rmcval == UPDATE_EXTEND3)
3716   {
3717     new_len = udp->old5 + udp->olda + udp->new3;
3718   }
3719   return new_len;
3720 }
3721 
3722 static SeqLocPtr 
3723 GetPropagatedLocation 
3724 (SeqLocPtr   orig_loc, 
3725  BioseqPtr   newbsp,
3726  BioseqPtr   oldbsp,
3727  Int4        new_len,
3728  SeqAlignPtr salp)
3729 {
3730   SeqLocPtr tmp_loc, new_loc;
3731   Boolean   split;
3732   
3733   tmp_loc = SeqLocCopy (orig_loc);
3734   ReplaceComplexLocation (tmp_loc, salp, new_len, 2, 1);   
3735 
3736   new_loc = SeqLocCopyRegion (oldbsp->id, tmp_loc, newbsp, 0, oldbsp->length - 1, Seq_strand_plus, &split);
3737   
3738   tmp_loc = SeqLocFree (tmp_loc);
3739   
3740   return new_loc;
3741 }
3742 
3743 
3744 static Boolean DoFeaturePropThruAlign (
3745   UpsDataPtr udp,
3746   SeqAnnotPtr PNTR sapp
3747 )
3748 
3749 {
3750   BioseqPtr          bsp, newbsp, oldbsp;
3751   CodeBreakPtr       cbp, prevcbp, nextcbp;
3752   SeqMgrFeatContext  context;
3753   CdRegionPtr        crp;
3754   SeqFeatPtr         dup, sfp, last = NULL;
3755   Uint2              entityID;
3756   Int4               from, to;
3757   Boolean            keepProteinIDs;
3758   SeqLocPtr          newloc;
3759   SeqEntryPtr        newsep, prdsep, top;
3760   RnaRefPtr          rrp;
3761   SeqAnnotPtr        sap = NULL, saptmp;
3762   SeqDescrPtr        sdp;
3763   SeqIdPtr           sip;
3764   Boolean            split;
3765   tRNAPtr            trp;
3766   Boolean            partial5, partial3;
3767 
3768   if (udp == NULL) return FALSE;
3769 
3770   SeqEntrySetScope (NULL);
3771 
3772   sfp = SeqMgrGetNextFeature (udp->newbsp, NULL, 0, 0, &context);
3773   if (sfp == NULL) return FALSE;
3774 
3775   keepProteinIDs = GetStatus (udp->keepProteinIDs);
3776 
3777   oldbsp = udp->oldbsp;
3778 
3779   entityID = ObjMgrGetEntityIDForPointer (oldbsp);
3780   top = GetBestTopParentForData (entityID, oldbsp);
3781 
3782   sdp = ExtractBioSourceAndPubs (top);
3783 
3784   sip = SeqIdFindBest (oldbsp->id, 0);
3785 
3786   from = udp->new5;
3787   to = udp->new5 + udp->newa;
3788 
3789   while (sfp != NULL) {
3790 
3791     if (context.right >= from && context.left <= to) {
3792       split = FALSE;
3793       newloc = GetPropagatedLocation (sfp->location, udp->newbsp, udp->oldbsp, 
3794                                       LengthForNewSequence (udp), udp->salp);
3795       if (newloc != NULL) {
3796         CheckSeqLocForPartial (sfp->location, &partial5, &partial3);
3797         SetSeqLocPartial (newloc, partial5, partial3);
3798         dup = AsnIoMemCopy ((Pointer) sfp,
3799                             (AsnReadFunc) SeqFeatAsnRead,
3800                             (AsnWriteFunc) SeqFeatAsnWrite);
3801                             
3802         SeqLocFree (dup->location);
3803         dup->location = newloc;
3804         if (split) {
3805           dup->partial = TRUE;
3806         }
3807         dup->partial |= partial5;
3808         dup->partial |= partial3;
3809 
3810         if (last == NULL) {
3811           sap = SeqAnnotNew ();
3812           if (oldbsp->annot == NULL) {
3813             oldbsp->annot = sap;
3814           } else {
3815             for (saptmp = oldbsp->annot; saptmp->next != NULL; saptmp = saptmp->next) continue;
3816             saptmp->next = sap;
3817           }
3818           sap->type = 1;
3819           sap->data = (Pointer) dup;
3820         } else {
3821           last->next = dup;
3822         }
3823         last = dup;
3824 
3825         switch (dup->data.choice) {
3826           case SEQFEAT_CDREGION :
3827             crp = (CdRegionPtr) dup->data.value.ptrvalue;
3828             if (crp != NULL) {
3829               prevcbp = NULL;
3830               for (cbp = crp->code_break; cbp != NULL; cbp = nextcbp) {
3831                 nextcbp = cbp->next;
3832                 newloc = GetPropagatedLocation (cbp->loc, udp->newbsp, udp->oldbsp, 
3833                                                 LengthForNewSequence (udp), udp->salp);
3834                 SeqLocFree (cbp->loc);
3835                 cbp->loc = newloc;
3836                 if (cbp->loc == NULL) {
3837                   if (prevcbp != NULL) {
3838                     prevcbp->next = nextcbp;
3839                   } else {
3840                     crp->code_break = nextcbp;
3841                   }
3842                   cbp->next = NULL;
3843                   CodeBreakFree (cbp);
3844                 } else {
3845                   prevcbp = cbp;
3846                 }
3847               }
3848             }
3849             break;
3850           case SEQFEAT_RNA :
3851             rrp = (RnaRefPtr) dup->data.value.ptrvalue;
3852             if (rrp != NULL && rrp->ext.choice == 2) {
3853               trp = (tRNAPtr) rrp->ext.value.ptrvalue;
3854               if (trp != NULL && trp->anticodon != NULL) {
3855                 newloc = GetPropagatedLocation (trp->anticodon, udp->newbsp, udp->oldbsp, 
3856                                                 LengthForNewSequence (udp), udp->salp);
3857                 SeqLocFree (trp->anticodon);
3858                 trp->anticodon = newloc;
3859               }
3860             }
3861             break;
3862           default :
3863             break;
3864         }
3865         if (dup->product != NULL) {
3866           SeqEntrySetScope (NULL);
3867           bsp = BioseqFindFromSeqLoc (dup->product);
3868           if (bsp != NULL) {
3869             prdsep = SeqMgrGetSeqEntryForData (bsp);
3870             if (prdsep != NULL) {
3871               newsep = AsnIoMemCopy ((Pointer) prdsep,
3872                                      (AsnReadFunc) SeqEntryAsnRead,
3873                                      (AsnWriteFunc) SeqEntryAsnWrite);
3874               if (newsep != NULL) {
3875                 if (IS_Bioseq (newsep)) {
3876                   newbsp = (BioseqPtr) newsep->data.ptrvalue;
3877                   if (newbsp != NULL) {
3878                     if (! keepProteinIDs) {
3879                       newbsp->id = SeqIdSetFree (newbsp->id);
3880                       newbsp->id = MakeNewProteinSeqId (NULL, sip);
3881                       VisitFeaturesOnBsp (newbsp, (Pointer) newbsp->id, CorrectFeatureSeqIds);
3882                       SetSeqFeatProduct (dup, newbsp);
3883                       /*
3884                       dup->product = SeqLocFree (dup->product);
3885                       dup->product = CreateWholeInterval (newsep);
3886                       */
3887                     }
3888                     SeqMgrReplaceInBioseqIndex (newbsp);
3889                   }
3890                 }
3891                 AddSeqEntryToSeqEntry (top, newsep, TRUE);
3892               }
3893             }
3894           }
3895         }
3896       }
3897     }
3898 
3899     sfp = SeqMgrGetNextFeature (udp->newbsp, sfp, 0, 0, &context);
3900   }
3901 
3902   ReplaceBioSourceAndPubs (top, sdp);
3903 
3904   if (sapp != NULL) {
3905     *sapp = sap;
3906   }
3907 
3908   return TRUE;
3909 }
3910 
3911 static void UpdateOneFeatureForSequenceReplace 
3912 (SeqFeatPtr  sfp, 
3913  SeqAlignPtr salp,
3914  BioseqPtr   oldbsp,
3915  Int4        new_len)
3916 {
3917   CodeBreakPtr cbp;
3918   CdRegionPtr  crp;
3919   RnaRefPtr    rrp;
3920   tRNAPtr      trp;
3921   
3922   if (sfp == NULL || salp == NULL)
3923   {
3924     return;
3925   }
3926   
3927   ReplaceComplexLocation (sfp->location, salp, new_len, 1, 2);
3928 
3929   switch (sfp->data.choice) {
3930     case SEQFEAT_CDREGION :
3931       crp = (CdRegionPtr) sfp->data.value.ptrvalue;
3932       if (crp != NULL) 
3933       {
3934         for (cbp = crp->code_break; cbp != NULL; cbp = cbp->next) 
3935         {
3936           ReplaceComplexLocation (cbp->loc, salp, new_len, 1, 2);
3937         }
3938       }
3939       break;
3940     case SEQFEAT_RNA :
3941       rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
3942       if (rrp != NULL && rrp->ext.choice == 2) {
3943         trp = (tRNAPtr) rrp->ext.value.ptrvalue;
3944         if (trp != NULL && trp->anticodon != NULL) {
3945           ReplaceComplexLocation (trp->anticodon, salp, new_len, 1, 2);
3946         }
3947       }
3948       break;
3949     default :
3950       break;
3951   }
3952 }
3953 
3954 static void UpdateLocationsForSequenceReplace 
3955 (SeqAlignPtr salp,
3956  BioseqPtr oldbsp,
3957  BioseqPtr newbsp)
3958 {
3959   BioseqPtr    parentbsp;
3960   SeqMgrFeatContext  context;
3961   SeqMgrSegmentContext segcontext;
3962   SeqFeatPtr           sfp;
3963   
3964   if (salp == NULL || oldbsp == NULL || newbsp == NULL)
3965   {
3966     return;
3967   }
3968     
3969   /* if this sequence is a part, the features will be indexed on
3970    * the parent.
3971    */
3972   parentbsp = SeqMgrGetParentOfPart (oldbsp, &segcontext);
3973   if (parentbsp == NULL)
3974   {
3975     sfp = SeqMgrGetNextFeature (oldbsp, NULL, 0, 0, &context);
3976     while (sfp != NULL)
3977     {
3978       UpdateOneFeatureForSequenceReplace (sfp, salp, oldbsp, newbsp->length);
3979       sfp = SeqMgrGetNextFeature (oldbsp, sfp, 0, 0, &context);
3980                                   
3981     }
3982   }
3983   else
3984   {
3985     sfp = SeqMgrGetNextFeature (parentbsp, NULL, 0, 0, &context);
3986     while (sfp != NULL)
3987     {
3988       UpdateOneFeatureForSequenceReplace (sfp, salp, oldbsp, newbsp->length);
3989       sfp = SeqMgrGetNextFeature (parentbsp, sfp, 0, 0, &context);
3990     }
3991   }  
3992 }
3993 
3994 static void 
3995 ReplaceOneSequence 
3996 (SeqAlignPtr salp,
3997  BioseqPtr oldbsp,
3998  BioseqPtr newbsp)
3999 {
4000   SeqDataPtr         bs;
4001   Int4               len, len_change;
4002   Uint1              seq_data_type, seq_ext_type;
4003   Pointer            seq_ext;
4004   Uint1              repr;
4005   BioseqPtr          parent_bsp;
4006   SeqMgrSegmentContext context;
4007   
4008   if (oldbsp == NULL || newbsp == NULL)
4009   {
4010     return;
4011   }
4012 
4013   UpdateLocationsForSequenceReplace (salp, oldbsp, newbsp);
4014   len_change = newbsp->length - oldbsp->length;
4015 
4016   /* switch bioseqs to finish update */
4017 
4018   bs = oldbsp->seq_data;
4019   oldbsp->seq_data = newbsp->seq_data;
4020   newbsp->seq_data = bs;
4021   len = oldbsp->length;
4022   oldbsp->length = newbsp->length;
4023   newbsp->length = len;
4024   seq_data_type = oldbsp->seq_data_type;
4025   oldbsp->seq_data_type = newbsp->seq_data_type;
4026   newbsp->seq_data_type = seq_data_type;  
4027   /* also move seq_ext, for delta sequences */
4028   seq_ext_type = oldbsp->seq_ext_type;
4029   seq_ext = oldbsp->seq_ext;
4030   oldbsp->seq_ext_type = newbsp->seq_ext_type;
4031   oldbsp->seq_ext = newbsp->seq_ext;
4032   newbsp->seq_ext_type = seq_ext_type;
4033   newbsp->seq_ext = seq_ext;
4034   
4035   /* swap repr */
4036   repr = oldbsp->repr;
4037   oldbsp->repr = newbsp->repr;
4038   newbsp->repr = repr;
4039   
4040   /* if this was part of a segmented set, update the parent length */
4041   parent_bsp = SeqMgrGetParentOfPart (oldbsp, &context);
4042   if (parent_bsp != NULL)
4043   {
4044     parent_bsp->length += len_change;
4045   }
4046 }
4047 
4048 static Boolean ReplaceSequence (UpsDataPtr udp)
4049 
4050 {
4051   MsgAnswer          ans;
4052 
4053   if (udp == NULL)
4054   {
4055     return TRUE;
4056   }
4057   
4058   if (FALSE == udp->isSet)
4059   {
4060     if ((udp->seq1 != NULL || udp->seq2 != NULL)
4061         && StringICmp (udp->seq1, udp->seq2) == 0
4062         && ! udp->revcomp) 
4063     {
4064             ans = Message (MSG_OKC, "Replacement sequence is identical to"
4065                                    " original - possible error");
4066             if (ans == ANS_CANCEL) return FALSE;
4067     }    
4068   }
4069 
4070   ReplaceOneSequence (udp->salp, udp->oldbsp, udp->newbsp);
4071   return TRUE;
4072 }
4073 
4074 static Boolean Merge5Prime (UpsDataPtr udp)
4075 
4076 {
4077   ByteStorePtr  bs;
4078   Char          ch;
4079   Int4          i, newlen;
4080   BioseqPtr     newbsp;
4081   CharPtr       ptr, str, tmp;
4082 
4083   /* construct replacement sequence by recombining between old and overlap */
4084 
4085   tmp = udp->seq2;
4086 
4087   newlen = udp->new5 + udp->newa + udp->old3;
4088   str = (CharPtr) MemNew (sizeof (Char) * (size_t) (newlen + 5));
4089   if (str == NULL)
4090     return FALSE;
4091   ptr = str;
4092 
4093   for (i = 0; i < udp->new5 + udp->newa; i++) {
4094     ch = *tmp;
4095     *ptr = ch;
4096     tmp++;
4097     ptr++;
4098   }
4099     
4100   tmp = udp->seq1 + udp->old5 + udp->olda;
4101   for (i = 0; i < udp->old3; i++) {
4102     ch = *tmp;
4103     *ptr = ch;
4104     tmp++;
4105     ptr++;
4106   }
4107 
4108   *ptr = '\0';
4109   bs = BSNew (newlen);
4110   BSWrite (bs, (VoidPtr) str, newlen);
4111 
4112   udp->seq2 = MemFree (udp->seq2);
4113   udp->seq2 = str;
4114 
4115   if (bs != NULL && BSLen (bs) < 1) {
4116     bs = BSFree (bs);
4117   }
4118   if (bs == NULL) return FALSE;
4119 
4120   /* overlap turned into replacement sequence */
4121 
4122   newbsp = udp->newbsp;
4123   newbsp->seq_data = SeqDataFree (newbsp->seq_data, newbsp->seq_data_type);
4124   newbsp->seq_data = (SeqDataPtr) bs;
4125   newbsp->seq_data_type = Seq_code_iupacna;
4126   newbsp->length = newlen;
4127 
4128   /* adjust alignment and reindex */
4129 
4130   if (! AdjustAlignment (udp, 2)) return FALSE;
4131 
4132   /* then finish by replacing with new sequence */
4133 
4134   return ReplaceSequence (udp);
4135 }
4136 
4137 static Boolean Merge3Prime (UpsDataPtr udp)
4138 
4139 {
4140   ByteStorePtr  bs;
4141   Char          ch;
4142   Int4          i, newlen;
4143   BioseqPtr     newbsp;
4144   CharPtr       ptr, str, tmp;
4145 
4146   /* construct replacement sequence by recombining between old and overlap */
4147 
4148   newlen = udp->old5 + udp->newa + udp->new3;
4149   str = (CharPtr) MemNew (sizeof (Char) * (size_t) (newlen + 5));
4150   if (str == NULL)
4151     return FALSE;
4152   ptr = str;
4153 
4154   tmp = udp->seq1;
4155   for (i = 0; i < udp->old5; i++) {
4156     ch = *tmp;
4157     *ptr = ch;
4158     tmp++;
4159     ptr++;
4160   }
4161     
4162   tmp = udp->seq2 + udp->new5;
4163   for (i = 0; i < udp->newa + udp->new3; i++) {
4164     ch = *tmp;
4165     *ptr = ch;
4166     tmp++;
4167     ptr++;
4168   }
4169 
4170   *ptr = '\0';
4171   bs = BSNew (newlen);
4172   BSWrite (bs, (VoidPtr) str, newlen);
4173 
4174   udp->seq2 = MemFree (udp->seq2);
4175   udp->seq2 = str;
4176 
4177   if (bs != NULL && BSLen (bs) < 1) {
4178     bs = BSFree (bs);
4179   }
4180   if (bs == NULL) return FALSE;
4181 
4182   /* overlap turned into replacement sequence */
4183 
4184   newbsp = udp->newbsp;
4185   newbsp->seq_data = SeqDataFree (newbsp->seq_data, newbsp->seq_data_type);
4186   newbsp->seq_data = (SeqDataPtr) bs;
4187   newbsp->seq_data_type = Seq_code_iupacna;
4188   newbsp->length = newlen;
4189 
4190   /* adjust alignment and reindex */
4191 
4192   if (! AdjustAlignment (udp, 3)) return FALSE;
4193 
4194   /* then finish by replacing with new sequence */
4195 
4196   return ReplaceSequence (udp);
4197 }
4198 
4199 static Boolean ExtendFeatures (UpsDataPtr udp, Int4 offset);
4200 
4201 /*------------------------------------------------------------------*/
4202 /*                                                                  */
4203 /*  Merge5PrimeNoOverlap () -- Merge a new sequence onto the 5' end */
4204 /*                             of an existing sequence.             */
4205 /*                                                                  */
4206 /*                             Performs a similar function to       */
4207 /*                             Merge5Prime() except works when      */
4208 /*                             there is no alignment between the    */
4209 /*                             two sequences.                       */
4210 /*                                                                  */
4211 /*------------------------------------------------------------------*/
4212 
4213 static Boolean Merge5PrimeNoOverlap (UpsDataPtr udp)
4214 
4215 {
4216   CharPtr       origSeqStr;
4217   CharPtr       newSeqStr;
4218   CharPtr       mergedSeqStr;
4219   Int4          mergedLen;
4220   ByteStorePtr  mergedBS;
4221 
4222   /* Get original and new sequences */
4223 
4224   origSeqStr = GetSequenceByBsp (udp->oldbsp);
4225   newSeqStr = GetSequenceByBsp (udp->newbsp);
4226 
4227   /* Concatenate the new sequence onto the beginning */
4228   /* (i.e. the 5' end) of the original sequence.     */
4229 
4230   mergedLen =  StringLen (newSeqStr) + StringLen (origSeqStr);
4231   mergedSeqStr = (CharPtr) MemNew (mergedLen + 1);
4232   sprintf (mergedSeqStr, "%s%s", newSeqStr, origSeqStr);
4233 
4234   /* Convert the new sequence into a ByteStore */
4235 
4236   mergedBS = BSNew (mergedLen);
4237   BSWrite (mergedBS, (VoidPtr) mergedSeqStr, mergedLen);
4238 
4239   /* Replace the original sequence with the */
4240   /* new concatenated sequence.             */
4241 
4242   udp->newbsp->seq_data      = SeqDataFree (udp->newbsp->seq_data, udp->newbsp->seq_data_type);
4243   udp->newbsp->seq_data      = (SeqDataPtr) mergedBS;
4244   udp->newbsp->seq_data_type = Seq_code_iupacna;
4245   udp->newbsp->length        = mergedLen;
4246 
4247   /* Replace the merged sequence and return */
4248 
4249   return ExtendFeatures (udp, StringLen (newSeqStr));
4250 }
4251 
4252 /*------------------------------------------------------------------*/
4253 /*                                                                  */
4254 /*  Merge3PrimeNoOverlap () -- Merge a new sequence onto the 3' end */
4255 /*                             of an existing sequence.             */
4256 /*                                                                  */
4257 /*                             Performs a similar function to       */
4258 /*                             Merge3Prime() except works when      */
4259 /*                             there is no alignment between the    */
4260 /*                             two sequences.                       */
4261 /*                                                                  */
4262 /*------------------------------------------------------------------*/
4263 
4264 static Boolean Merge3PrimeNoOverlap (UpsDataPtr udp)
4265 
4266 {
4267   CharPtr       origSeqStr;
4268   CharPtr       newSeqStr;
4269   CharPtr       mergedSeqStr;
4270   Int4          mergedLen;
4271   ByteStorePtr  mergedBS;
4272 
4273   /* Get original and new sequences */
4274 
4275   origSeqStr = GetSequenceByBsp (udp->oldbsp);
4276   newSeqStr = GetSequenceByBsp (udp->newbsp);
4277 
4278   /* Concatenate the new sequence onto the end   */
4279   /* (i.e. the 3' end) of the original sequence. */
4280 
4281   mergedLen =  StringLen (newSeqStr) + StringLen (origSeqStr);
4282   mergedSeqStr = (CharPtr) MemNew (mergedLen + 1);
4283   sprintf (mergedSeqStr, "%s%s", origSeqStr, newSeqStr);
4284 
4285   /* Convert the new sequence into a ByteStore */
4286 
4287   mergedBS = BSNew (mergedLen);
4288   BSWrite (mergedBS, (VoidPtr) mergedSeqStr, mergedLen);
4289 
4290   /* Replace the original sequence with the */
4291   /* new concatenated sequence.             */
4292 
4293   udp->newbsp->seq_data      = SeqDataFree (udp->newbsp->seq_data, udp->newbsp->seq_data_type);
4294   udp->newbsp->seq_data      = (SeqDataPtr) mergedBS;
4295   udp->newbsp->seq_data_type = Seq_code_iupacna;
4296   udp->newbsp->length        = mergedLen;
4297 
4298   /* Replace the merged sequence and return */
4299 
4300   return ExtendFeatures (udp, 0);
4301 }
4302 
4303 static Boolean OkToPatchDelta (UpsDataPtr udp)
4304 {
4305   Boolean rval = TRUE;
4306   
4307   if (udp == NULL || udp->oldbsp == NULL || udp->newbsp == NULL
4308       || udp->oldbsp->repr != Seq_repr_delta || udp->newbsp->repr != Seq_repr_delta
4309       || udp->oldbsp->seq_ext_type != 4 || udp->newbsp->seq_ext_type != 4)
4310   {
4311     rval = FALSE;
4312   }
4313 
4314   return rval;
4315 }
4316 
4317 static void SplitDeltaSeq (DeltaSeqPtr dsp, Int4 offset)
4318 {
4319   SeqLocPtr   slp1, slp2;
4320   SeqLitPtr   slip1, slip2;
4321   Int4        len;
4322   Boolean     changed;
4323   DeltaSeqPtr dsp_new;
4324   ByteStorePtr bs_1, bs_2;
4325   Int2         residue;
4326   Int4         pos;
4327   
4328   if (dsp == NULL || dsp->data.ptrvalue == NULL || offset == 0)
4329   {
4330     return;
4331   }
4332   
4333   if (dsp->choice == 1)
4334   {
4335     slp1 = (SeqLocPtr)(dsp->data.ptrvalue);
4336     len = SeqLocLen (slp1);
4337     if (offset > len)
4338     {
4339       return;
4340     }
4341     slp2 = (SeqLocPtr) AsnIoMemCopy (slp1, (AsnReadFunc) SeqLocAsnRead,
4342                                      (AsnWriteFunc) SeqLocAsnWrite);
4343     slp1 = SeqLocDelete (slp1, SeqLocId (slp1), 
4344                           offset, len - 1, FALSE, &changed);
4345     slp2 = SeqLocDelete (slp2, SeqLocId (slp2),
4346                          0, offset, FALSE, &changed);
4347     dsp_new = ValNodeNew (NULL);
4348     dsp_new->choice = 1;
4349     dsp_new->data.ptrvalue = slp2;
4350     dsp_new->next = dsp->next;
4351     dsp->next = dsp_new;
4352   }
4353   else if (dsp->choice == 2)
4354   {
4355     slip1 = (SeqLitPtr) dsp->data.ptrvalue;
4356     if (offset > slip1->length)
4357     {
4358       return;
4359     }
4360     if (IsDeltaSeqGap (dsp))
4361     {
4362       /* use AsnIoMemCopy, to automatically copy gap data if present */
4363       slip2 = (SeqLitPtr) AsnIoMemCopy (slip1, (AsnReadFunc) SeqLitAsnRead, (AsnWriteFunc) SeqLitAsnWrite);
4364       slip2->length = slip1->length - offset;
4365       slip1->length = offset;
4366     }
4367     else
4368     {
4369       slip2 = SeqLitNew ();
4370       if (slip1->seq_data_type == Seq_code_iupacna)
4371       {
4372         bs_1 = (ByteStorePtr) slip1->seq_data;
4373       }
4374       else
4375       {
4376         bs_1 = BSConvertSeq((ByteStorePtr) slip1->seq_data, Seq_code_iupacna, 
4377                               slip1->seq_data_type, 
4378                               slip1->length);
4379         slip1->seq_data_type = Seq_code_iupacna;
4380         slip1->seq_data = (SeqDataPtr) bs_1;
4381       }
4382       bs_2 = BSNew (slip1->length - offset);
4383       pos = offset;
4384       BSSeek(bs_1, pos, SEEK_SET);
4385       BSSeek (bs_2, 0L, SEEK_SET);
4386       while (pos < slip1->length)
4387       {
4388         residue = BSGetByte (bs_1);
4389         BSPutByte (bs_2, residue);
4390         pos++;
4391       }
4392       BSSeek(bs_1, offset, SEEK_SET);
4393       BSDelete(bs_1, slip1->length - offset);
4394       
4395       slip2->seq_data = (SeqDataPtr) bs_2;
4396       slip2->seq_data_type = slip1->seq_data_type;
4397       slip2->length = slip1->length - offset;
4398       slip1->length = offset;
4399     }
4400     dsp_new = ValNodeNew (NULL);
4401     dsp_new->choice = 2;
4402     dsp_new->data.ptrvalue = slip2;
4403     dsp_new->next = dsp->next;
4404     dsp->next = dsp_new;
4405   }
4406 }
4407 
4408 /* This function will patch a delta sequence with another delta sequence.
4409  * The pieces in the overlap from the old sequence will be replaced by pieces
4410  * in the overlap from the new sequence.
4411  */
4412 static Boolean PatchDeltaSequence (UpsDataPtr udp)
4413 
4414 {
4415   Int4        currnew_pos = 0, currold_pos;
4416   SeqLitPtr   slip, slip_new;
4417   DeltaSeqPtr dspold, dspnew;
4418   Int4        seqstart;
4419   DeltaSeqPtr new_list = NULL;
4420   
4421   if (! OkToPatchDelta (udp))
4422   {
4423     return FALSE;
4424   }
4425 
4426   /* keep old 5' end intact */
4427   currold_pos = 0;
4428   seqstart = 0;
4429   dspold = (DeltaSeqPtr) udp->oldbsp->seq_ext;
4430   while (dspold != NULL && currold_pos < udp->old5)
4431   {
4432     seqstart = currold_pos;
4433     if (dspold->data.ptrvalue == NULL || dspold->choice != 2)
4434     {
4435       return FALSE;
4436     }
4437     slip = (SeqLitPtr) (dspold->data.ptrvalue);
4438           currold_pos += slip->length;
4439                 if (currold_pos > udp->old5)
4440                 {
4441       SplitDeltaSeq (dspold, udp->old5 - seqstart);
4442       slip = (SeqLitPtr) (dspold->data.ptrvalue);
4443       currold_pos = udp->old5;            
4444                 }
4445                 slip_new = (SeqLitPtr) AsnIoMemCopy (slip, (AsnReadFunc) SeqLitAsnRead,
4446                                                      (AsnWriteFunc) SeqLitAsnWrite);
4447                 ValNodeAddPointer (&new_list, 2, slip_new);
4448           dspold = dspold->next;
4449   }
4450   
4451   /* skip over new 5' end */
4452   currnew_pos = 0;
4453   seqstart = 0;
4454   dspnew = (DeltaSeqPtr) udp->newbsp->seq_ext;
4455   while (dspnew != NULL && currnew_pos < udp->new5)
4456   {
4457     seqstart = currold_pos;
4458     if (dspnew->data.ptrvalue == NULL || dspnew->choice != 2)
4459     {
4460       return FALSE;
4461     }
4462           slip = (SeqLitPtr) (dspnew->data.ptrvalue);
4463           currnew_pos += slip->length;
4464           if (currnew_pos > udp->new5)
4465           {
4466       SplitDeltaSeq (dspnew, udp->new5 - seqstart);
4467       currnew_pos = udp->new5;
4468           }
4469           dspnew = dspnew->next;
4470   }
4471   
4472   /* copy in new overlap */
4473   while (dspnew != NULL && currnew_pos < udp->new5 + udp->newa)
4474   {
4475     seqstart = currold_pos;
4476     if (dspnew->data.ptrvalue == NULL || dspnew->choice != 2)
4477     {
4478       return FALSE;
4479     }
4480           slip = (SeqLitPtr) (dspnew->data.ptrvalue);
4481           currnew_pos += slip->length;
4482                 if (currnew_pos > udp->new5 + udp->newa)
4483                 {
4484       SplitDeltaSeq (dspnew, udp->new5 + udp->newa - seqstart);
4485       slip = (SeqLitPtr) (dspnew->data.ptrvalue);
4486       currnew_pos = udp->new5 + udp->newa;                
4487                 }
4488                 slip_new = (SeqLitPtr) AsnIoMemCopy (slip, (AsnReadFunc) SeqLitAsnRead,
4489                                                      (AsnWriteFunc) SeqLitAsnWrite);
4490                 ValNodeAddPointer (&new_list, 2, slip_new);
4491                 dspnew = dspnew->next;
4492   }
4493   
4494   /* skip over old overlap */
4495   
4496   while (dspold != NULL && currold_pos < udp->old5 + udp->olda)
4497   {
4498     seqstart = currold_pos;
4499     if (dspold->data.ptrvalue == NULL || dspold->choice != 2)
4500     {
4501       return FALSE;
4502     }
4503     slip = (SeqLitPtr) (dspold->data.ptrvalue);
4504     currold_pos += slip->length;
4505     if (currold_pos > udp->old5 + udp->olda)
4506     {
4507       SplitDeltaSeq (dspold, udp->new5 + udp->newa - seqstart);
4508       currold_pos = udp->old5 + udp->olda;                      
4509     }
4510     dspold = dspold->next;
4511   }
4512   
4513   /* copy in old 3' */
4514   
4515   while (dspold != NULL)
4516   {
4517     if (dspold->data.ptrvalue == NULL || dspold->choice != 2)
4518     {
4519       return FALSE;
4520     }
4521     slip = (SeqLitPtr) (dspold->data.ptrvalue);
4522                 slip_new = (SeqLitPtr) AsnIoMemCopy (slip, (AsnReadFunc) SeqLitAsnRead,
4523                                                      (AsnWriteFunc) SeqLitAsnWrite);
4524                 ValNodeAddPointer (&new_list, 2, slip_new);
4525                 dspold = dspold->next;
4526   }
4527   
4528   /* free newbsp's old SeqLit List */
4529   for (dspnew = (DeltaSeqPtr) udp->newbsp->seq_ext;
4530        dspnew != NULL; 
4531        dspnew = dspnew->next)
4532   {
4533     slip = (SeqLitPtr) (dspnew->data.ptrvalue);
4534     SeqLitFree (slip);
4535   }
4536   udp->newbsp->seq_ext = ValNodeFree (udp->newbsp->seq_ext);
4537   udp->newbsp->seq_ext = new_list;
4538   udp->newbsp->length = udp->old5 + udp->newa + udp->old3;
4539   return TRUE;  
4540 }
4541 
4542 static Boolean OkToPatchRaw (UpsDataPtr udp)
4543 {
4544   Boolean rval = TRUE;
4545   
4546   if (udp == NULL || udp->oldbsp == NULL || udp->newbsp == NULL
4547       || udp->oldbsp->repr != Seq_repr_raw || udp->newbsp->repr != Seq_repr_raw)
4548   {
4549     rval = FALSE;
4550   }
4551 
4552   return rval;
4553 }
4554 
4555 static Boolean PatchRawSequence (UpsDataPtr udp)
4556 
4557 {
4558   ByteStorePtr  bs;
4559   Char          ch;
4560   Int4          i, newlen;
4561   BioseqPtr     newbsp;
4562   CharPtr       ptr, str, tmp;
4563 
4564   newlen = udp->old5 + udp->newa + udp->old3;
4565   str = (CharPtr) MemNew (sizeof (Char) * (size_t) (newlen + 5));
4566   if (str == NULL) return FALSE;
4567 
4568   /* construct replacement sequence by double recombination */
4569   ptr = str;
4570 
4571   tmp = udp->seq1;
4572   for (i = 0; i < udp->old5; i++) {
4573     ch = *tmp;
4574     *ptr = ch;
4575     tmp++;
4576     ptr++;
4577   }
4578 
4579   tmp = udp->seq2 + udp->new5;
4580   for (i = 0; i < udp->newa; i++) {
4581     ch = *tmp;
4582     *ptr = ch;
4583     tmp++;
4584     ptr++;
4585   }
4586 
4587   tmp = udp->seq1 + udp->old5 + udp->olda;
4588   for (i = 0; i < udp->old3; i++) {
4589     ch = *tmp;
4590     *ptr = ch;
4591     tmp++;
4592     ptr++;
4593   }
4594 
4595   *ptr = '\0';
4596   bs = BSNew (newlen);
4597   BSWrite (bs, (VoidPtr) str, newlen);
4598 
4599   udp->seq2 = MemFree (udp->seq2);
4600   udp->seq2 = str;
4601 
4602   if (bs != NULL && BSLen (bs) < 1) {
4603     bs = BSFree (bs);
4604   }
4605   if (bs == NULL) return FALSE;
4606 
4607   /* overlap turned into replacement sequence */
4608 
4609   newbsp = udp->newbsp;
4610   newbsp->seq_data = SeqDataFree (newbsp->seq_data, newbsp->seq_data_type);
4611   newbsp->seq_data = (SeqDataPtr) bs;
4612   newbsp->seq_data_type = Seq_code_iupacna;
4613   newbsp->length = newlen;
4614   return TRUE;  
4615 }
4616 
4617 static Boolean PatchSequence (UpsDataPtr udp)
4618 
4619 {
4620   Boolean rval = FALSE;
4621 
4622   if (OkToPatchRaw (udp))
4623   {
4624     rval = PatchRawSequence (udp);
4625   }
4626   else if (OkToPatchDelta (udp))
4627   {
4628     rval = PatchDeltaSequence (udp);
4629   }
4630   
4631   if (!rval)
4632   {
4633     return rval;
4634   }
4635 
4636   /* adjust alignment and reindex */
4637 
4638   if (! AdjustAlignment (udp, 4)) return FALSE;
4639 
4640   /* then finish by replacing with new sequence */
4641 
4642   return ReplaceSequence (udp);
4643 }
4644 
4645 static void MarkProductForDeletion (
4646   SeqLocPtr product
4647 )
4648 
4649 {
4650   BioseqPtr  bsp;
4651   SeqIdPtr   sip;
4652 
4653   if (product == NULL) return;
4654   sip = SeqLocId (product);
4655   if (sip == NULL) return;
4656   bsp = BioseqFind (sip);
4657   if (bsp == NULL) return;
4658   bsp->idx.deleteme = TRUE;
4659 }
4660 
4661 static void CombineTexts (
4662   CharPtr PNTR txtptr,
4663   CharPtr PNTR oldtxtptr
4664 )
4665 
4666 {
4667   size_t     len;
4668   CharPtr    str;
4669 
4670   if (txtptr == NULL || oldtxtptr == NULL) return;
4671 
4672   if (*txtptr == NULL) {
4673 
4674     *txtptr = *oldtxtptr;
4675     *oldtxtptr = NULL;
4676 
4677   } else if (*oldtxtptr != NULL && StringICmp (*txtptr, *oldtxtptr) != 0) {
4678 
4679     len = StringLen (*txtptr) + StringLen (*oldtxtptr) + 5;
4680     str = MemNew (sizeof (Char) * len);
4681     StringCpy (str, *txtptr);
4682     StringCat (str, "; ");
4683     StringCat (str, *oldtxtptr);
4684     *txtptr = MemFree (*txtptr);
4685     *txtptr = str;
4686   }
4687 }
4688 
4689 static void FuseCommonFeatureFields (
4690   SeqFeatPtr sfp,
4691   SeqFeatPtr oldsfp
4692 )
4693 
4694 {
4695   GBQualPtr       lastgbq;
4696   SeqFeatXrefPtr  lastxref;
4697 
4698   if (sfp == NULL || oldsfp == NULL) return;
4699 
4700   CombineTexts (&(sfp->comment), &(oldsfp->comment));
4701   CombineTexts (&(sfp->title), &(oldsfp->title));
4702   CombineTexts (&(sfp->except_text), &(oldsfp->except_text));
4703 
4704   if (sfp->qual == NULL) {
4705     sfp->qual = oldsfp->qual;
4706     oldsfp->qual = NULL;
4707   } else if (oldsfp->qual != NULL) {
4708     for (lastgbq = sfp->qual; lastgbq->next != NULL; lastgbq = lastgbq->next) continue;
4709     lastgbq->next = oldsfp->qual;
4710     oldsfp->qual = NULL;
4711   }
4712 
4713   ValNodeLink (&(sfp->dbxref), oldsfp->dbxref);
4714   oldsfp->dbxref = NULL;
4715 
4716   ValNodeLink (&(sfp->cit), oldsfp->cit);
4717   oldsfp->cit = NULL;
4718 
4719   if (sfp->xref == NULL) {
4720     sfp->xref = oldsfp->xref;
4721     oldsfp->xref = NULL;
4722   } else if (oldsfp->xref != NULL) {
4723     for (lastxref = sfp->xref; lastxref->next != NULL; lastxref = lastxref->next) continue;
4724     lastxref->next = oldsfp->xref;
4725     oldsfp->xref = NULL;
4726   }
4727 
4728   if (sfp->ext == NULL) {
4729     sfp->ext = oldsfp->ext;
4730     oldsfp->ext = NULL;
4731   } else if (oldsfp->ext != NULL) {
4732     sfp->ext = CombineUserObjects (sfp->ext, oldsfp->ext);
4733     oldsfp->ext = NULL;
4734   }
4735 
4736   sfp->partial |= oldsfp->partial;
4737   sfp->excpt |= oldsfp->excpt;
4738   sfp->pseudo |= oldsfp->pseudo;
4739 }
4740 
4741 static void FuseFeatures (
4742   SeqFeatPtr sfp,
4743   SeqFeatPtr oldsfp
4744 )
4745 
4746 {
4747   GeneRefPtr      grp, oldgrp;
4748   BioseqPtr       prod, oldprod;
4749   SeqFeatPtr      prot, oldprot;
4750   ProtRefPtr      prp, oldprp;
4751   RnaRefPtr       rrp, oldrrp;
4752   SeqIdPtr        sip;
4753 
4754   if (sfp == NULL || oldsfp == NULL) return;
4755 
4756   /* merge common fields */
4757 
4758   FuseCommonFeatureFields (sfp, oldsfp);
4759 
4760   /* now deal with type-specific data */
4761 
4762   switch (sfp->data.choice) {
4763     case SEQFEAT_GENE :
4764       grp = (GeneRefPtr) sfp->data.value.ptrvalue;
4765       oldgrp = (GeneRefPtr) oldsfp->data.value.ptrvalue;
4766       if (grp == NULL || oldgrp == NULL) return;
4767       CombineTexts (&(grp->locus), &(oldgrp->locus));
4768       CombineTexts (&(grp->allele), &(oldgrp->allele));
4769       CombineTexts (&(grp->desc), &(oldgrp->desc));
4770       CombineTexts (&(grp->maploc), &(oldgrp->maploc));
4771       CombineTexts (&(grp->locus_tag), &(oldgrp->locus_tag));
4772       grp->pseudo |= oldgrp->pseudo;
4773       ValNodeLink (&(grp->db), oldgrp->db);
4774       oldgrp->db = NULL;
4775       ValNodeLink (&(grp->syn), oldgrp->syn);
4776       oldgrp->syn = NULL;
4777       break;
4778     case SEQFEAT_CDREGION :
4779       sip = SeqLocId (sfp->product);
4780       prod = BioseqFind (sip);
4781       sip = SeqLocId (oldsfp->product);
4782       oldprod = BioseqFind (sip);
4783       if (prod == NULL || oldprod == NULL) return;
4784       prot = SeqMgrGetBestProteinFeature (prod, NULL);
4785       oldprot = SeqMgrGetBestProteinFeature (oldprod, NULL);
4786       if (prot == NULL || oldprot == NULL) return;
4787       FuseCommonFeatureFields (prot, oldprot);
4788       prp = (ProtRefPtr) prot->data.value.ptrvalue;
4789       oldprp = (ProtRefPtr) oldprot->data.value.ptrvalue;
4790       if (prp == NULL || oldprp == NULL) return;
4791       ValNodeLink (&(prp->name), oldprp->name);
4792       oldprp->name = NULL;
4793       ValNodeLink (&(prp->ec), oldprp->ec);
4794       oldprp->ec = NULL;
4795       ValNodeLink (&(prp->activity), oldprp->activity);
4796       oldprp->activity = NULL;
4797       ValNodeLink (&(prp->db), oldprp->db);
4798       oldprp->db = NULL;
4799       CombineTexts (&(prp->desc), &(oldprp->desc));
4800       break;
4801     case SEQFEAT_RNA :
4802       rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
4803       oldrrp = (RnaRefPtr) oldsfp->data.value.ptrvalue;
4804       if (rrp == NULL || oldrrp == NULL) return;
4805       if (rrp->ext.choice == 1 && oldrrp->ext.choice == 1) {
4806         CombineTexts ((CharPtr PNTR) &(rrp->ext.value.ptrvalue), (CharPtr PNTR) &(oldrrp->ext.value.ptrvalue));
4807       }
4808       break;
4809     case SEQFEAT_REGION :
4810     case SEQFEAT_COMMENT :
4811       if (sfp->data.value.ptrvalue == NULL || oldsfp->data.value.ptrvalue == NULL) return;
4812       CombineTexts ((CharPtr PNTR) &(sfp->data.value.ptrvalue), (CharPtr PNTR) &(oldsfp->data.value.ptrvalue));
4813       break;
4814     default :
4815       break;
4816   }
4817 }
4818 
4819 static void RemoveOldFeatsInRegion (
4820   UpsDataPtr udp,
4821   BioseqPtr bsp,
4822   SeqAnnotPtr sap
4823 )
4824 
4825 {
4826   SeqMgrFeatContext  context;
4827   Int4               left, right;
4828   SeqFeatPtr         sfp;
4829 
4830   if (udp == NULL || bsp == NULL || sap == NULL) return;
4831   if (sap->type != 1) return;
4832 
4833   left = INT4_MAX;
4834   right = INT4_MIN;
4835 
4836   for (sfp = (SeqFeatPtr) sap->data; sfp != NULL; sfp = sfp->next) {
4837     if (sfp != SeqMgrGetDesiredFeature (0, bsp, 0, 0, sfp, &context)) continue;
4838     left = MIN (left, context.left);
4839     right = MAX (right, context.right);
4840   }
4841 
4842   sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &context);
4843 
4844   while (sfp != NULL) {
4845 
4846     if (context.sap != sap && context.right >= left && context.left <= right) {
4847       sfp->idx.deleteme = TRUE;
4848       MarkProductForDeletion (sfp->product);
4849     }
4850 
4851     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &context);
4852   }
4853 }
4854 
4855 static void RemoveOldFeats (BioseqPtr bsp)
4856 
4857 {
4858   SeqMgrFeatContext  context;
4859   SeqFeatPtr         sfp;
4860 
4861   if (bsp == NULL) return;
4862 
4863   sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &context);
4864 
4865   while (sfp != NULL) 
4866   {
4867     sfp->idx.deleteme = TRUE;
4868     MarkProductForDeletion (sfp->product);
4869     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &context);
4870   }
4871 }
4872 
4873 
4874 static void ResolveDuplicateFeats (
4875   UpsDataPtr udp,
4876   BioseqPtr bsp,
4877   SeqAnnotPtr sap
4878 )
4879 
4880 {
4881   SeqMgrFeatContext  context, lastcontext;
4882   Int2               i, j;
4883   Boolean            ivalssame;
4884   SeqFeatPtr         lastsfp = NULL, sfp;
4885   Int2               nobmval;
4886 
4887   if (udp == NULL || bsp == NULL || sap == NULL) return;
4888 
4889   nobmval = GetValue (udp->nobm);
4890   if (nobmval == UPDATE_FEAT_DUP_USE_BOTH) return; /* keep both */
4891 
4892   SeqMgrIndexFeatures (0, (Pointer) bsp);
4893 
4894   if (nobmval == UPDATE_FEAT_DUP_REPLACE) {
4895     RemoveOldFeatsInRegion (udp, bsp, sap);
4896     return;
4897   }
4898 
4899   lastsfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &context);
4900   if (lastsfp == NULL) return;
4901 
4902   MemCopy ((Pointer) &lastcontext, (Pointer) &context, sizeof (SeqMgrFeatContext));
4903 
4904   sfp = SeqMgrGetNextFeature (bsp, lastsfp, 0, 0, &context);
4905   if (sfp == NULL) return;
4906 
4907   while (sfp != NULL) {
4908 
4909     if (context.left == lastcontext.left &&
4910         context.right == lastcontext.right &&
4911         context.featdeftype == lastcontext.featdeftype) {
4912 
4913       if (context.strand == lastcontext.strand ||
4914           lastcontext.strand == Seq_strand_unknown ||
4915           context.strand == Seq_strand_unknown) {
4916 
4917         ivalssame = TRUE;
4918         if (context.numivals != lastcontext.numivals ||
4919             context.ivals == NULL ||
4920             lastcontext.ivals == NULL) {
4921 
4922           ivalssame = FALSE;
4923 
4924         } else {
4925 
4926           for (i = 0, j = 0; i < lastcontext.numivals; i++, j += 2) {
4927             if (context.ivals [j] != lastcontext.ivals [j]) {
4928               ivalssame = FALSE;
4929             }
4930             if (context.ivals [j + 1] != lastcontext.ivals [j + 1]) {
4931               ivalssame = FALSE;
4932             }
4933           }
4934         }
4935 
4936         if (ivalssame &&
4937             context.sap != lastcontext.sap &&
4938             (context.sap == sap || lastcontext.sap == sap)) {
4939 
4940           if (nobmval == UPDATE_FEAT_DUP_USE_NEW) { /* keep new */
4941             if (context.sap == sap) {
4942               lastsfp->idx.deleteme = TRUE;
4943               MarkProductForDeletion (lastsfp->product);
4944             } else if (lastcontext.sap == sap) {
4945               sfp->idx.deleteme = TRUE;
4946               MarkProductForDeletion (sfp->product);
4947             }
4948 
4949           } else if (nobmval == UPDATE_FEAT_DUP_USE_OLD) { /* keep old */
4950             if (context.sap == sap) {
4951               sfp->idx.deleteme = TRUE;
4952               MarkProductForDeletion (sfp->product);
4953             } else if (lastcontext.sap == sap) {
4954               lastsfp->idx.deleteme = TRUE;
4955               MarkProductForDeletion (lastsfp->product);
4956             }
4957 
4958           } else if (nobmval == UPDATE_FEAT_DUP_MERGE) { /* merge */
4959             if (context.sap == sap) {
4960               FuseFeatures (sfp, lastsfp);
4961               lastsfp->idx.deleteme = TRUE;
4962               MarkProductForDeletion (lastsfp->product);
4963             } else if (lastcontext.sap == sap) {
4964               FuseFeatures (lastsfp, sfp);
4965               sfp->idx.deleteme = TRUE;
4966               MarkProductForDeletion (sfp->product);
4967             }
4968           }
4969         }
4970       }
4971     }
4972 
4973     lastsfp = sfp;
4974     MemCopy ((Pointer) &lastcontext, (Pointer) &context, sizeof (SeqMgrFeatContext));
4975 
4976     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &context);
4977   }
4978 }
4979 
4980 extern void AddCitSubToUpdatedSequence (BioseqPtr upd_bsp, Uint2 input_entityID, CharPtr update_txt)
4981 {
4982   SeqEntryPtr top_sep, upd_sep;
4983 
4984   upd_sep = SeqMgrGetSeqEntryForData (upd_bsp);
4985   if (upd_sep == NULL) return;
4986   top_sep = GetTopSeqEntryForEntityID ( input_entityID);
4987   if (top_sep == NULL) return;
4988   CreateUpdateCitSubFromBestTemplate (top_sep, upd_sep, update_txt);
4989 }
4990 
4991 static Boolean ExtendFeatures (UpsDataPtr udp, Int4 offset)
4992 
4993 {
4994   MsgAnswer          ans;
4995   CodeBreakPtr       cbp;
4996   SeqMgrFeatContext  context;
4997   CdRegionPtr        crp;
4998   Int4               len;
4999   BioseqPtr          newbsp;
5000   BioseqPtr          oldbsp;
5001   RnaRefPtr          rrp;
5002   Uint1              seq_data_type;
5003   SeqFeatPtr         sfp;
5004   SeqIdPtr           sip;
5005   tRNAPtr            trp;
5006   SeqDataPtr         sdp;
5007 
5008   if (udp->salp != NULL)
5009     if (FALSE == udp->isSet)
5010       if (StringICmp (udp->seq1, udp->seq2) == 0) {
5011         ans = Message (MSG_OKC, "Replacement sequence is identical to"
5012                        " original - possible error");
5013         if (ans == ANS_CANCEL) return FALSE;
5014       }
5015 
5016   oldbsp = udp->oldbsp;
5017   newbsp = udp->newbsp;
5018 
5019   sip = SeqIdFindBest (oldbsp->id, 0);
5020   if (sip == NULL) return FALSE;
5021 
5022   if (offset > 0) {
5023     sfp = SeqMgrGetNextFeature (oldbsp, NULL, 0, 0, &context);
5024     while (sfp != NULL) {
5025       OffsetLocation (sfp->location, offset, sip);
5026       switch (sfp->data.choice) {
5027         case SEQFEAT_CDREGION :
5028           crp = (CdRegionPtr) sfp->data.value.ptrvalue;
5029           if (crp != NULL) {
5030             for (cbp = crp->code_break; cbp != NULL; cbp = cbp->next) {
5031               OffsetLocation (cbp->loc, offset, sip);
5032             }
5033           }
5034           break;
5035         case SEQFEAT_RNA :
5036           rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
5037           if (rrp != NULL && rrp->ext.choice == 2) {
5038             trp = (tRNAPtr) rrp->ext.value.ptrvalue;
5039             if (trp != NULL && trp->anticodon != NULL) {
5040               OffsetLocation (trp->anticodon, offset, sip);
5041             }
5042           }
5043           break;
5044         default :
5045           break;
5046       }
5047       sfp = SeqMgrGetNextFeature (oldbsp, sfp, 0, 0, &context);
5048     }
5049   }
5050 
5051   /* switch bioseqs to finish extension */
5052 
5053   sdp = oldbsp->seq_data;
5054   oldbsp->seq_data = newbsp->seq_data;
5055   newbsp->seq_data = sdp;
5056   len = oldbsp->length;
5057   oldbsp->length = newbsp->length;
5058   newbsp->length = len;
5059   seq_data_type = oldbsp->seq_data_type;
5060   oldbsp->seq_data_type = newbsp->seq_data_type;
5061   newbsp->seq_data_type = seq_data_type;
5062 
5063   return TRUE;
5064 }
5065 
5066 static Boolean ExtendBothEnds (UpsDataPtr udp)
5067 
5068 {
5069   ByteStorePtr  bs;
5070   Char          ch;
5071   Int4          i, newlen;
5072   BioseqPtr     newbsp;
5073   BioseqPtr     oldbsp;
5074   CharPtr       ptr, str, tmp;
5075 
5076   /* construct replacement sequence by extending old sequence */
5077 
5078   newlen = udp->new5 + udp->olda + udp->new3;
5079   str = (CharPtr) MemNew (sizeof (Char) * (size_t) (newlen + 5));
5080   if (str == NULL)
5081     return FALSE;
5082   ptr = str;
5083 
5084   tmp = udp->seq2;
5085   for (i = 0; i < udp->new5; i++) {
5086     ch = *tmp;
5087     *ptr = ch;
5088     tmp++;
5089     ptr++;
5090   }
5091     
5092   tmp = udp->seq1 + udp->old5;
5093   for (i = 0; i < udp->olda; i++) {
5094     ch = *tmp;
5095     *ptr = ch;
5096     tmp++;
5097     ptr++;
5098   }
5099 
5100   tmp = udp->seq2 + udp->new5 + udp->newa;
5101   for (i = 0; i < udp->new3; i++) {
5102     ch = *tmp;
5103     *ptr = ch;
5104     tmp++;
5105     ptr++;
5106   }
5107 
5108   *ptr = '\0';
5109   bs = BSNew (newlen);
5110   BSWrite (bs, (VoidPtr) str, newlen);
5111 
5112   udp->seq2 = MemFree (udp->seq2);
5113   udp->seq2 = str;
5114 
5115   if (bs != NULL && BSLen (bs) < 1) {
5116     bs = BSFree (bs);
5117   }
5118   if (bs == NULL) return FALSE;
5119 
5120   /* overlap turned into replacement sequence */
5121 
5122   oldbsp = udp->oldbsp;
5123   newbsp = udp->newbsp;
5124   newbsp->seq_data = SeqDataFree (newbsp->seq_data, newbsp->seq_data_type);
5125   newbsp->seq_data = (SeqDataPtr) bs;
5126   newbsp->seq_data_type = Seq_code_iupacna;
5127   newbsp->length = newlen;
5128 
5129   /* then finish by offsetting features */
5130 
5131   return ExtendFeatures (udp, udp->new5);
5132 }
5133 
5134 static Boolean Extend5Prime (UpsDataPtr udp)
5135 
5136 {
5137   ByteStorePtr  bs;
5138   Char          ch;
5139   Int4          i, newlen;
5140   BioseqPtr     newbsp;
5141   BioseqPtr     oldbsp;
5142   CharPtr       ptr, str, tmp;
5143 
5144   /* construct replacement sequence by extending old sequence */
5145 
5146   newlen = udp->new5 + udp->olda + udp->old3;
5147   str = (CharPtr) MemNew (sizeof (Char) * (size_t) (newlen + 5));
5148   if (str == NULL)
5149     return FALSE;
5150   ptr = str;
5151 
5152   tmp = udp->seq2;
5153   for (i = 0; i < udp->new5; i++) {
5154     ch = *tmp;
5155     *ptr = ch;
5156     tmp++;
5157     ptr++;
5158   }
5159     
5160   tmp = udp->seq1 + udp->old5;
5161   for (i = 0; i < udp->olda + udp->old3; i++) {
5162     ch = *tmp;
5163     *ptr = ch;
5164     tmp++;
5165     ptr++;
5166   }
5167 
5168   *ptr = '\0';
5169   bs = BSNew (newlen);
5170   BSWrite (bs, (VoidPtr) str, newlen);
5171 
5172   udp->seq2 = MemFree (udp->seq2);
5173   udp->seq2 = str;
5174 
5175   if (bs != NULL && BSLen (bs) < 1) {
5176     bs = BSFree (bs);
5177   }
5178   if (bs == NULL) return FALSE;
5179 
5180   /* overlap turned into replacement sequence */
5181 
5182   oldbsp = udp->oldbsp;
5183   newbsp = udp->newbsp;
5184   newbsp->seq_data = SeqDataFree (newbsp->seq_data, newbsp->seq_data_type);
5185   newbsp->seq_data = (SeqDataPtr) bs;
5186   newbsp->seq_data_type = Seq_code_iupacna;
5187   newbsp->length = newlen;
5188 
5189   /* then finish by offsetting features */
5190 
5191   return ExtendFeatures (udp, udp->new5);
5192 }
5193 
5194 static Boolean Extend3Prime (UpsDataPtr udp)
5195 
5196 {
5197   ByteStorePtr  bs;
5198   Char          ch;
5199   Int4          i, newlen;
5200   BioseqPtr     newbsp;
5201   BioseqPtr     oldbsp;
5202   CharPtr       ptr, str, tmp;
5203 
5204   /* construct replacement sequence by extending old sequence */
5205 
5206   newlen = udp->old5 + udp->olda + udp->new3;
5207   str = (CharPtr) MemNew (sizeof (Char) * (size_t) (newlen + 5));
5208   if (str == NULL)
5209     return FALSE;
5210   ptr = str;
5211 
5212   tmp = udp->seq1;
5213   for (i = 0; i < udp->old5 + udp->olda; i++) {
5214     ch = *tmp;
5215     *ptr = ch;
5216     tmp++;
5217     ptr++;
5218   }
5219     
5220   tmp = udp->seq2 + udp->new5 + udp->newa;
5221   for (i = 0; i < udp->new3; i++) {
5222     ch = *tmp;
5223     *ptr = ch;
5224     tmp++;
5225     ptr++;
5226   }
5227 
5228   *ptr = '\0';
5229   bs = BSNew (newlen);
5230   BSWrite (bs, (VoidPtr) str, newlen);
5231 
5232   udp->seq2 = MemFree (udp->seq2);
5233   udp->seq2 = str;
5234 
5235   if (bs != NULL && BSLen (bs) < 1) {
5236     bs = BSFree (bs);
5237   }
5238   if (bs == NULL) return FALSE;
5239 
5240   /* overlap turned into replacement sequence */
5241 
5242   oldbsp = udp->oldbsp;
5243   newbsp = udp->newbsp;
5244   newbsp->seq_data = SeqDataFree (newbsp->seq_data, newbsp->seq_data_type);
5245   newbsp->seq_data = (SeqDataPtr) bs;
5246   newbsp->seq_data_type = Seq_code_iupacna;
5247   newbsp->length = newlen;
5248 
5249   /* no offset, but ExtendFeatures finishes switch */
5250 
5251   return ExtendFeatures (udp, 0);
5252 }
5253 
5254 static Boolean ExtendOneSequence (UpsDataPtr udp)
5255 {
5256   Boolean      update = FALSE;
5257   MsgAnswer    ans;
5258   Uint2        entityID;
5259   CharPtr      errmsg = NULL;
5260   
5261   
5262   if (udp == NULL) return FALSE;
5263   
5264   switch (udp->rmcval) {
5265     case UPDATE_REPLACE :
5266       if (udp->old5 > 0 && udp->old3 > 0) {
5267         errmsg = "Unaligned sequence at 5' and 3' ends.  Do you wish to proceed?";
5268       } else if (udp->old5 > 0) {
5269         errmsg = "Unaligned sequence at 5' end.  Do you wish to proceed?";
5270       } else if (udp->old3 > 0) {
5271         errmsg = "Unaligned sequence at 3' end.  Do you wish to proceed?";
5272       }
5273       break;
5274     case UPDATE_EXTEND5 :
5275       if (udp->old5 > 0) {
5276         errmsg = "Unaligned sequence at 5' end.  Do you wish to proceed?";
5277       }
5278       break;
5279     case UPDATE_EXTEND3 :
5280       if (udp->old3 > 0) {
5281         errmsg = "Unaligned sequence at 3' end.  Do you wish to proceed?";
5282       }
5283       break;
5284     default :
5285       break;
5286   }
5287   if (errmsg != NULL) {
5288     ans = Message (MSG_YN, "%s", errmsg);
5289     if (ans == ANS_NO) {
5290       return FALSE;
5291     }
5292   }
5293 
5294   switch (udp->rmcval) {
5295     case UPDATE_REPLACE :
5296       if (ExtendBothEnds (udp)) {
5297         update = TRUE;
5298       }
5299       break;
5300     case UPDATE_EXTEND5:
5301       if (udp->salp == NULL) {
5302         if (Merge5PrimeNoOverlap (udp)) {
5303           update = TRUE;
5304         }
5305       } else if (Extend5Prime (udp)) {
5306         update = TRUE;
5307       }
5308       break;
5309     case UPDATE_EXTEND3 :
5310       if (udp->salp == NULL) {
5311         if (Merge3PrimeNoOverlap (udp)) {
5312           update = TRUE;
5313         }
5314       } else if (Extend3Prime (udp)) {
5315         update = TRUE;
5316       }
5317       break;
5318     default :
5319       break;
5320   }
5321 
5322   if (update) {
5323       
5324     entityID = ObjMgrGetEntityIDForPointer (udp->oldbsp);
5325     if (GetStatus (udp->add_cit_subs))
5326     {
5327       AddCitSubToUpdatedSequence ( udp->oldbsp, entityID, kSubmitterUpdateText);
5328     }
5329   }
5330   return update;
5331 }
5332 
5333 static void OpenSequenceUpdateLog (UpsDataPtr udp)
5334 {
5335   if (udp == NULL || udp->log_fp != NULL)
5336   {
5337         return;
5338   }
5339   TmpNam (udp->log_path);
5340   udp->log_fp = FileOpen (udp->log_path, "wb");
5341 }
5342 
5343 static void CloseOutSequenceUpdateLog (UpsDataPtr udp)
5344 {
5345   if (udp == NULL || udp->log_fp == NULL) 
5346   {
5347     return;
5348   }
5349   FileClose (udp->log_fp);
5350   udp->log_fp = NULL;
5351   if (udp->data_in_log) {
5352     LaunchGeneralTextViewer (udp->log_path, "Protein changes");
5353     udp->data_in_log = FALSE;
5354   }
5355   FileRemove (udp->log_path);   
5356 }
5357 
5358 
5359 static Boolean PrepareToUpdateSequences (UpsDataPtr udp);
5360 static Boolean PrepareUpdatePtr (UpsDataPtr    udp);
5361 static ForM UpdateSequenceForm (UpsDataPtr udp);
5362 static void UpdateOneSequence (
5363   UpsDataPtr   udp,
5364   Int2         sfbval,
5365   Boolean      add_cit_subs,
5366   Boolean      update_proteins);
5367 
5368 
5369 static Int4 FindNewCDSStop (SeqLocPtr slp, BioseqPtr bsp, Int4 prot_len)
5370 {
5371   Int4      loc_len, tot_len = 0;
5372   SeqLocPtr this_slp;
5373   Int4      curr_start;
5374   
5375   for (this_slp = SeqLocFindNext (slp, NULL);
5376        this_slp != NULL;
5377        this_slp = SeqLocFindNext (slp, this_slp))
5378   {
5379     loc_len = SeqLocLen (this_slp);
5380     curr_start = GetOffsetInBioseq (this_slp, bsp, SEQLOC_START);
5381     if (loc_len + tot_len > prot_len)
5382     {
5383       curr_start = GetOffsetInBioseq (this_slp, bsp, SEQLOC_START);
5384       if (SeqLocStrand (this_slp) == Seq_strand_minus)
5385       {
5386         return curr_start - (prot_len - tot_len) + 1;
5387       }
5388       else
5389       {
5390         return curr_start + prot_len - tot_len - 1;
5391       }
5392     }
5393     tot_len += loc_len;
5394   }
5395   return tot_len;
5396 }
5397 
5398 
5399 static CharPtr FixProteinString
5400 (SeqFeatPtr    sfp,
5401  Uint1         strand,
5402  Boolean       truncate_proteins,
5403  Boolean PNTR  truncated,
5404  Boolean PNTR  contains_start,
5405  Boolean PNTR  contains_stop)
5406 {
5407   ByteStorePtr bs;
5408   BioseqPtr    nucBsp;
5409   CharPtr      newprot;
5410   CharPtr      ptr;
5411   Char         ch;
5412   Int4         start, stop, new_stop, prot_len;
5413   Boolean      changed;
5414   CdRegionPtr  crp;
5415   
5416   if (sfp == NULL || truncated == NULL 
5417       || contains_start == NULL
5418       || contains_stop == NULL) {
5419     return NULL;
5420   }
5421 
5422   bs = ProteinFromCdRegionEx (sfp, TRUE, FALSE);
5423   if (bs == NULL) return NULL;
5424   newprot = BSMerge (bs, NULL);
5425   bs = BSFree (bs);
5426   if (newprot == NULL) return NULL;
5427 
5428   ptr = newprot;
5429   ch = *ptr;
5430   if (ch == 'M') {
5431     *contains_start = TRUE;
5432   } else {
5433     *contains_start = FALSE;
5434   }
5435   *contains_stop = FALSE;
5436   *truncated = FALSE;
5437   while (ch != '\0')
5438   {
5439     *ptr = TO_UPPER (ch);
5440     if (ch == '*') {
5441       *contains_stop = TRUE;
5442       if (*(ptr + 1) == 0 || truncate_proteins) {
5443         *ptr = 0;
5444         if (truncate_proteins && *(ptr + 1) != 0) {
5445           *truncated = TRUE;
5446           nucBsp = BioseqFindFromSeqLoc (sfp->location);
5447           if (nucBsp == NULL) return newprot;
5448           start = GetOffsetInBioseq (sfp->location, nucBsp, SEQLOC_START);
5449           stop = GetOffsetInBioseq (sfp->location, nucBsp, SEQLOC_STOP);
5450           prot_len = (1 + ptr - newprot) * 3;
5451           if (sfp->data.choice == SEQFEAT_CDREGION) {
5452             crp = (CdRegionPtr) sfp->data.value.ptrvalue;
5453             if (crp != NULL) {
5454               if (crp->frame == 2) {
5455                 prot_len += 1;
5456               } else if (crp->frame == 3) {
5457                 prot_len += 2;
5458               }
5459             }
5460           }
5461           new_stop = FindNewCDSStop (sfp->location, nucBsp, prot_len);
5462           if (strand == Seq_strand_minus) {
5463             sfp->location = SeqLocDelete (sfp->location, SeqLocId (sfp->location),
5464                           stop, new_stop - 1, FALSE, &changed);
5465           } else {
5466             sfp->location = SeqLocDelete (sfp->location, SeqLocId (sfp->location),
5467                           new_stop + 1, stop, FALSE, &changed);
5468           }
5469         }
5470         return newprot;
5471       }
5472     }
5473     ptr++;
5474     ch = *ptr;
5475   }
5476   return newprot;
5477 }
5478 
5479 /* This function will truncate base pairs to make the length of the CDS
5480  * a multiple of three.  If truncation occurs, the function returns TRUE,
5481  * otherwise the function returns FALSE.
5482  */
5483 static SeqLocPtr ShiftStopForLengthChange
5484 (SeqLocPtr slp,
5485  BioseqPtr nucBsp,
5486  Int4      transl_except_len,
5487  Boolean PNTR changed)
5488 {
5489   Int4      start, stop, new_stop;
5490   Uint1     strand;
5491   SeqIdPtr  sip;
5492   Int4      len;
5493 
5494   if (slp == NULL || nucBsp == NULL || changed == NULL) {
5495     return NULL;
5496   }
5497 
5498   *changed = FALSE;
5499 
5500   start = GetOffsetInBioseq (slp, nucBsp, SEQLOC_START);
5501   stop = GetOffsetInBioseq (slp, nucBsp, SEQLOC_STOP);
5502   new_stop = stop;
5503   strand = SeqLocStrand (slp);
5504   len = SeqLocLen (slp);
5505 
5506   if (strand == Seq_strand_minus) {
5507     if (len % 3 != transl_except_len) {
5508       new_stop += len % 3 + transl_except_len;
5509       sip = SeqLocId (slp);
5510       slp = SeqLocDelete (slp, sip, stop, new_stop - 1, FALSE, changed);
5511       if (slp == NULL) {
5512         return NULL;
5513       }
5514     }
5515   } else {
5516     if (len % 3 != transl_except_len) {
5517       new_stop -= len % 3 - transl_except_len;
5518       sip = SeqLocId (slp);
5519       slp = SeqLocDelete (slp, sip, new_stop + 1, stop, FALSE, changed);
5520       if (slp == NULL) {
5521         return NULL;
5522       }
5523     }
5524   }
5525   return slp;
5526 }
5527 
5528 extern SeqLocPtr 
5529 ExpandSeqLoc 
5530 (Int4 start,
5531  Int4 stop,
5532  Uint1 strand,
5533  BioseqPtr bsp,
5534  SeqLocPtr slp)
5535 {
5536   Int4      curr_start, curr_stop, tmp_start, tmp_stop;
5537   SeqLocPtr this_slp;
5538 
5539   if (slp == NULL) return NULL;
5540 
5541   if (slp->choice == SEQLOC_INT || slp->choice == SEQLOC_PNT) {
5542     slp = expand_seq_loc (start, stop, strand, slp);
5543   } else {
5544     curr_start = GetOffsetInBioseq (slp, bsp, SEQLOC_START);
5545     curr_stop = GetOffsetInBioseq (slp, bsp, SEQLOC_STOP);
5546     for (this_slp = SeqLocFindNext (slp, NULL);
5547          this_slp != NULL;
5548          this_slp = SeqLocFindNext (slp, this_slp))
5549     {
5550       tmp_start = GetOffsetInBioseq (this_slp, bsp, SEQLOC_START);
5551       tmp_stop = GetOffsetInBioseq (this_slp, bsp, SEQLOC_STOP);
5552       if (strand == Seq_strand_minus) {
5553         if (tmp_start == curr_start && tmp_start < stop) {
5554           this_slp = expand_seq_loc (tmp_stop, stop, strand, this_slp);
5555           tmp_start = stop;
5556         }
5557         if (tmp_stop == curr_stop && tmp_stop > start) {
5558           this_slp = expand_seq_loc (start, tmp_start, strand, this_slp);
5559         }
5560       } else {
5561         if (tmp_start == curr_start && tmp_start > start) {
5562           this_slp = expand_seq_loc (start, tmp_stop, strand, this_slp);
5563           tmp_start = start;
5564         }
5565         if (tmp_stop == curr_stop && tmp_stop < stop) {
5566           this_slp = expand_seq_loc (tmp_start, stop, strand, this_slp);
5567         }
5568       }
5569     }
5570   }
5571   return slp;
5572 }
5573 
5574 static SeqLocPtr ShiftLocationForFrame
5575 (SeqLocPtr slp,
5576  Uint1 frame,
5577  BioseqPtr nucBsp)
5578 {
5579   Int4      max_stop, start, stop;
5580   Uint1     strand;
5581   SeqIdPtr  sip;
5582   Int4      offset, new_start;
5583   Boolean   changed;
5584   
5585 
5586   if (slp == NULL || nucBsp == NULL) return NULL;
5587   if (frame == 0 || frame == 1) return slp;
5588 
5589   start = GetOffsetInBioseq (slp, nucBsp, SEQLOC_START);
5590   stop = GetOffsetInBioseq (slp, nucBsp, SEQLOC_STOP);
5591   strand = SeqLocStrand (slp);
5592   max_stop = nucBsp->length - 1;
5593   new_start = start;
5594  
5595   offset = frame - 1;
5596   sip = SeqLocId (slp);
5597   if (strand == Seq_strand_minus) {
5598     stop -= offset;
5599     new_start = start - offset;
5600     if ((1 + new_start - stop ) % 3 != 0) {
5601       new_start -= (1 + new_start - stop) % 3;
5602     }
5603     if (stop < 0) stop = 0;
5604     slp = ExpandSeqLoc (stop, start, strand, nucBsp, slp);
5605     if (new_start < 0) new_start = 0;
5606     if (new_start < start) {
5607       slp = SeqLocDelete (slp, sip, new_start + 1, start, FALSE, &changed);
5608     }
5609   } else {
5610     stop += offset;
5611     new_start = start + offset;
5612     if ((1 + stop - new_start) % 3 != 0) {
5613       new_start += (1 + stop - new_start) % 3;
5614     }
5615     if (stop > max_stop) stop = max_stop;
5616     slp = ExpandSeqLoc (start, stop, strand, nucBsp, slp);
5617     if (start > max_stop) start = max_stop;
5618     if (new_start > start) {
5619       slp = SeqLocDelete (slp, sip, start, new_start - 1, FALSE, &changed);
5620     }
5621   }
5622   return slp;
5623 }
5624 
5625 static TransTablePtr GetTranslationTable (CdRegionPtr crp, Boolean PNTR table_is_local)
5626 {
5627   TransTablePtr tbl = NULL;
5628   ValNodePtr    vnp;
5629   Int2          genCode = 0;
5630   Char          str [32];
5631 
5632   if (crp == NULL || table_is_local == NULL) return NULL;
5633 
5634   *table_is_local = FALSE;
5635   /* find genetic code */
5636 
5637   if (crp->genetic_code != NULL) {
5638     vnp = (ValNodePtr) crp->genetic_code->data.ptrvalue;
5639     while (vnp != NULL) {
5640       if (vnp->choice == 2) {
5641         genCode = (Int2) vnp->data.intvalue;
5642       }
5643       vnp = vnp->next;
5644     }
5645   }
5646 
5647   if (genCode == 7) {
5648     genCode = 4;
5649   } else if (genCode == 8) {
5650     genCode = 1;
5651   } else if (genCode == 0) {
5652     genCode = 1;
5653   }
5654 
5655   /* set up translation table */
5656   /* set app property name for storing desired FSA */
5657 
5658   sprintf (str, "TransTableFSAforGenCode%d", (int) genCode);
5659 
5660   /* get FSA for desired genetic code if it already exists */
5661 
5662   tbl = (TransTablePtr) GetAppProperty (str);
5663   if (tbl == NULL) {
5664     tbl = TransTableNew (genCode);
5665     *table_is_local = TRUE;
5666   }
5667   return tbl;
5668 }
5669 
5670 static CharPtr ExtendProtein5
5671 (SeqFeatPtr sfp,
5672  Uint2      input_entityID,
5673  Boolean    force_partial)
5674 {
5675   CdRegionPtr   crp;
5676   TransTablePtr tbl = NULL;
5677   Boolean       table_is_local = FALSE;
5678   SeqLocPtr     test_slp;
5679   SeqIdPtr      sip;
5680   BioseqPtr     nucBsp;
5681   Int4          start, new_start;
5682   Int4          stop, new_stop;
5683   Int4          increment = 3000;
5684   Int4          offset;
5685   Uint1         strand;
5686   Boolean       found_start = FALSE;
5687   Boolean       found_stop = FALSE;
5688   Boolean       stop_looking = FALSE;
5689   Int4          dna_len;
5690   CharPtr       bases;
5691   Int4          total;
5692   Int2          state;
5693   CharPtr       codon_start;
5694   Boolean       partial3, partial5;
5695   Boolean       contains_start, contains_stop;
5696   Boolean       changed;
5697   CharPtr       newprot;
5698   Boolean       truncated;
5699  
5700   if (sfp == NULL || sfp->data.choice != SEQFEAT_CDREGION 
5701       || (crp = (CdRegionPtr)sfp->data.value.ptrvalue) == NULL) {
5702     return NULL;
5703   }
5704   nucBsp = GetBioseqGivenSeqLoc (sfp->location, input_entityID);
5705   if (nucBsp == NULL) return NULL;
5706 
5707   tbl = GetTranslationTable (crp, &table_is_local);
5708   if (tbl == NULL) return NULL;
5709 
5710   test_slp = SeqLocMerge (nucBsp, sfp->location, NULL, FALSE, FALSE, FALSE);
5711   strand = SeqLocStrand (sfp->location);
5712   sip = SeqLocId (sfp->location);
5713   offset = -1;
5714 
5715   start = GetOffsetInBioseq (test_slp, nucBsp, SEQLOC_START);
5716   if (start == 0)
5717   {
5718         stop_looking = TRUE;
5719   }
5720  
5721   while (((! found_start && ! found_stop) || force_partial) && ! stop_looking) {
5722     start = GetOffsetInBioseq (test_slp, nucBsp, SEQLOC_START);
5723     stop = GetOffsetInBioseq (test_slp, nucBsp, SEQLOC_STOP);
5724     if (strand == Seq_strand_minus) {
5725       new_start = start + increment;
5726       new_stop = start + 1;
5727       if (new_start > nucBsp->length - 1) {
5728         new_start = start + ((Int4)((nucBsp->length - 1 - start) / 3)) * 3;
5729         stop_looking = TRUE;
5730       }
5731       test_slp = ExpandSeqLoc (stop, new_start, strand, nucBsp, test_slp);
5732       test_slp = SeqLocDelete (test_slp, sip, stop, start, FALSE, &changed);
5733     } else {
5734       new_start = start - increment;
5735       new_stop = start - 1;
5736       if (new_start < 0) {
5737         new_start = start % 3;
5738         stop_looking = TRUE;
5739       }
5740       test_slp = ExpandSeqLoc (new_start, stop, strand, nucBsp, test_slp);
5741       test_slp = SeqLocDelete (test_slp, sip, start, stop, FALSE, &changed);
5742     }
5743     dna_len = SeqLocLen (test_slp);
5744     bases = ReadCodingRegionBases (test_slp, dna_len, crp->frame, &total);
5745     if (bases == NULL) {
5746       stop_looking = TRUE;
5747     } else {
5748       state = 0;
5749       codon_start = bases + StringLen (bases) - 3;
5750       while (codon_start >= bases && ! found_start && ! found_stop) {
5751         state = 0;
5752         state = NextCodonState (tbl, state, (Uint1)*codon_start);
5753         state = NextCodonState (tbl, state, (Uint1)*(codon_start + 1));
5754         state = NextCodonState (tbl, state, (Uint1)*(codon_start + 2));
5755         if (IsOrfStart (tbl, state, TTBL_TOP_STRAND)) {
5756           found_start = TRUE;
5757           if (strand == Seq_strand_minus) {
5758             offset = new_start - (codon_start - bases);
5759           } else {
5760             offset = new_start + codon_start - bases;
5761           }
5762         } else if (IsOrfStop (tbl, state, TTBL_TOP_STRAND)) {
5763           found_stop = TRUE;
5764         } else {
5765           codon_start -= 3;
5766         }
5767       }
5768       MemFree (bases);
5769     }
5770   }
5771   
5772   SeqLocFree (test_slp);
5773   if (! found_stop) { 
5774     start = GetOffsetInBioseq (sfp->location, nucBsp, SEQLOC_START);
5775     stop = GetOffsetInBioseq (sfp->location, nucBsp, SEQLOC_STOP);
5776     if (found_start) {
5777       if (strand == Seq_strand_minus) {
5778         sfp->location = ExpandSeqLoc (stop, offset, strand, nucBsp, sfp->location);
5779       } else {
5780         sfp->location = ExpandSeqLoc (offset, stop, strand, nucBsp, sfp->location);
5781       }
5782     } else {
5783       CheckSeqLocForPartial (sfp->location, &partial5, &partial3);
5784       SetSeqLocPartial (sfp->location, TRUE, partial3);
5785       sfp->partial = TRUE;
5786       if (crp->frame == 0)
5787       {
5788         crp->frame = 1;
5789       }
5790       if (strand == Seq_strand_minus) {
5791         sfp->location = ExpandSeqLoc (stop, nucBsp->length - 1, strand, nucBsp, sfp->location);
5792         crp->frame = (nucBsp->length - 1 - start + crp->frame - 1) % 3 + 1;
5793       } else {
5794         sfp->location = ExpandSeqLoc (0, stop, strand, nucBsp, sfp->location);
5795         crp->frame = (start + crp->frame - 1) % 3 + 1;
5796       }
5797     }
5798   }
5799   newprot = FixProteinString (sfp, strand, FALSE, &truncated,
5800                               &contains_start, &contains_stop);
5801   if (table_is_local) {
5802     TransTableFree (tbl);
5803   }
5804 
5805   return newprot;
5806 }
5807 
5808 
5809 extern CharPtr ExtendProtein3 
5810 (SeqFeatPtr sfp,
5811  Uint2      input_entityID,
5812  Boolean    force_partial)
5813 {
5814   BioseqPtr nucBsp;
5815   Int4      max_stop, min_start, start, stop;
5816   Uint1     strand;
5817   Boolean   contains_start, contains_stop;
5818   Int4      increment = 3000;
5819   CharPtr   newprot;
5820   Boolean   partial5, partial3;
5821   Boolean   truncated;
5822 
5823   if (sfp == NULL) return NULL;
5824 
5825   nucBsp = GetBioseqGivenSeqLoc (sfp->location, input_entityID);
5826   if (nucBsp == NULL) return NULL;
5827 
5828   CheckSeqLocForPartial (sfp->location, &partial5, &partial3);
5829   start = GetOffsetInBioseq (sfp->location, nucBsp, SEQLOC_START);
5830   stop = GetOffsetInBioseq (sfp->location, nucBsp, SEQLOC_STOP);
5831   strand = SeqLocStrand (sfp->location);
5832   max_stop = nucBsp->length - 1;
5833   if (stop > start) {
5834     while (max_stop % 3 != stop % 3) {
5835       max_stop --;
5836     }
5837     min_start = start %3;
5838   } else {
5839     while (max_stop % 3 != start % 3) {
5840       max_stop --;
5841     }
5842     min_start = stop % 3;
5843   } 
5844   
5845   contains_stop = FALSE;
5846   contains_start = FALSE;
5847   newprot = NULL;
5848   /* need to initialize newprot in case we're already at the edge */
5849   if ((strand != Seq_strand_minus && stop == max_stop)
5850       || (strand == Seq_strand_minus && stop == min_start))
5851   {
5852         newprot = FixProteinString (sfp, strand, FALSE, &truncated,
5853                               &contains_start, &contains_stop);
5854   }
5855   while ((! contains_stop || force_partial) &&
5856          (   (strand == Seq_strand_minus && stop > min_start) 
5857           || (strand != Seq_strand_minus && stop < max_stop)))
5858   {
5859     if (newprot != NULL) {
5860       MemFree (newprot);
5861       newprot = NULL;
5862     }
5863     if (strand == Seq_strand_minus) {
5864       stop -= increment;
5865       if (stop < min_start) {
5866         stop = min_start;
5867       }
5868       sfp->location = ExpandSeqLoc (stop, start, strand, nucBsp, sfp->location);
5869     } else {
5870       stop += increment;
5871       if (stop > max_stop) {
5872         stop = max_stop;
5873       }
5874       sfp->location = ExpandSeqLoc (start, stop, strand, nucBsp, sfp->location);
5875     }
5876     newprot = FixProteinString (sfp, strand, TRUE, &truncated,
5877                               &contains_start, &contains_stop);
5878   }
5879 
5880   if (! contains_stop || force_partial) {
5881     start = GetOffsetInBioseq (sfp->location, nucBsp, SEQLOC_START);
5882     stop = GetOffsetInBioseq (sfp->location, nucBsp, SEQLOC_STOP);
5883     if (strand == Seq_strand_minus) {
5884       sfp->location = ExpandSeqLoc (0, start, strand, nucBsp, sfp->location);
5885     } else {
5886       sfp->location = ExpandSeqLoc (start, nucBsp->length - 1, strand, nucBsp, sfp->location);
5887     }
5888     partial3 = TRUE;
5889     SetSeqLocPartial (sfp->location, partial5, TRUE);
5890   }
5891   return newprot;
5892 }
5893 
5894 static Boolean MergeOverlapsForThisFeature (SeqFeatPtr sfp)
5895 {  
5896   if (sfp == NULL) return FALSE;
5897   return ! sfp->excpt;
5898 }
5899 
5900 static Boolean 
5901 AdjustCDSForUpdate
5902 (SeqFeatPtr   sfp,
5903  Uint2        input_entityID,
5904  Uint1        frame,
5905  Int4         transl_except_len,
5906  Boolean      truncate_proteins,
5907  Boolean      extend_proteins5,
5908  Boolean      extend_proteins3,
5909  Boolean PNTR truncated,
5910  Boolean PNTR stop_shifted,
5911  Boolean PNTR extended5,
5912  Boolean PNTR extended3,
5913  BioseqPtr    protBsp,
5914  BioseqPtr PNTR newbsp)
5915 {
5916   ByteStorePtr  bs;
5917   CharPtr       newprot, ptr;
5918   SeqEntryPtr   nwsep;
5919   BioseqPtr     newBsp;
5920   Boolean       contains_start, contains_stop;
5921   Uint1         strand;
5922   SeqLocPtr     newloc;
5923   BioseqPtr     nucBsp;
5924   Boolean       partial5, partial3;
5925   CharPtr       seqnew = NULL, seqold = NULL;
5926   Boolean       rval = FALSE;
5927  
5928   if (sfp == NULL
5929     || sfp->idx.subtype != FEATDEF_CDS
5930     || sfp->product == NULL
5931     || protBsp == NULL
5932     || truncated == NULL || stop_shifted == NULL
5933     || extended5 == NULL || extended3 == NULL
5934     || newbsp == NULL)
5935   {
5936     return FALSE;
5937   }
5938   
5939   CheckSeqLocForPartial (sfp->location, &partial3, &partial5);
5940   
5941   nucBsp = GetBioseqGivenSeqLoc (sfp->location, input_entityID);
5942   if (nucBsp == NULL) return FALSE;
5943   
5944   newloc = SeqLocMergeExEx (nucBsp, sfp->location, NULL, FALSE, FALSE,
5945                             MergeOverlapsForThisFeature (sfp), FALSE, FALSE, FALSE);
5946 
5947   if (newloc == NULL) return FALSE;
5948   sfp->location = newloc;
5949   strand = SeqLocStrand (sfp->location);
5950   sfp->location = ShiftStopForLengthChange (sfp->location, nucBsp, transl_except_len, stop_shifted);
5951   if (sfp->location == NULL) {
5952     return FALSE;
5953   }
5954 
5955   sfp->location = ShiftLocationForFrame (sfp->location, frame, nucBsp);
5956 
5957   newprot = FixProteinString (sfp, strand, truncate_proteins, truncated,
5958                               &contains_start, &contains_stop);
5959 
5960   /* Must do 3' end first, otherwise may truncate at stops introduced by expanding 5' end for partiality */
5961   if ((! contains_stop && extend_proteins3 && transl_except_len == 0)
5962       || ((extend_proteins3 || partial3) && !truncate_proteins)) {
5963     MemFree (newprot);
5964     newprot = ExtendProtein3 (sfp, input_entityID, partial3 && !truncate_proteins);
5965     if (newprot == NULL) return FALSE;
5966     *extended3 = TRUE;
5967   } else {
5968     *extended3 = FALSE;
5969   }
5970   if (! contains_start && (extend_proteins5 || partial5)) {
5971     MemFree (newprot);
5972     newprot = ExtendProtein5 (sfp, input_entityID, partial5);
5973     if (newprot == NULL) return FALSE;
5974     *extended5 = TRUE;
5975   } else {
5976     *extended5 = FALSE;
5977   }
5978 
5979   sfp->partial = CheckSeqLocForPartial (sfp->location, &partial5, &partial3);
5980 
5981   bs = BSNew (1000);
5982   if (bs != NULL)
5983   {
5984     ptr = newprot;
5985     BSWrite (bs, (VoidPtr) ptr, (Int4) StringLen (ptr));
5986   } 
5987   MemFree (newprot);
5988   
5989   newBsp = BioseqNew ();
5990   if (newBsp == NULL) {
5991     return FALSE;
5992   }
5993 
5994   newBsp->id = SeqIdParse ("lcl|ProtAlign");
5995   newBsp->repr = Seq_repr_raw;
5996   newBsp->mol = Seq_mol_aa;
5997   newBsp->seq_data_type = Seq_code_ncbieaa;
5998   newBsp->seq_data = (SeqDataPtr) bs;
5999   newBsp->length = BSLen (bs);
6000 
6001   /* create SeqEntry for temporary protein bioseq to live in */
6002   nwsep = SeqEntryNew ();
6003   nwsep->choice = 1;
6004   nwsep->data.ptrvalue = newBsp;
6005   SeqMgrSeqEntry (SM_BIOSEQ, (Pointer) newBsp, nwsep);
6006 
6007   seqold = GetSequenceByBsp (protBsp);
6008   seqnew = GetSequenceByBsp (newBsp);
6009 
6010   if (StringCmp (seqold, seqnew) == 0
6011     || (contains_stop && ! *truncated
6012       && StringNCmp (seqold,
6013                      seqnew,
6014                      StringLen (seqold)) == 0))
6015   {
6016     SeqEntryFree (nwsep);
6017     rval = FALSE;
6018   }
6019   else
6020   {
6021     *newbsp = newBsp;
6022     rval = TRUE;
6023   }
6024 
6025   return rval;   
6026 }
6027 
6028   
6029 static void WarnNoProteinUpdate (BioseqPtr bsp)
6030 {
6031   Char     acc_str [256];
6032   CharPtr  warn_format = "Protein %s has not been updated - you must manually re-translate the coding regions and move any protein features";
6033   CharPtr  warn_msg;
6034 
6035   if (bsp == NULL || bsp->id == NULL) return;
6036   SeqIdWrite (bsp->id, acc_str, PRINTID_REPORT, sizeof (acc_str));
6037   warn_msg = (CharPtr) MemNew (StringLen (warn_format) + StringLen (acc_str));
6038   if (warn_msg == NULL) return;
6039   sprintf (warn_msg, warn_format, acc_str);
6040   ErrPostEx (SEV_ERROR, 0, 0, warn_msg);
6041   MemFree (warn_msg);
6042 }
6043 
6044 
6045 static void LogFrameChange (FILE *fp, BioseqPtr bsp, Uint1 frame)
6046 {
6047   Char     acc_str [256];
6048 
6049   if (fp == NULL || bsp == NULL || bsp->id == NULL) return;
6050   SeqIdWrite (bsp->id, acc_str, PRINTID_REPORT, sizeof (acc_str));
6051   fprintf (fp, "Changed frame for %s to %d\n", acc_str, frame);
6052 }
6053 
6054 
6055 static void LogProteinTruncate (FILE *fp, BioseqPtr bsp)
6056 {
6057   Char     acc_str [256];
6058 
6059   if (fp == NULL || bsp == NULL || bsp->id == NULL) return;
6060   SeqIdWrite (bsp->id, acc_str, PRINTID_REPORT, sizeof (acc_str));
6061   fprintf (fp, "Truncated protein %s at stop\n", acc_str);
6062 }
6063 
6064 
6065 static void LogProteinStopShift (FILE *fp, BioseqPtr bsp)
6066 {
6067   Char     acc_str [256];
6068 
6069   if (fp == NULL || bsp == NULL || bsp->id == NULL) return;
6070   SeqIdWrite (bsp->id, acc_str, PRINTID_REPORT, sizeof (acc_str));
6071   fprintf (fp, "Adjusted length of CDS for protein %s to be multiple of 3\n", acc_str);
6072 }
6073 
6074 
6075 static void LogProteinExtend5 (FILE *fp, BioseqPtr bsp)
6076 {
6077   Char     acc_str [256];
6078 
6079   if (fp == NULL || bsp == NULL || bsp->id == NULL) return;
6080   SeqIdWrite (bsp->id, acc_str, PRINTID_REPORT, sizeof (acc_str));
6081   fprintf (fp, "Extended protein %s on 5' end\n", acc_str);
6082 }
6083 
6084 
6085 static void LogProteinExtend3 (FILE *fp, BioseqPtr bsp)
6086 {
6087   Char     acc_str [256];
6088 
6089   if (fp == NULL || bsp == NULL || bsp->id == NULL) return;
6090   SeqIdWrite (bsp->id, acc_str, PRINTID_REPORT, sizeof (acc_str));
6091   fprintf (fp, "Extended protein %s on 3' end\n", acc_str);
6092 }
6093 
6094 static void LogGeneCorrection (FILE *fp, SeqFeatPtr gene, SeqLocPtr oldloc)
6095 {
6096   CharPtr           loc1, loc2;
6097   SeqMgrFeatContext gcontext;
6098   SeqFeatPtr        found_gene;
6099 
6100   if (fp == NULL || gene == NULL || gene->location == NULL || oldloc == NULL) return;
6101   found_gene = SeqMgrGetDesiredFeature (gene->idx.entityID, NULL, 0, 0, gene, &gcontext);
6102   if (found_gene == NULL) return;
6103   loc1 = SeqLocPrint (gene->location);
6104   loc2 = SeqLocPrint (oldloc);
6105   if (loc1 != NULL && loc2 != NULL && StringCmp (loc1, loc2) != 0) {
6106     fprintf (fp, "Moved gene %s from %s to %s\n", gcontext.label, loc2, loc1);
6107   }
6108   MemFree (loc1);
6109   MemFree (loc2);
6110 }
6111 
6112 
6113 static void LogGeneBadCorrection (FILE *fp, SeqFeatPtr gene)
6114 {
6115   SeqMgrFeatContext gcontext;
6116   SeqFeatPtr        found_gene;
6117 
6118   if (fp == NULL || gene == NULL || gene->location == NULL) return;
6119   found_gene = SeqMgrGetDesiredFeature (gene->idx.entityID, NULL, 0, 0, gene, &gcontext);
6120   if (found_gene == NULL) return;
6121   fprintf (fp, "Please examine gene %s, new gene may be too large\n", gcontext.label);
6122 }
6123 
6124 
6125 static void CorrectCDSGene
6126 (SeqFeatPtr sfp,
6127  SeqFeatPtr gene_sfp,
6128  FILE *fp,
6129  Boolean PNTR data_in_log)
6130 {
6131   BioseqPtr bsp;
6132   Boolean   partial5, partial3;
6133   SeqLocPtr log_slp, new_slp;
6134   Int2      res;
6135 
6136   if (sfp == NULL || gene_sfp == NULL || fp == NULL 
6137       || data_in_log == NULL){
6138     return;
6139   }
6140   bsp = BioseqFindFromSeqLoc (sfp->location);
6141   if (bsp == NULL) return;
6142   new_slp = SeqLocMerge (bsp, sfp->location, NULL, TRUE, FALSE, FALSE);
6143   res = SeqLocCompare (gene_sfp->location, new_slp);
6144   if (res == SLC_A_EQ_B) {
6145     SeqLocFree (new_slp);
6146     return;
6147   }
6148   if (SeqLocLen (gene_sfp->location) > SeqLocLen (new_slp)) {
6149     SeqLocFree (new_slp);
6150     new_slp = SeqLocMerge (bsp, sfp->location, gene_sfp->location, TRUE, FALSE, FALSE);
6151     LogGeneBadCorrection (fp, gene_sfp);
6152   }
6153   log_slp = SeqLocMerge (bsp, sfp->location, NULL, FALSE, FALSE, FALSE);
6154 
6155   *data_in_log = TRUE;
6156   SeqLocFree (gene_sfp->location);
6157   gene_sfp->location = new_slp;
6158   CheckSeqLocForPartial (sfp->location, &partial5, &partial3);
6159   SetSeqLocPartial (gene_sfp->location, partial5, partial3);
6160   gene_sfp->partial = sfp->partial;
6161   LogGeneCorrection (fp, gene_sfp, log_slp);
6162   SeqLocFree (log_slp);
6163 }
6164 
6165 static void FixProtRefPtrs (ValNodePtr feat_list)
6166 {
6167   ValNodePtr vnp;
6168   SeqFeatPtr sfp;
6169   Uint1      strand;
6170   BioseqPtr  bsp;
6171 
6172   if (feat_list == NULL) return;
6173   for (vnp = feat_list; vnp != NULL; vnp = vnp->next) {
6174     sfp = (SeqFeatPtr)vnp->data.ptrvalue;
6175     if (sfp == NULL) continue;
6176     bsp = BioseqFindFromSeqLoc (sfp->location);
6177     if (bsp == NULL) continue;
6178     strand = SeqLocStrand (sfp->location);
6179     if (strand == Seq_strand_minus) {
6180       sfp->location = ExpandSeqLoc (bsp->length - 1, 0, strand, bsp, sfp->location);
6181     } else {
6182       sfp->location = ExpandSeqLoc (0, bsp->length - 1, strand, bsp, sfp->location);
6183     }
6184   }
6185 }
6186 
6187 
6188 static Boolean PrepareUpdateAlignmentForProtein
6189 (SeqFeatPtr sfp,
6190  BioseqPtr  protBsp,
6191  Uint2      input_entityID,
6192  FILE *     fp,
6193  Boolean    truncate_proteins,
6194  Boolean    extend_proteins5,
6195  Boolean    extend_proteins3,
6196  Boolean    correct_cds_genes,
6197  Int4       transl_except_len,
6198  Boolean    *data_in_log,
6199  SeqAlignPtr PNTR salpptr,
6200  BioseqPtr PNTR newbspptr)
6201 {
6202   Boolean       align_succeeded;
6203   Boolean       changed_frame;
6204   Uint1         frame_attempts;
6205   ErrSev        level;
6206   CdRegionPtr   crp;
6207   SeqLocPtr     orig_slp;
6208   Boolean       orig_partial;
6209   SeqFeatPtr    gene_sfp;
6210   SeqMgrFeatContext gcontext;
6211   Boolean       truncated, stop_shifted;
6212   Boolean       extended5, extended3;
6213   Uint1         old_frame;
6214   BioseqPtr     newBsp = NULL;
6215   Boolean       adjust_succeeded;
6216   SeqAlignPtr   salp = NULL;
6217   Boolean       revcomp;
6218 
6219   if (sfp == NULL || sfp->data.choice != SEQFEAT_CDREGION
6220       || (crp = (CdRegionPtr)sfp->data.value.ptrvalue) == NULL
6221       || protBsp == NULL
6222       || data_in_log == NULL) {
6223     return FALSE;
6224   }
6225 
6226   old_frame = crp->frame;
6227 
6228   orig_slp = sfp->location;
6229   orig_partial = sfp->partial;
6230   if (correct_cds_genes) {
6231     gene_sfp = SeqMgrGetOverlappingGene (sfp->location, &gcontext);
6232   }
6233   align_succeeded = FALSE;
6234   changed_frame = FALSE;
6235 
6236   level = ErrSetMessageLevel (SEV_MAX);
6237   for (frame_attempts = 1;
6238        frame_attempts < 4 && ! align_succeeded;
6239        frame_attempts ++) {
6240     if (sfp->location != orig_slp) {
6241       if (sfp->location->choice == 0) {
6242         SeqLocFree (sfp->location);
6243       }
6244       sfp->location = orig_slp;
6245     }
6246     sfp->partial = orig_partial;    
6247     crp->frame = old_frame;
6248     if (newBsp != NULL) {
6249       newBsp = BioseqFree (newBsp);
6250     }
6251     truncated= FALSE;
6252     stop_shifted = FALSE;
6253     extended5 = FALSE;
6254     extended3 = FALSE;
6255     adjust_succeeded = AdjustCDSForUpdate (sfp,
6256                                            input_entityID,
6257                                            frame_attempts,
6258                                            transl_except_len,
6259                                            truncate_proteins,
6260                                            extend_proteins5,
6261                                            extend_proteins3,
6262                                            &truncated, &stop_shifted,
6263                                            &extended5, &extended3,
6264                                            protBsp, &newBsp);
6265     if (sfp->location == NULL || sfp->location->choice == 0) 
6266     {
6267       sfp->location = orig_slp;
6268     }
6269     if (adjust_succeeded)
6270     {
6271       salp = Sequin_GlobalAlign2Seq (protBsp, newBsp, &revcomp);
6272     }
6273     if (!adjust_succeeded || salp != NULL)
6274     {
6275       if (frame_attempts > 1) {
6276         changed_frame = TRUE;
6277         LogFrameChange (fp, protBsp, frame_attempts);
6278         *data_in_log = TRUE;
6279       }
6280       break;
6281     }    
6282   }
6283   ErrSetMessageLevel (level);
6284   if (adjust_succeeded && salp == NULL) 
6285   {
6286     /* put CD Region back to original state */
6287     crp->frame = old_frame;
6288     if (sfp->location != orig_slp) {
6289       SeqLocFree (sfp->location);
6290       sfp->location = orig_slp;
6291     }
6292     sfp->partial = orig_partial;
6293     WarnNoProteinUpdate (protBsp);
6294     newBsp = BioseqFree (newBsp);
6295     return FALSE;
6296   }
6297 
6298   if (truncated) {
6299     LogProteinTruncate (fp, protBsp);
6300     *data_in_log = TRUE;
6301   }
6302   if (stop_shifted) {
6303     LogProteinStopShift (fp, protBsp);
6304     *data_in_log = TRUE;
6305   }
6306   if (extended5) {
6307     LogProteinExtend5 (fp, protBsp);
6308     *data_in_log = TRUE;
6309   }
6310   if (extended3) {
6311     LogProteinExtend3 (fp, protBsp);
6312     *data_in_log = TRUE;
6313   }
6314   
6315   if (correct_cds_genes && gene_sfp != NULL) {
6316     CorrectCDSGene (sfp, gene_sfp, fp, data_in_log);
6317   }
6318   if (sfp->location != orig_slp) {
6319     SeqLocFree (orig_slp);
6320   }
6321   
6322   *salpptr = salp;
6323   *newbspptr = newBsp;
6324   return TRUE;
6325 }
6326 
6327 
6328 typedef struct proteinfromcdsdata {
6329  Uint2      input_entityID;
6330  Uint4      input_itemID;
6331  Uint4      input_itemtype;
6332  FILE *     fp;
6333  Boolean    data_to_report;
6334 } ProteinFromCDSData, PNTR ProteinFromCDSPtr;
6335 
6336 static void UpdateOneProteinFromCDS (SeqFeatPtr sfp, Pointer userdata)
6337 {
6338   ProteinFromCDSPtr pfcp;
6339   SeqLocPtr         new_product;
6340   Boolean           data_in_log;
6341   Int4              transl_except_len = 0;
6342   BioseqPtr         protBsp;
6343   SeqAlignPtr       salp = NULL;
6344   BioseqPtr         newbsp = NULL;
6345   Boolean           rval;
6346   
6347   pfcp = (ProteinFromCDSPtr) userdata;
6348   if ( pfcp == NULL
6349     || sfp == NULL
6350     || sfp->idx.subtype != FEATDEF_CDS
6351     || sfp->product == NULL)
6352   {
6353     return;
6354   }
6355   
6356   protBsp = BioseqFindFromSeqLoc (sfp->product);
6357   if (protBsp == NULL)
6358   {
6359     return;
6360   }
6361  
6362   data_in_log = FALSE;
6363   
6364   if (CodingRegionHasTranslExcept(sfp))
6365   {
6366         transl_except_len = SeqLocLen (sfp->location) % 3;
6367   }
6368   
6369   rval = PrepareUpdateAlignmentForProtein (sfp,
6370                                            protBsp,
6371                                            pfcp->input_entityID,
6372                                            pfcp->fp,
6373                                            TRUE, TRUE, TRUE, TRUE,
6374                                            transl_except_len,
6375                                            &data_in_log,
6376                                            &salp,
6377                                            &newbsp);
6378   if (data_in_log) {
6379     pfcp->data_to_report = TRUE;
6380   }
6381   if (!rval) return;
6382 
6383   ReplaceOneSequence (salp, protBsp, newbsp);
6384   if (sfp->product->choice != SEQLOC_WHOLE)
6385   {
6386     new_product = SeqLocWholeNew (protBsp);
6387     if (new_product == NULL) return;
6388     SeqLocFree (sfp->product);
6389     sfp->product = new_product;
6390   }
6391 }
6392 
6393 static Boolean CheckForIDCollision (
6394   BioseqPtr oldbsp,
6395   BioseqPtr newbsp,
6396   BoolPtr islocal
6397 )
6398 
6399 {
6400   SeqIdPtr  sip;
6401 
6402   if (oldbsp == NULL || newbsp == NULL) return FALSE;
6403   for (sip = newbsp->id; sip != NULL; sip = sip->next) {
6404     if (SeqIdIn (sip, oldbsp->id)) {
6405       if (sip->choice == SEQID_LOCAL) {
6406         *islocal = TRUE;
6407       }
6408       return TRUE;
6409     }
6410   }
6411   return FALSE;
6412 }
6413 
6414 static CharPtr convPubDescMssg =
6415 "Do you wish to convert publications to apply only to the appropriate ranges?";
6416 
6417 #define UPDATE_SKIP_THIS    1
6418 #define UPDATE_SKIP_ALL     2
6419 #define UPDATE_REPLACE_THIS 3
6420 #define UPDATE_REPLACE_ALL  4
6421 #define UPDATE_CANCEL       5
6422 
6423 typedef struct noalignmentchoice
6424 {
6425   Boolean done;
6426   Boolean cancelled;
6427   GrouP   action_choice;
6428   Boolean skip_this;
6429   Boolean skip_all;
6430   Boolean replace_this;
6431   Boolean replace_all;
6432 } NoAlignmentChoiceData, PNTR NoAlignmentChoicePtr;
6433 
6434 static void NoAlignmentChoiceOk (ButtoN b)
6435 {
6436   NoAlignmentChoicePtr nacp;
6437   
6438   nacp = (NoAlignmentChoicePtr) GetObjectExtra (b);
6439   if (nacp == NULL) return;
6440   nacp->cancelled = FALSE;
6441   nacp->done = TRUE;
6442 }
6443 
6444 static void NoAlignmentChoiceCancel (ButtoN b)
6445 {
6446   NoAlignmentChoicePtr nacp;
6447   
6448   nacp = (NoAlignmentChoicePtr) GetObjectExtra (b);
6449   if (nacp == NULL) return;
6450   nacp->cancelled = TRUE;
6451   nacp->done = TRUE;
6452 }
6453 
6454 static Int2 GetNoAlignmentChoice (SeqIdPtr id, Int2 previous_choice)
6455 {
6456   Char                  buf [64];
6457   WindoW                w;
6458   GrouP                 h, g, c;
6459   ButtoN                b;
6460   NoAlignmentChoiceData nacd;
6461   Char                  promptstr[115];
6462   Int2                  no_aln_choice;
6463   SeqIdPtr              sip, sip_next;
6464 
6465   sip = SeqIdFindBest (id, 0);
6466   if (sip == NULL) return UPDATE_CANCEL;
6467   w = ModalWindow(-20, -13, -10, -10, NULL);
6468   if (w == NULL) return 0;
6469 
6470   h = HiddenGroup (w, -1, 0, NULL);
6471   g = HiddenGroup(h, 0, 4, NULL);
6472   sip_next = sip->next;
6473   sip->next = NULL;
6474   SeqIdWrite (sip, buf, PRINTID_REPORT, sizeof (buf) - 1);
6475   sip->next = sip_next;
6476   sprintf (promptstr, "There is no alignment between the sequences for %s.", buf);
6477   StaticPrompt (g, promptstr, 0, popupMenuHeight, programFont, 'l');
6478   StaticPrompt (g, "You may choose to :", 0, popupMenuHeight, programFont, 'l');
6479   nacd.action_choice = HiddenGroup (g, 0, 4, NULL);
6480   RadioButton (nacd.action_choice, "Skip This Sequence");
6481   RadioButton (nacd.action_choice, "Skip All Sequences without Alignments");
6482   RadioButton (nacd.action_choice, "Replace This Sequence");
6483   RadioButton (nacd.action_choice, "Replace All Sequences without Alignments");
6484   if (previous_choice > 0 && previous_choice < UPDATE_CANCEL)
6485   {
6486     SetValue (nacd.action_choice, previous_choice);
6487   }
6488   else
6489   {
6490     SetValue (nacd.action_choice, 1);
6491   }
6492   c = HiddenGroup (h, 2, 0, NULL);
6493   b = PushButton (c, "Ok", NoAlignmentChoiceOk);
6494   SetObjectExtra (b, &nacd, NULL);
6495   b = PushButton (c, "Cancel", NoAlignmentChoiceCancel);
6496   SetObjectExtra (b, &nacd, NULL);
6497   
6498   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL);
6499 
6500   nacd.cancelled = FALSE;
6501   nacd.done = FALSE;
6502   Show(w); 
6503   Select (w);
6504   while (!nacd.done)
6505   {
6506     ProcessExternalEvent ();
6507     Update ();
6508   }
6509   ProcessAnEvent ();
6510   no_aln_choice = GetValue (nacd.action_choice);
6511   Remove (w);
6512   if (nacd.cancelled)
6513   {
6514     return UPDATE_CANCEL;
6515   }
6516   else
6517   {
6518     return no_aln_choice;
6519   }
6520 }
6521 
6522 static Boolean PrepareUpdatePtr (UpsDataPtr    udp)
6523 {
6524   Uint2        entityID;
6525   SeqEntryPtr  oldsep, newsep;
6526   SeqIdPtr     sip;
6527   Boolean      islocal = FALSE;
6528   Char         buf [64];
6529   SeqAlignPtr  salp = NULL;
6530   Boolean      revcomp = FALSE;
6531   Boolean      asked_about_desc_prop = FALSE;
6532   Boolean      propagate_descriptors = FALSE;
6533   SeqIdPtr     id, id_next;
6534   MsgAnswer    ans;
6535   Char         collision_id [100];
6536 
6537   if (udp->oldbsp == NULL || udp->newbsp == NULL) return FALSE;
6538   if (ISA_na (udp->oldbsp->mol) != ISA_na (udp->newbsp->mol)) {
6539     Message (MSG_OK, "Both sequences must be either nucleotides or proteins");
6540     return FALSE;
6541   }
6542 
6543   entityID = ObjMgrGetEntityIDForPointer (udp->oldbsp);
6544   oldsep = GetBestTopParentForData (entityID, udp->oldbsp);
6545   entityID = ObjMgrGetEntityIDForPointer (udp->newbsp);
6546   newsep = GetBestTopParentForData (entityID, udp->newbsp);
6547   if (oldsep == NULL || newsep == NULL)
6548     return FALSE;
6549 
6550   if (CONVERTPUBS_NOT_SET == udp->convertPubs) 
6551   {
6552     if (Message (MSG_YN, convPubDescMssg) == ANS_YES) {
6553       ConvertPubSrcComDescsToFeats (oldsep, TRUE, FALSE, FALSE, FALSE, &asked_about_desc_prop, &propagate_descriptors, NULL);
6554       ConvertPubSrcComDescsToFeats (newsep, TRUE, FALSE, FALSE, FALSE, &asked_about_desc_prop, &propagate_descriptors, NULL);
6555       udp->convertPubs = CONVERTPUBS_YES;
6556     }
6557     else
6558       udp->convertPubs = CONVERTPUBS_NO;
6559   }
6560 
6561   if (CheckForIDCollision (udp->oldbsp, udp->newbsp, &islocal)) {
6562     sprintf (collision_id, "lcl|SequinUpdateSequence%d", udp->seqsubpos);
6563     sip = SeqIdParse (collision_id);
6564     if (sip != NULL) {
6565       BioseqReplaceID (udp->newbsp, sip);
6566       sip = SeqIdFree (sip);
6567     }
6568   }
6569   
6570   salp = Sequin_GlobalAlign2Seq (udp->oldbsp, udp->newbsp, &revcomp);
6571 
6572   if (salp == NULL) {
6573     if (udp->log_fp != NULL) {
6574       id = SeqIdFindBest (udp->oldbsp->id, 0);
6575       if (id != NULL)
6576       {
6577         id_next = id->next;
6578         id->next = NULL;
6579         SeqIdWrite (id, buf, PRINTID_REPORT, sizeof (buf) - 1);
6580         id->next = id_next;
6581         fprintf (udp->log_fp, "No sequence similarity for %s\n", buf);
6582         udp->data_in_log = TRUE;  
6583       }
6584     }
6585     if (udp->suppress_continue_msg) {
6586       return FALSE;
6587     } else {
6588       if (udp->isSet && udp->do_update)
6589       {
6590         if (udp->no_aln_choice != UPDATE_SKIP_ALL && udp->no_aln_choice != UPDATE_REPLACE_ALL)
6591         {
6592           udp->no_aln_choice = GetNoAlignmentChoice (udp->oldbsp->id, udp->no_aln_choice);
6593         }
6594         if (udp->no_aln_choice == UPDATE_CANCEL)
6595         {
6596           return FALSE;
6597         }
6598       }
6599       else if (udp->do_update)
6600       {
6601         ans = Message (MSG_YN, "There is no alignment between the sequences.  Do you wish to continue?");
6602         if (ans == ANS_YES)
6603         {
6604           udp->useGUI = TRUE;
6605         }
6606         else
6607         {
6608           return FALSE;
6609         }
6610       }
6611     }
6612   }
6613   udp->salp     = salp;
6614   udp->revcomp  = revcomp;
6615   udp->diffOrgs = FALSE;
6616   udp->recomb1  = -1;
6617   udp->recomb2  = -1;
6618   
6619   return TRUE;
6620 }
6621 
6622 static void UpdateProteinsOnNewBsp (SeqFeatPtr sfp, Pointer userdata);
6623 
6624 static void
6625 FindProtRefPtrsOnBsp
6626 (BioseqPtr bsp,
6627  ValNodePtr PNTR feat_list)
6628 {
6629   SeqMgrFeatContext context;
6630   SeqFeatPtr        sfp;
6631   ValNodePtr        vnp;
6632  
6633   if (bsp == NULL || feat_list == NULL) return;
6634   sfp = SeqMgrGetNextFeature (bsp, NULL, SEQFEAT_PROT, 0, &context);
6635   while (sfp != NULL) {
6636     if (context.left == 0 && context.right == bsp->length - 1) {
6637       vnp = ValNodeNew (*feat_list);
6638       if (vnp != NULL) {
6639         vnp->data.ptrvalue = sfp;
6640       }
6641       if (*feat_list == NULL) {
6642         *feat_list = vnp;
6643       }
6644     }
6645     sfp = SeqMgrGetNextFeature (bsp, sfp, SEQFEAT_PROT, 0, &context);
6646   }
6647 }
6648 
6649 static ValNodePtr FindProductProtRefs (BioseqPtr bsp)
6650 {
6651   SeqFeatPtr        sfp;
6652   SeqMgrFeatContext context;
6653   ValNodePtr        feat_list = NULL;
6654 
6655   if (bsp == NULL) return NULL;
6656   sfp = SeqMgrGetNextFeature (bsp, NULL, SEQFEAT_CDREGION, 0, &context);
6657   while (sfp != NULL) {
6658     FindProtRefPtrsOnBsp (BioseqFindFromSeqLoc (sfp->product), &feat_list);
6659     sfp = SeqMgrGetNextFeature (bsp, sfp, SEQFEAT_CDREGION, 0, &context);
6660   }
6661   return feat_list; 
6662 }
6663 
6664 static ValNodePtr FindTranslExceptCDSs (BioseqPtr bsp)
6665 {
6666   SeqFeatPtr        sfp;
6667   SeqMgrFeatContext context;
6668   ValNodePtr        feat_list = NULL;
6669   ValNodePtr        vnp;
6670   Int4              cd_len;
6671 
6672   if (bsp == NULL) return NULL;
6673   sfp = SeqMgrGetNextFeature (bsp, NULL, SEQFEAT_CDREGION, 0, &context);
6674   while (sfp != NULL) {
6675     if (CodingRegionHasTranslExcept (sfp)) 
6676     {
6677       vnp = ValNodeNew(feat_list);
6678       if (feat_list == NULL) 
6679       {
6680         feat_list = vnp;
6681       }
6682       if (vnp != NULL)
6683       {
6684         cd_len = SeqLocLen (sfp->location);
6685         vnp->choice = cd_len % 3;
6686         vnp->data.ptrvalue = sfp;
6687       }
6688     }
6689     sfp = SeqMgrGetNextFeature (bsp, sfp, SEQFEAT_CDREGION, 0, &context);
6690   }
6691   return feat_list; 
6692 }
6693 
6694 static Int4 GetOriginalTranslExceptLen (SeqFeatPtr sfp, ValNodePtr list)
6695 {
6696   ValNodePtr vnp;
6697   
6698   if (sfp == NULL || list == NULL) return 0;
6699   for (vnp = list; vnp != NULL; vnp = vnp->next)
6700   {
6701         if (vnp->data.ptrvalue == sfp) 
6702         {
6703                 return vnp->choice;
6704         }
6705   }
6706   if (CodingRegionHasTranslExcept (sfp)) 
6707   {
6708         return SeqLocLen (sfp->location) % 3;
6709   }
6710   return 0;
6711 }
6712 
6713 static void UpdateOneSequence (
6714   UpsDataPtr   udp,
6715   Int2         sfbval,
6716   Boolean      add_cit_subs,
6717   Boolean      update_proteins
6718 )
6719 {
6720   SeqAnnotPtr  sap = NULL;
6721   Uint2        entityID;
6722   SeqEntryPtr  sep;
6723   Boolean      update = FALSE;
6724   Boolean      feature_update = FALSE;
6725   ValNodePtr   prot_feat_list = NULL;
6726 
6727   if (udp != NULL)
6728   {
6729     if (GetStatus (udp->replace_all))
6730     {
6731           RemoveOldFeats (udp->oldbsp);
6732     }
6733   }
6734 
6735   if (update_proteins && udp != NULL) {
6736     prot_feat_list = FindProductProtRefs (udp->oldbsp);
6737     if (udp->transl_except_list != NULL)
6738     {
6739       ValNodeFree (udp->transl_except_list);
6740       udp->transl_except_list = NULL;
6741     }
6742     udp->transl_except_list = FindTranslExceptCDSs (udp->oldbsp);
6743   }
6744 
6745   if (sfbval == UPDATE_SEQUENCE_ONLY || sfbval == UPDATE_SEQUENCE_AND_FEATURES) {
6746     switch (udp->rmcval) {
6747       case UPDATE_REPLACE :
6748         if (ReplaceSequence (udp)) {
6749           update = TRUE;
6750         }
6751         break;
6752       case UPDATE_EXTEND5 :
6753               if (NULL == udp->salp) {
6754                 if (Merge5PrimeNoOverlap (udp))
6755                   update = TRUE;
6756               }
6757               else 
6758               {
6759                 if (Merge5Prime (udp))
6760                   update = TRUE;
6761         }
6762         break;
6763       case UPDATE_EXTEND3 :
6764               if (NULL == udp->salp) {
6765                 if (Merge3PrimeNoOverlap (udp))
6766                   update = TRUE;
6767               }
6768               else 
6769               {
6770                 if (Merge3Prime (udp))
6771                   update = TRUE;
6772         }
6773         break;
6774       case UPDATE_PATCH :
6775         if (PatchSequence (udp)) {
6776           update = TRUE;
6777         }
6778         break;
6779       default :
6780         break;
6781     }
6782     if ( sfbval == UPDATE_SEQUENCE_AND_FEATURES) {
6783       switch (udp->rmcval) {
6784         case UPDATE_REPLACE :
6785           if (DoFeaturePropWithOffset (udp, 0, &sap, FALSE)) {
6786             update = TRUE;
6787             feature_update = TRUE;
6788           }
6789           break;
6790         case UPDATE_EXTEND5 :
6791           if (DoFeaturePropWithOffset (udp, 0, &sap, FALSE)) {
6792             update = TRUE;
6793             feature_update = TRUE;
6794           }
6795           break;
6796         case UPDATE_EXTEND3 :
6797           if (DoFeaturePropWithOffset (udp, udp->old5 - udp->new5, &sap, FALSE)) {
6798             update = TRUE;
6799             feature_update = TRUE;
6800           }
6801           break;
6802         case UPDATE_PATCH :
6803           if (DoFeaturePropWithOffset (udp, udp->old5 - udp->new5, &sap, TRUE)) {
6804             update = TRUE;
6805             feature_update = TRUE;
6806           }
6807           break;
6808         default :
6809           break;
6810       }
6811     }
6812     if (udp->rmcval == UPDATE_REPLACE && udp->revcomp && update)
6813     {
6814       ReverseComplementBioseqAndFeats (udp->oldbsp, udp->input_entityID);
6815     }
6816 
6817   } else if (sfbval == UPDATE_FEATURES_ONLY) {
6818     switch (udp->rmcval) {
6819       case UPDATE_REPLACE :
6820         if (DoFeaturePropThruAlign (udp, &sap)) {
6821           update = TRUE;
6822           feature_update = TRUE;
6823         }
6824         break;
6825       case UPDATE_EXTEND5 :
6826         if (DoFeaturePropThruAlign (udp, &sap)) {
6827           update = TRUE;
6828           feature_update = TRUE;
6829         }
6830         break;
6831       case UPDATE_EXTEND3 :
6832         if (DoFeaturePropThruAlign (udp, &sap)) {
6833           update = TRUE;
6834           feature_update = TRUE;
6835         }
6836         break;
6837       case UPDATE_PATCH :
6838         if (DoFeaturePropThruAlign (udp, &sap)) {
6839           update = TRUE;
6840           feature_update = TRUE;
6841         }
6842         break;
6843       default :
6844         break;
6845     }
6846   }
6847   if (update) {
6848     entityID = ObjMgrGetEntityIDForPointer (udp->oldbsp);
6849     if (add_cit_subs
6850       && (feature_update || StringCmp (udp->seq1, udp->seq2) != 0))
6851     {
6852       AddCitSubToUpdatedSequence ( udp->oldbsp, entityID, kSubmitterUpdateText);
6853     }
6854     if (update_proteins)
6855     {
6856       SeqMgrClearFeatureIndexes (entityID, udp->oldbsp);
6857       SeqMgrIndexFeatures (entityID, NULL);
6858       sep = GetBestTopParentForData (entityID, udp->oldbsp);
6859       udp->truncate_proteins = GetStatus (udp->truncate_proteins_btn);
6860       udp->extend_proteins5 = GetStatus (udp->extend_proteins5_btn);
6861       udp->extend_proteins3 = GetStatus (udp->extend_proteins3_btn);
6862       udp->correct_cds_genes = GetStatus (udp->correct_cds_genes_btn);
6863       VisitFeaturesInSep (sep, udp, UpdateProteinsOnNewBsp);
6864       FixProtRefPtrs (prot_feat_list);
6865     }
6866     if (! udp->suppress_instant_refresh) {
6867       ObjMgrSetDirtyFlag (entityID, TRUE);
6868       ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
6869     }
6870   }
6871   
6872   if (GetStatus (udp->update_quality_scores_btn) && udp->rmcval == UPDATE_REPLACE 
6873       && (sfbval == UPDATE_SEQUENCE_ONLY || sfbval == UPDATE_SEQUENCE_AND_FEATURES))
6874   {
6875     ReplaceQualityScores (udp->oldbsp, udp->newbsp, udp->log_fp, &(udp->data_in_log));
6876   }
6877   else if (sfbval != UPDATE_FEATURES_ONLY)
6878   {
6879     RemoveQualityScores (udp->oldbsp, udp->log_fp, &(udp->data_in_log));
6880   }
6881   
6882   ValNodeFree (prot_feat_list);
6883   ValNodeFree (udp->transl_except_list);
6884   udp->transl_except_list = NULL;
6885   if (sfbval == UPDATE_FEATURES_ONLY || sfbval == UPDATE_SEQUENCE_AND_FEATURES) {
6886     if (update) {
6887       entityID = ObjMgrGetEntityIDForPointer (udp->oldbsp);
6888       sep = GetTopSeqEntryForEntityID (entityID);
6889       /* need to set scope to make sure we mark the right bioseq for deletion */
6890       SeqEntrySetScope (sep);
6891       /* resolve features unless the policy was to remove all the old ones */
6892       if (!GetStatus (udp->replace_all))
6893       {
6894         ResolveDuplicateFeats (udp, udp->oldbsp, sap);          
6895       }
6896       SeqEntrySetScope (NULL);
6897       DeleteMarkedObjects (entityID, 0, NULL);
6898       SeqMgrClearFeatureIndexes (entityID, NULL);
6899       ObjMgrSetDirtyFlag (entityID, TRUE);
6900       ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
6901     }
6902   }
6903 }
6904 
6905 static void UpdateProteinsOnNewBsp (SeqFeatPtr sfp, Pointer userdata)
6906 {
6907   UpsDataPtr    udp_orig;
6908   SeqLocPtr     new_product;
6909   Boolean       data_in_log;
6910   Int4          transl_except_len = 0;
6911   Boolean       fix_products = TRUE;
6912   BioseqPtr     protBsp = NULL;
6913   SeqAlignPtr   salp = NULL;
6914   BioseqPtr     newbsp = NULL;
6915   Boolean       rval;
6916 
6917   if (sfp == NULL || sfp->idx.subtype != FEATDEF_CDS || userdata == NULL)
6918   {
6919     return;
6920   }
6921   
6922   if (sfp->idx.deleteme)
6923   {
6924     return;
6925   }
6926   
6927   protBsp = BioseqFindFromSeqLoc (sfp->product);
6928   if (protBsp == NULL)
6929   {
6930     return;
6931   }
6932   udp_orig = (UpsDataPtr) userdata;
6933 
6934   data_in_log = FALSE;
6935   transl_except_len = GetOriginalTranslExceptLen (sfp, udp_orig->transl_except_list);
6936   rval = PrepareUpdateAlignmentForProtein (sfp,
6937                                            protBsp,
6938                                            udp_orig->input_entityID,
6939                                            udp_orig->log_fp,
6940                                            udp_orig->truncate_proteins,
6941                                            udp_orig->extend_proteins5,
6942                                            udp_orig->extend_proteins3,
6943                                            udp_orig->correct_cds_genes,
6944                                            transl_except_len,
6945                                            &data_in_log,
6946                                            &salp,
6947                                            &newbsp);
6948   if (data_in_log) {
6949     udp_orig->data_in_log = TRUE;
6950   }
6951   if (!rval) return;
6952   
6953   if (protBsp->idx.deleteme)
6954   {
6955     fix_products = FALSE;
6956   }
6957 
6958   ReplaceOneSequence (salp, protBsp, newbsp);
6959   
6960   if (fix_products)
6961   {
6962     if (sfp->product->choice != SEQLOC_WHOLE) {
6963       new_product = SeqLocWholeNew (protBsp);
6964       if (new_product == NULL) return;
6965       SeqLocFree (sfp->product);
6966       sfp->product = new_product;
6967     }
6968     newbsp = BioseqFree (newbsp);
6969   }
6970 }
6971 
6972 extern void UpdateProteinsFromCDS ( IteM i)
6973 {
6974   BaseFormPtr        bfp;
6975   SeqEntryPtr        sep;
6976   ProteinFromCDSData pfcd;
6977   Char               path [PATH_MAX];
6978 
6979 #ifdef WIN_MAC
6980   bfp = currentFormDataPtr;
6981 #else
6982   bfp = GetObjectExtra (i);
6983 #endif
6984 
6985   if (bfp == NULL)
6986     return;
6987   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
6988   if (sep == NULL) return;
6989 
6990   pfcd.input_entityID = bfp->input_entityID;
6991   pfcd.input_itemID = bfp->input_itemID;
6992   pfcd.input_itemtype = bfp->input_itemtype;
6993   pfcd.data_to_report = FALSE;
6994   TmpNam (path);
6995   pfcd.fp = FileOpen (path, "wb");
6996   if (pfcd.fp == NULL) return;
6997 
6998   WatchCursor ();
6999   VisitFeaturesInSep (sep, (Pointer) &pfcd, UpdateOneProteinFromCDS);
7000   FileClose (pfcd.fp);
7001   if (pfcd.data_to_report) {
7002     LaunchGeneralTextViewer (path, "Update Log");
7003   }
7004   FileRemove (path);
7005   ArrowCursor ();
7006   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
7007   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
7008 }
7009 
7010 /* This section of code is used to warn the user when an alignment update
7011  * will affect the area inside a variation or the area immediately to the
7012  * left or right of a variation.
7013  */
7014 static void VariationAlignmentCallback (SeqFeatPtr sfp, Pointer userdata)
7015 {
7016   CharPtr    buf, cp;
7017   UpsDataPtr udp;
7018   Boolean    change_found = FALSE;
7019   
7020   if (sfp == NULL || userdata == NULL || sfp->idx.subtype != FEATDEF_variation)
7021   {
7022     return;
7023   }
7024   udp = (UpsDataPtr) userdata;
7025   if (udp->salp == NULL)
7026   {
7027     return;
7028   }
7029   
7030   buf = FeatureLocationAlignment (sfp, udp->salp, 1, 2);
7031   if (buf == NULL)
7032   {
7033     return;
7034   }
7035   cp = buf;
7036   /* skip over "Old    :" */
7037   if (StringLen (cp) > 8)
7038   {
7039     cp += 8;
7040   }
7041   while (*cp != 0 && *cp != '\n' && !change_found)
7042   {
7043     if (*cp == '-')
7044     {
7045       change_found = TRUE;
7046     }
7047     cp++;
7048   }
7049   if (*cp == '\n')
7050   {
7051     cp++;
7052   }
7053   /* skip over "New    :" */
7054   if (StringLen (cp) > 8)
7055   {
7056     cp += 8;
7057   }
7058   while (*cp != 0 && *cp != '\n' && !change_found)
7059   {
7060     if (*cp != '.')
7061     {
7062       change_found = TRUE;
7063     }
7064     cp++;
7065   }
7066   if (change_found)
7067   {
7068     ValNodeAddPointer (&udp->affected_variation_features, 0, sfp);
7069   }
7070   buf = MemFree (buf);
7071 }
7072 
7073 static CharPtr PrepareVariationFeatureLogEntry (SeqFeatPtr sfp, SeqAlignPtr salp)
7074 {
7075   CharPtr loc_buf, feat_buf, total_buf;
7076   Int4    buf_len;
7077   
7078   if (sfp == NULL || salp == NULL)
7079   {
7080     return NULL;
7081   }
7082   
7083   loc_buf = SeqLocPrint (sfp->location);
7084   feat_buf = FeatureLocationAlignment (sfp, salp, 1, 2);
7085     
7086   buf_len = StringLen (sfp->comment) + StringLen (loc_buf) + StringLen (feat_buf) + 3;
7087   total_buf = (CharPtr) MemNew (buf_len * sizeof (Char));
7088   if (total_buf != NULL)
7089   {
7090     total_buf [0] = 0;
7091     /* add feature name */
7092     if (!StringHasNoText (sfp->comment))
7093     {
7094       StringCpy (total_buf, sfp->comment);
7095       StringCat (total_buf, "\n");
7096     }
7097     /* add feature location */
7098     if (!StringHasNoText (loc_buf))
7099     {
7100       StringCat (total_buf, loc_buf);
7101       StringCat (total_buf, "\n");
7102     }
7103     /* add alignment picture */
7104     if (!StringHasNoText (feat_buf))
7105     {
7106       StringCat (total_buf, feat_buf);
7107     }
7108     loc_buf = MemFree (loc_buf);
7109     feat_buf = MemFree (feat_buf);
7110   }
7111   return total_buf;
7112 }
7113 
7114 static Int4 
7115 VariationFeatureChangesOk 
7116 (ValNodePtr  variation_feature_list,
7117  SeqAlignPtr salp,
7118  Boolean     allow_skip)
7119 {
7120   WindoW w;
7121   GrouP  h, c;
7122   ButtoN b;
7123   DoC    doc;
7124   ValNodePtr vnp;
7125   SeqFeatPtr sfp;
7126   CharPtr               total_buf;
7127   ModalAcceptCancelData acd;
7128   CharPtr               str_format = "%d variation features are affected by this update.";
7129   
7130   if (variation_feature_list == NULL || salp == NULL)
7131   {
7132     return TRUE;
7133   }
7134   
7135   w = MovableModalWindow (-20, -13, -10, -10, "Affected Variation Sequences", NULL);
7136   h = HiddenGroup(w, -1, 0, NULL);
7137   SetGroupSpacing (h, 10, 10);
7138 
7139   doc = DocumentPanel (h, stdCharWidth * 40, stdLineHeight * 12);
7140   SetDocAutoAdjust (doc, TRUE);
7141   
7142   total_buf = MemNew (StringLen (str_format) + 15);
7143   if (total_buf != NULL)
7144   {
7145     sprintf (total_buf, str_format, ValNodeLen (variation_feature_list));
7146     AppendText (doc, total_buf, NULL, NULL, programFont);
7147     total_buf = MemFree (total_buf);
7148   }
7149   
7150   for (vnp = variation_feature_list; vnp != NULL; vnp = vnp->next)
7151   {
7152     sfp = (SeqFeatPtr) vnp->data.ptrvalue;
7153     total_buf = PrepareVariationFeatureLogEntry (sfp, salp);
7154     if (!StringHasNoText (total_buf))
7155     {
7156       AppendText (doc, total_buf, NULL, NULL, programFont);
7157     }
7158     MemFree (total_buf);
7159   }
7160   UpdateDocument (doc, 0, 0);
7161   
7162   c = HiddenGroup (h, 3, 0, NULL);
7163   b = PushButton (c, "Proceed", ModalAcceptButton);
7164   SetObjectExtra (b, &acd, NULL);
7165   if (allow_skip)
7166   {
7167     b = PushButton (c, "Skip Update", ModalThirdOptionButton);
7168     SetObjectExtra (b, &acd, NULL);
7169   }
7170   
7171   b = PushButton (c, "Cancel Update", ModalCancelButton);
7172   SetObjectExtra (b, &acd, NULL);
7173  
7174   
7175   AlignObjects (ALIGN_CENTER, (HANDLE) doc,
7176                               (HANDLE) c, 
7177                               NULL);
7178 
7179   Show (w);
7180   Select (w);
7181   
7182   acd.cancelled = FALSE;
7183   acd.third_option = FALSE;
7184   acd.accepted = FALSE;
7185   while (!acd.accepted && ! acd.cancelled && !acd.third_option)
7186   {
7187     ProcessExternalEvent ();
7188     Update ();
7189   }
7190   ProcessAnEvent ();
7191   Remove (w);
7192   
7193   if (acd.accepted)
7194   {
7195     return 1;
7196   }
7197   else if (acd.cancelled)
7198   {
7199     return 2;
7200   }
7201   else
7202   {
7203     return 3;
7204   }
7205 }
7206 
7207 static void 
7208 AddVariationFeaturesToLog 
7209 (FILE       *fp, 
7210  BoolPtr    data_in_log,
7211  ValNodePtr variation_feature_list,
7212  SeqAlignPtr salp)
7213 {
7214   ValNodePtr vnp;
7215   CharPtr    total_buf;
7216   SeqFeatPtr sfp;
7217   
7218   if (fp == NULL || variation_feature_list == NULL)
7219   {
7220     return;
7221   }
7222   
7223   for (vnp = variation_feature_list; vnp != NULL; vnp = vnp->next)
7224   {
7225     sfp = (SeqFeatPtr) vnp->data.ptrvalue;
7226     total_buf = PrepareVariationFeatureLogEntry (sfp, salp);
7227     if (!StringHasNoText (total_buf))
7228     {
7229       fprintf (fp, total_buf);
7230       if (data_in_log != NULL)
7231       {
7232         *data_in_log = TRUE;
7233       }
7234     }
7235     MemFree (total_buf);
7236   }
7237   
7238 }
7239 
7240 static void AcceptRMCOrExtend (ButtoN b)
7241 {
7242   UpsDataPtr   udp;
7243   Int2         sfbval;
7244   Boolean      log_is_local;
7245   Boolean      update_proteins = FALSE;
7246   Uint2        entityID;
7247 
7248   udp = (UpsDataPtr) GetObjectExtra (b);
7249   if (udp == NULL) return;
7250   SafeHide (udp->form);
7251 
7252   sfbval = GetValue (udp->sfb);
7253   udp->rmcval = GetValue (udp->rmc);
7254 
7255   if (udp->log_fp == NULL) {
7256     OpenSequenceUpdateLog (udp);
7257     if (udp->log_fp == NULL) return;
7258     log_is_local = TRUE;
7259   } else {
7260     log_is_local = FALSE;
7261   }
7262   WatchCursor ();
7263   Update ();
7264   
7265   if (udp->do_update)
7266   {
7267     udp->affected_variation_features = ValNodeFree (udp->affected_variation_features);
7268     VisitFeaturesOnBsp (udp->oldbsp, udp, VariationAlignmentCallback);
7269     if (1 == VariationFeatureChangesOk (udp->affected_variation_features, udp->salp, FALSE))
7270     {
7271       if (udp->update_proteins != NULL 
7272         && Enabled (udp->update_proteins)
7273         && GetStatus (udp->update_proteins))
7274       {
7275         update_proteins = TRUE;
7276       }
7277       AddVariationFeaturesToLog (udp->log_fp, &(udp->data_in_log), 
7278                                  udp->affected_variation_features, udp->salp);
7279       UpdateOneSequence (udp, sfbval,
7280                          GetStatus (udp->add_cit_subs),
7281                          update_proteins);
7282     }
7283     udp->affected_variation_features = ValNodeFree (udp->affected_variation_features);
7284   }
7285   else
7286   {
7287     if (ExtendOneSequence (udp))
7288     {
7289       entityID = ObjMgrGetEntityIDForPointer (udp->oldbsp);
7290       ObjMgrSetDirtyFlag (entityID, TRUE);
7291       ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
7292     }
7293   }
7294   
7295   Remove (udp->form);
7296   if (log_is_local) {
7297     CloseOutSequenceUpdateLog (udp);
7298   }
7299   ArrowCursor ();
7300   Update();
7301 }
7302 
7303 static void DoAcceptRMCOrExtendSet (UpsDataPtr udp)
7304 {
7305   Int2         sfbval = 0;
7306   Boolean      log_is_local = FALSE;
7307   Boolean      update_proteins = FALSE;
7308   Boolean      do_update = TRUE;
7309   Boolean      old_useGUI;
7310   Char         acc_str [256];
7311   SeqIdPtr     sip, sip_next;
7312   Int2         prior_rmcval;
7313   Int4         variation_action = 1;
7314 
7315   if (udp == NULL) return;
7316   
7317   SafeHide (udp->form);
7318   old_useGUI = udp->useGUI;
7319   
7320   prior_rmcval = udp->rmcval;
7321   if (udp->do_update)
7322   {
7323     if (udp->salp == NULL 
7324         && (udp->no_aln_choice == UPDATE_REPLACE_THIS
7325          || udp->no_aln_choice == UPDATE_REPLACE_ALL))
7326     {
7327       sfbval = UPDATE_SEQUENCE_ONLY;
7328       udp->rmcval = UPDATE_REPLACE;
7329       udp->useGUI = FALSE;
7330     }
7331     else if (udp->salp == NULL
7332              && (udp->no_aln_choice == UPDATE_SKIP_THIS
7333               || udp->no_aln_choice == UPDATE_SKIP_ALL))
7334     {
7335       do_update = FALSE;
7336     }
7337     else
7338     {
7339       sfbval = GetValue (udp->sfb);
7340       udp->rmcval = GetValue (udp->rmc);
7341       prior_rmcval = udp->rmcval;
7342     }
7343   }
7344   else
7345   {
7346     udp->rmcval = GetValue (udp->rmc);
7347     prior_rmcval = udp->rmcval;
7348   }
7349 
7350   if (udp->log_fp == NULL) 
7351   {
7352     OpenSequenceUpdateLog (udp);
7353     if (udp->log_fp == NULL) return;
7354     log_is_local = TRUE;
7355   }
7356   if (do_update && udp->do_update)
7357   {
7358     udp->affected_variation_features = ValNodeFree (udp->affected_variation_features);
7359     VisitFeaturesOnBsp (udp->oldbsp, udp, VariationAlignmentCallback);
7360     variation_action = VariationFeatureChangesOk (udp->affected_variation_features, udp->salp, TRUE);
7361     if (1 != variation_action)
7362     {
7363       do_update = FALSE;
7364     }
7365     
7366     
7367   }
7368     
7369   if (do_update)
7370   {
7371     if (udp->do_update)
7372     {
7373       if (udp->update_proteins != NULL 
7374           && Enabled (udp->update_proteins)
7375           && GetStatus (udp->update_proteins))
7376       {
7377         update_proteins = TRUE;
7378       }
7379 
7380       AddVariationFeaturesToLog (udp->log_fp, &(udp->data_in_log), 
7381                                  udp->affected_variation_features, udp->salp);
7382       UpdateOneSequence (udp, sfbval, GetStatus (udp->add_cit_subs),
7383                          update_proteins);
7384     }
7385     else
7386     {
7387       ExtendOneSequence (udp);
7388     }
7389 
7390     Remove (udp->form);
7391   }
7392   else
7393   {
7394     sip = SeqIdFindBest (udp->oldbsp->id, 0);
7395     if (sip != NULL)
7396     {
7397       sip_next = sip->next;
7398       SeqIdWrite (sip, acc_str, PRINTID_REPORT, sizeof (acc_str));
7399       fprintf (udp->log_fp, "Skipped update for %s\n", acc_str);
7400             udp->data_in_log = TRUE;
7401       sip->next = sip_next;
7402     }
7403   }
7404   udp->affected_variation_features = ValNodeFree (udp->affected_variation_features);
7405   
7406   if (log_is_local) 
7407   {
7408     CloseOutSequenceUpdateLog (udp);
7409   }
7410   
7411   if (2 == variation_action)
7412   {
7413     FileClose (udp->fp);
7414     CloseOutSequenceUpdateLog (udp);
7415   }
7416   
7417   udp->useGUI = old_useGUI;
7418   udp->rmcval = prior_rmcval;
7419   /* if we are updating a set from a SeqSub, we don't want to free the SeqSub yet */
7420   if (udp->seqsubsep != NULL)
7421   {
7422     udp->newbsp = NULL;
7423   }
7424   FreeUdpFields (udp);
7425 }
7426 
7427 /*------------------------------------------------------------------*/
7428 /*                                                                  */
7429 /* AcceptRMCAll () -- Breaks out of the GUI interface and updates   */
7430 /*                    all remaining sequences in the file without   */
7431 /*                    user intervention.                            */
7432 /*                                                                  */
7433 /*------------------------------------------------------------------*/
7434 
7435 static void AcceptRMCOrExtendAll (ButtoN b)
7436 
7437 {
7438   UpsDataPtr   udp;
7439   Int2         state;
7440   Int4         count;
7441   Char         msgStr[256];
7442 
7443   /* Get current data */
7444 
7445   udp = (UpsDataPtr) GetObjectExtra (b);
7446   if (udp == NULL)
7447     return;
7448 
7449   /* Process the current sequence */
7450 
7451   WatchCursor ();
7452   udp->useGUI = FALSE;
7453 
7454   if (udp->log_fp == NULL) {
7455     OpenSequenceUpdateLog (udp);
7456     if (udp->log_fp == NULL) return;
7457   }
7458   
7459   
7460   udp->rmcval = GetValue (udp->rmc);
7461 
7462   DoAcceptRMCOrExtendSet (udp);
7463 
7464   /* Loop through the file, processing all others */
7465 
7466   state = FASTA_READ_OK;
7467   count = 0;
7468 
7469   while (FASTA_READ_OK == state) {
7470     count++;
7471     WatchCursor ();
7472     state = UpdateNextBioseqInFastaSet (udp);
7473     if (udp->useGUI)
7474       return;
7475   }
7476 
7477   CloseOutSequenceUpdateLog (udp);
7478   ArrowCursor ();
7479 
7480   /* If there was an error, report it, otherwise */
7481   /* print a status message.                     */
7482 
7483   if (FASTA_READ_ERROR == state) {
7484     sprintf (msgStr, "Encountered error while updating.  Only %d sequences "
7485              "were updated.", count);
7486     Message (MSG_OK, msgStr);
7487   }
7488   else {
7489     sprintf (msgStr, "Successfully processed %d sequences from file (not"
7490              " counting any updated before hitting 'Accept All').", count);
7491     Message (MSG_OK, msgStr);
7492   }
7493 }
7494 
7495 
7496 static void AcceptRMCOrExtendSet (ButtoN b)
7497 
7498 {
7499   UpsDataPtr   udp;
7500 
7501   udp = (UpsDataPtr) GetObjectExtra (b);
7502   if (udp == NULL)
7503     return;
7504   
7505   if (udp->log_fp == NULL) {
7506     OpenSequenceUpdateLog (udp);
7507     if (udp->log_fp == NULL) return;
7508   }
7509 
7510   udp->rmcval = GetValue (udp->rmc);
7511   
7512   DoAcceptRMCOrExtendSet (udp);
7513 
7514   UpdateNextBioseqInFastaSet (udp);
7515 }
7516 
7517 static void SetProteinOptionsEnable (UpsDataPtr udp)
7518 {
7519   if (udp == NULL || udp->update_proteins == NULL) return;
7520   
7521   if (Enabled (udp->update_proteins) && GetStatus (udp->update_proteins))
7522   {
7523     Enable (udp->truncate_proteins_btn);
7524     Enable (udp->extend_proteins3_btn);
7525     Enable (udp->extend_proteins5_btn);
7526     Enable (udp->correct_cds_genes_btn);
7527   }
7528   else
7529   {
7530     Disable (udp->truncate_proteins_btn);
7531     Disable (udp->extend_proteins3_btn);
7532     Disable (udp->extend_proteins5_btn);
7533     Disable (udp->correct_cds_genes_btn);
7534   }
7535 }
7536 
7537 static void SetStatusUpdateAcceptBtns (UpsDataPtr udp, Boolean status)
7538 {
7539   if (udp == NULL) return;
7540   
7541   if (status)
7542   {
7543     SafeEnable (udp->accept);
7544     SafeEnable (udp->acceptAll);
7545   }
7546   else
7547   {
7548     SafeDisable (udp->accept);
7549     SafeDisable (udp->acceptAll);
7550   }    
7551 }
7552 
7553 static void UpdateAccept (GrouP g)
7554 
7555 {
7556   Int2        rmcval, sfbval;
7557   UpsDataPtr  udp;
7558   Int2        nobmval = UPDATE_FEAT_DUP_NOT_SET;
7559 
7560   udp = (UpsDataPtr) GetObjectExtra (g);
7561   if (udp == NULL) return;
7562 
7563   rmcval = GetValue (udp->rmc);
7564   sfbval = GetValue (udp->sfb);
7565   
7566   if (rmcval == UPDATE_REPLACE)
7567   {
7568     sfbval = GetValue (udp->sfb);
7569     if (sfbval == UPDATE_SEQUENCE_ONLY || sfbval == UPDATE_SEQUENCE_AND_FEATURES)
7570     {
7571       Enable (udp->update_quality_scores_btn);
7572     }
7573     else
7574     {
7575       Disable (udp->update_quality_scores_btn);
7576     }
7577   }
7578   else
7579   {
7580     Disable (udp->update_quality_scores_btn);
7581   }
7582   
7583   if (sfbval == UPDATE_FEATURES_ONLY || sfbval == UPDATE_SEQUENCE_AND_FEATURES)
7584   {
7585     if (!GetStatus (udp->replace_all))
7586     {
7587       nobmval = GetValue (udp->nobm);
7588     }
7589   }
7590   
7591   /* set enables for protein updates */
7592   if (sfbval == UPDATE_SEQUENCE_ONLY
7593      || (sfbval == UPDATE_SEQUENCE_AND_FEATURES
7594         && (nobmval == UPDATE_FEAT_DUP_USE_OLD || nobmval == UPDATE_FEAT_DUP_USE_BOTH)))
7595   {
7596     SafeEnable (udp->update_proteins);
7597   }
7598   else
7599   {
7600     SafeDisable (udp->update_proteins);
7601   }
7602   SetProteinOptionsEnable (udp);    
7603 
7604   if (rmcval == UPDATE_CHOICE_NOT_SET) {
7605     SetStatusUpdateAcceptBtns (udp, FALSE);
7606     return;
7607   }
7608   if (! udp->do_update) {
7609     SetStatusUpdateAcceptBtns (udp, TRUE);
7610     return;
7611   }
7612     
7613   if (sfbval == UPDATE_CHOICE_NOT_SET || sfbval == UPDATE_SEQUENCE_ONLY || udp->diffOrgs) {
7614     SafeDisable (udp->keepProteinIDs);
7615     if (sfbval == UPDATE_CHOICE_NOT_SET || sfbval == UPDATE_SEQUENCE_ONLY) {
7616       SafeDisable (udp->nobm);
7617       SafeDisable (udp->replace_all);
7618     } else {
7619       SafeEnable (udp->replace_all);
7620       if (GetStatus (udp->replace_all))
7621       {
7622         SafeDisable (udp->nobm);        
7623       }
7624       else
7625       {
7626         SafeEnable (udp->nobm);
7627       }
7628     }
7629   } else if (sfbval == UPDATE_FEATURES_ONLY || sfbval == UPDATE_SEQUENCE_AND_FEATURES) {
7630     SafeEnable (udp->keepProteinIDs);
7631     SafeEnable (udp->replace_all);
7632     if (GetStatus (udp->replace_all))
7633     {
7634       SafeDisable (udp->nobm);          
7635     }
7636     else
7637     {
7638       SafeEnable (udp->nobm);
7639     }
7640   }
7641   if (sfbval == UPDATE_CHOICE_NOT_SET) {
7642     SetStatusUpdateAcceptBtns (udp, FALSE);
7643     return;
7644   }
7645   if (sfbval == UPDATE_FEATURES_ONLY || sfbval == UPDATE_SEQUENCE_AND_FEATURES) {
7646     if (!GetStatus (udp->replace_all) && nobmval == UPDATE_FEAT_DUP_NOT_SET)
7647     {
7648       SetStatusUpdateAcceptBtns (udp, FALSE);
7649       return;
7650     }
7651   }
7652 
7653   SetStatusUpdateAcceptBtns (udp, TRUE);
7654 }
7655 
7656 static void UpdateButtons (GrouP g)
7657 {
7658   UpsDataPtr        udp;
7659   Int2              rmcval;
7660   Uint2             entityID;
7661   SeqFeatPtr        sfp;
7662   SeqMgrFeatContext fcontext;
7663 
7664   udp = (UpsDataPtr) GetObjectExtra (g);
7665   if (udp == NULL) return;
7666 
7667   rmcval = GetValue (udp->rmc);
7668 
7669   if (udp->new5 <= udp->old5 && udp->new3 <= udp->old3) 
7670   {
7671     if (rmcval == UPDATE_PATCH)
7672     {
7673       /* If patch sequence matches, must be feature propagation only */
7674 
7675       if (StringNICmp (udp->seq1 + udp->old5 - udp->new5,
7676                        udp->seq2,
7677                        StringLen (udp->seq2)) == 0) {
7678         SetValue (udp->sfb, UPDATE_FEATURES_ONLY);
7679         Disable (udp->sfb);
7680       }
7681     }
7682     else if (rmcval == UPDATE_REPLACE)
7683     {
7684       /* If no features, must be sequence update only */
7685 
7686       entityID = ObjMgrGetEntityIDForPointer (udp->newbsp);
7687       if (! SeqMgrFeaturesAreIndexed (entityID))
7688         SeqMgrIndexFeatures (entityID, NULL);
7689 
7690       sfp = SeqMgrGetNextFeature (udp->newbsp, NULL, 0, 0, &fcontext);
7691       if (sfp == NULL) 
7692       {
7693         SetValue (udp->sfb, UPDATE_SEQUENCE_ONLY);
7694         Disable (udp->sfb);
7695         Disable (udp->replace_all);
7696         Disable (udp->nobm);
7697       }
7698       else if (!indexerVersion &&
7699                (udp->newbsp->repr != Seq_repr_raw || udp->oldbsp->repr != Seq_repr_raw))
7700       {
7701         SetValue (udp->sfb, UPDATE_FEATURES_ONLY);
7702         Disable (udp->sfb);
7703       }
7704       else
7705       {
7706         Enable (udp->sfb);
7707       }
7708     }
7709   }
7710   UpdateAccept (g);
7711 }
7712 
7713 static void DrawAlignBlock (
7714   SegmenT pict,
7715   Int4 top,
7716   Int4 bottom,
7717   Int4 labelpt,
7718   Int2 labelaln,
7719   Int4 len5,
7720   Int4 lena,
7721   Int4 len3,
7722   Int4 aln_length
7723 )
7724 
7725 {
7726   Char  str [96];
7727 
7728   if (len5 > 0) {
7729     AddRectangle (pict, -len5, top, 0, bottom, NO_ARROW, FALSE, 0);
7730   }
7731   sprintf (str, "%ld", (long) len5);
7732   AddLabel (pict, -len5, (top + bottom) / 2, str, SMALL_TEXT, 5, MIDDLE_LEFT, 0);
7733 
7734   if (len3 > 0) {
7735     AddRectangle (pict, aln_length, top, aln_length + len3, bottom, NO_ARROW, FALSE, 0);
7736   }
7737   sprintf (str, "%ld", (long) len3);
7738   AddLabel (pict, aln_length + len3, (top + bottom) / 2, str, SMALL_TEXT, 5, MIDDLE_RIGHT, 0);
7739 
7740   AddRectangle (pict, 0, top, aln_length, bottom, NO_ARROW, TRUE, 0);
7741   sprintf (str, "%ld", (long) lena);
7742   AddLabel (pict, aln_length / 2, labelpt, str, SMALL_TEXT, 5, labelaln, 0);
7743 }
7744 
7745 static SegmenT MakeAlignPicture (
7746   UpsDataPtr udp,
7747   CharPtr strid1,
7748   CharPtr strid2,
7749   SeqAlignPtr sap
7750 )
7751 
7752 {
7753   SegmenT  pict;
7754   Char     str [96];
7755   Int4     top, bottom;
7756 
7757   pict = CreatePicture ();
7758   if (sap == NULL) return pict;
7759 
7760   top = 0;
7761   bottom = top - 10;
7762 
7763   DrawAlignBlock (pict, top, bottom, bottom, LOWER_CENTER, udp->old5, udp->olda, udp->old3, udp->aln_length);
7764 
7765   /*
7766   AddLabel (pict, (udp->stopmax - udp->startmax) / 2, bottom - 20, strid1, SMALL_TEXT, 5, LOWER_CENTER, 0);
7767   */
7768 
7769 
7770   sprintf (str, "%ld", (long) udp->aln_length);
7771   AddLabel (pict, udp->aln_length / 2, 10, str, SMALL_TEXT, 5, MIDDLE_CENTER, 0);
7772 
7773 
7774   top = 30;
7775   bottom = top - 10;
7776 
7777   DrawAlignBlock (pict, top, bottom, top, UPPER_CENTER, udp->new5, udp->newa, udp->new3, udp->aln_length);
7778 
7779   /*
7780   AddLabel (pict, (udp->stopmax - udp->startmax) / 2, top + 20, strid2, SMALL_TEXT, 5, UPPER_CENTER, 0);
7781   */
7782 
7783   return pict;
7784 }
7785 
7786 static void DrawAlignDiffs (
7787   UpsDataPtr udp,
7788   SegmenT pict,
7789   Int4 top,
7790   Int4 bottom,
7791   SeqAlignPtr sap
7792 )
7793 
7794 {
7795   AlnMsg2Ptr  amp1, amp2;
7796   SegmenT    seg;
7797   Int4       len1, len2, i;
7798   Int4       seg_i, seg_n, seg_start, seg_stop;
7799 
7800   if (udp->seq1 == NULL || udp->seq2 == NULL) return;
7801   len1 = StringLen (udp->seq1);
7802   len2 = StringLen (udp->seq2);
7803 
7804   seg = CreateSegment (pict, 0, 0);
7805   AddAttribute (seg, COLOR_ATT, RED_COLOR, 0, 0, 0, 0);
7806 
7807   seg_n = AlnMgr2GetNumSegs(sap);
7808   for (seg_i = 1; seg_i<=seg_n; seg_i++) {
7809     AlnMgr2GetNthSegmentRange(sap, seg_i, &seg_start, &seg_stop);
7810 
7811     amp1 = AlnMsgNew2 ();
7812     amp2 = AlnMsgNew2 ();
7813     if (amp1 == NULL || amp2 == NULL) return;
7814 
7815     amp1->from_aln = seg_start;
7816     amp1->to_aln = seg_stop;
7817     amp1->row_num = 1;
7818 
7819     amp2->from_aln = seg_start;
7820     amp2->to_aln = seg_stop;
7821     amp2->row_num = 2;
7822 
7823     AlnMgr2GetNextAlnBit (sap, amp1);
7824     AlnMgr2GetNextAlnBit (sap, amp2);
7825 
7826     if (amp1->to_row - amp1->from_row == amp2->to_row - amp2->from_row &&
7827         amp1->type == AM_SEQ && amp2->type == AM_SEQ) {
7828       for (i=0; i<seg_stop-seg_start+1; i++) {
7829         if (udp->seq1[amp1->from_row+i] != udp->seq2[amp2->from_row+i]) {
7830 
7831           /* record for accurate scrolling to text view */
7832           ValNodeAddInt (&(udp->mismatches), 0, i);
7833 
7834           AddLine (seg, seg_start+i, top, seg_start+i, bottom, FALSE, 0);
7835         }
7836       }
7837     }
7838 
7839     AlnMsgFree2 (amp1);
7840     AlnMsgFree2 (amp2);
7841   }
7842 }
7843 
7844 static void DrawAlignBits (
7845   UpsDataPtr udp,
7846   SegmenT pict,
7847   Int4 top,
7848   Int4 bottom,
7849   Int4 row,
7850   Int4 pos1,
7851   Int4 pos2,
7852   SeqAlignPtr sap
7853 )
7854 
7855 {
7856   AlnMsg2Ptr  amp;
7857   Int4       len, start, stop, from, to;
7858   Char       str [96];
7859   Boolean    wasgap;
7860 
7861   amp = AlnMsgNew2 ();
7862   if (amp == NULL) return;
7863 
7864   amp->from_aln = 0;
7865   amp->to_aln = -1;
7866   amp->row_num = row;
7867 
7868   start = 0;
7869   stop = 0;
7870   from = 0;
7871   to = 0;
7872   wasgap = FALSE;
7873 
7874   while (AlnMgr2GetNextAlnBit (sap, amp)) {
7875     len = amp->to_row - amp->from_row + 1;
7876     stop = start + len;
7877     if (amp->type == AM_GAP) {
7878       if (wasgap) {
7879         to = stop;
7880       } else {
7881         AddRectangle (pict, from, top, to, bottom, NO_ARROW, FALSE, 0);
7882         wasgap = TRUE;
7883         from = start;
7884         to = stop;
7885       }
7886     } else {
7887       if (wasgap) {
7888 
7889         /* record for accurate scrolling to text view */
7890         ValNodeAddInt (&(udp->indels), 0, from);
7891 
7892         AddLine (pict, from, (top + bottom) / 2, to, (top + bottom) / 2, FALSE, 0);
7893         wasgap = FALSE;
7894         from = start;
7895         to = stop;
7896       } else {
7897         to = stop;
7898       }
7899     }
7900     start += len;
7901   }
7902 
7903   if (to > from) {
7904     if (wasgap) {
7905 
7906       /* record for accurate scrolling to text view */
7907       ValNodeAddInt (&(udp->indels), 0, from);
7908 
7909       AddLine (pict, from, (top + bottom) / 2, to, (top + bottom) / 2, FALSE, 0);
7910     } else {
7911       AddRectangle (pict, from, top, to, bottom, NO_ARROW, FALSE, 0);
7912     }
7913   }
7914 
7915   AlnMsgFree2 (amp);
7916 
7917   sprintf (str, "%ld", (long) pos1);
7918   AddLabel (pict, 0, (top + bottom) / 2, str, SMALL_TEXT, 5, MIDDLE_LEFT, 0);
7919 
7920   sprintf (str, "%ld", (long) pos2);
7921   AddLabel (pict, to, (top + bottom) / 2, str, SMALL_TEXT, 5, MIDDLE_RIGHT, 0);
7922 }
7923 
7924 static SegmenT MakeAlignDetails (
7925   UpsDataPtr udp,
7926   CharPtr strid1,
7927   CharPtr strid2,
7928   SeqAlignPtr sap
7929 )
7930 
7931 {
7932   Int4     aln_length;
7933   SegmenT  pict;
7934   Int4     top, bottom;
7935 
7936   pict = CreatePicture ();
7937   if (sap == NULL) return pict;
7938 
7939   aln_length = udp->aln_length;
7940 
7941   top = 0;
7942   bottom = top - 10;
7943 
7944   DrawAlignBits (udp, pict, top, bottom, 1, udp->old5 + 1, udp->old5 + udp->olda, sap);
7945 
7946   /*
7947   AddLabel (pict, aln_length / 2, bottom, strid1, SMALL_TEXT, 5, LOWER_CENTER, 0);
7948   */
7949 
7950   top = 30;
7951   bottom = top - 10;
7952 
7953   if (udp->revcomp) {
7954     DrawAlignBits (udp, pict, top, bottom, 2, udp->new3 + udp->newa, udp->new3 + 1, sap);
7955   } else {
7956     DrawAlignBits (udp, pict, top, bottom, 2, udp->new5 + 1, udp->new5 + udp->newa, sap);
7957   }
7958 
7959   /*
7960   AddLabel (pict, aln_length / 2, top, strid2, SMALL_TEXT, 5, UPPER_CENTER, 0);
7961   */
7962 
7963   top = 15;
7964   bottom = top - 10;
7965 
7966   DrawAlignDiffs (udp, pict, top, bottom, sap);
7967 
7968   return pict;
7969 }
7970 
7971 static CharPtr MakeAlignSequence (
7972   UpsDataPtr udp,
7973   SeqAlignPtr sap,
7974   Int4 row,
7975   CharPtr seq
7976 )
7977 
7978 {
7979   CharPtr    aln;
7980   AlnMsg2Ptr  amp;
7981   Int4       aln_length, len, lens, start, stop, from, to, i, j;
7982 
7983   if (udp == NULL || sap == NULL || seq == NULL || udp->aln_length < 1) return NULL;
7984   lens = StringLen (seq);
7985 
7986   aln = (CharPtr) MemNew (sizeof (Char) * (udp->aln_length + 2));
7987   if (aln == NULL) return NULL;
7988   aln_length = udp->aln_length;
7989   MemSet ((Pointer) aln, '-', aln_length);
7990 
7991   amp = AlnMsgNew2 ();
7992   if (amp == NULL) return aln;
7993 
7994   amp->from_aln = 0;
7995   amp->to_aln = -1;
7996   amp->row_num = row;
7997 
7998   start = 0;
7999   stop = 0;
8000   from = 0;
8001   to = 0;
8002 
8003   while (AlnMgr2GetNextAlnBit (sap, amp)) {
8004     len = amp->to_row - amp->from_row + 1;
8005     stop = start + len;
8006 
8007     if (amp->type == AM_SEQ) {
8008       for (i = start, j = amp->from_row; i < stop && j < lens; i++, j++) {
8009         aln [i] = seq [j];
8010       }
8011     }
8012     start += len;
8013   }
8014 
8015   AlnMsgFree2 (amp);
8016 
8017   return aln;
8018 }
8019 
8020 static void PrintTAln (ButtoN b)
8021 
8022 {
8023   AsnIoPtr    aip;
8024   Char        path [PATH_MAX];
8025   UpsDataPtr  udp;
8026 
8027   udp = (UpsDataPtr) GetObjectExtra (b);
8028   if (udp == NULL) return;
8029   TmpNam (path);
8030   aip = AsnIoOpen (path, "w");
8031   if (aip != NULL) {
8032     SeqAlignAsnWrite (udp->salp, aip, NULL);
8033     AsnIoClose (aip);
8034     LaunchGeneralTextViewer (path, "Update Sequence Alignment");
8035   }
8036   FileRemove (path);
8037 }
8038 
8039 static void PrintGAln (ButtoN b)
8040 
8041 {
8042   UpsDataPtr  udp;
8043 
8044   udp = (UpsDataPtr) GetObjectExtra (b);
8045   if (udp == NULL) return;
8046   PrintViewer (udp->overview);
8047   PrintViewer (udp->details);
8048 }
8049 
8050 static void CalculateOverhangs (
8051   UpsDataPtr udp
8052 )
8053 
8054 {
8055   Int4         aln_length;
8056   Uint2        entityID;
8057   SeqAlignPtr  sap;
8058   SeqEntryPtr  sep;
8059   Int4         stopold, startold, lenold, stopnew, startnew, lennew;
8060 
8061   if (udp == NULL) return;
8062   sap = udp->salp;
8063   if (sap == NULL) return;
8064   aln_length = AlnMgr2GetAlnLength (sap, FALSE);
8065   AlnMgr2GetNthSeqRangeInSA (sap, 1, &startold, &stopold);
8066   AlnMgr2GetNthSeqRangeInSA (sap, 2, &startnew, &stopnew);
8067   lenold = udp->oldbsp->length;
8068   lennew = udp->newbsp->length;
8069 
8070   udp->old5 = startold;
8071   udp->old3 = lenold - stopold - 1;
8072   udp->olda = stopold - startold + 1;
8073 
8074   udp->new5 = startnew;
8075   udp->new3 = lennew - stopnew - 1;
8076   udp->newa = stopnew - startnew + 1;
8077 
8078   udp->aln_length = aln_length;
8079   udp->startmax = MAX (startold, startnew);
8080   udp->stopmax = MAX (aln_length + lenold - stopold, aln_length + lennew - stopnew);
8081 
8082   udp->strandold = AlnMgr2GetNthStrand (sap, 1);
8083   udp->strandnew = AlnMgr2GetNthStrand (sap, 2);
8084 
8085   entityID = ObjMgrGetEntityIDForPointer (udp->oldbsp);
8086   sep = GetTopSeqEntryForEntityID (entityID);
8087   SeqEntrySetScope (sep);
8088   udp->seq1 = GetSequenceByBsp (udp->oldbsp);
8089   SeqEntrySetScope (NULL);
8090 
8091   entityID = ObjMgrGetEntityIDForPointer (udp->oldbsp);
8092   sep = GetTopSeqEntryForEntityID (entityID);
8093   SeqEntrySetScope (sep);
8094   udp->seq2 = GetSequenceByBsp (udp->newbsp);
8095   SeqEntrySetScope (NULL);
8096 
8097   udp->aln1 = MakeAlignSequence (udp, sap, 1, udp->seq1);
8098   udp->aln2 = MakeAlignSequence (udp, sap, 2, udp->seq2);
8099 
8100   udp->log10_aln_length = 1;
8101   while (aln_length >= 10) {
8102     aln_length /= 10;
8103     (udp->log10_aln_length)++;
8104   }
8105 }
8106 
8107 static Int4 CalculateBestScale (
8108   UpsDataPtr udp,
8109   VieweR vwr,
8110   SegmenT pict
8111 )
8112 
8113 {
8114   BoxInfo  box;
8115   Int2     i;
8116   Int4     max, worldwid, portwid;
8117   RecT     r;
8118   Int4     scaleX, oldscaleX;
8119   Int4     wid;
8120 
8121   ObjectRect (vwr, &r);
8122   InsetRect (&r, 4, 4);
8123   wid = (Int4) (r.right - r.left + 1);
8124 
8125   SegmentBox (pict, &box);
8126   oldscaleX = (box.right - box.left + wid - 1) / wid;
8127   RecalculateSegment (pict, oldscaleX, 1);
8128   SegmentBox (pict, &box);
8129   portwid = wid * oldscaleX;
8130   worldwid = box.right - box.left + 20 * oldscaleX + 1;
8131   max = MAX (worldwid, portwid);
8132   scaleX = (max + wid - 1) / wid;
8133   i = 0;
8134   while (i < 10 && (scaleX > oldscaleX || portwid < worldwid)) {
8135     oldscaleX = scaleX;
8136     RecalculateSegment (pict, oldscaleX, 1);
8137     SegmentBox (pict, &box);
8138     portwid = wid * oldscaleX;
8139     worldwid = box.right - box.left + 20 * oldscaleX + 1;
8140     max = MAX (worldwid, portwid);
8141     scaleX = (max + wid - 1) / wid;
8142     i++;
8143   }
8144 
8145   return scaleX;
8146 }
8147 
8148 static Uint1 leftTriFillSym [] = {
8149   0x0C, 0x3C, 0xFC, 0x3C, 0x0C, 0x00, 0x00, 0x00
8150 };
8151 static Uint1 rightTriFillSym [] = {
8152   0xC0, 0xF0, 0xFC, 0xF0, 0xC0, 0x00, 0x00, 0x00
8153 };
8154 
8155 static void LetDraw (
8156   PaneL pnl
8157 )
8158 
8159 {
8160   Char        ch1, ch2;
8161   Int2        i, k, q, left, top, bottom, arrowwidth;
8162   size_t      len;
8163   Int4        offset, j, pos, realpos;
8164   RecT        r, x;
8165   BaR         sb;
8166   Char        str [32];
8167   UpsDataPtr  udp;
8168 
8169   udp = (UpsDataPtr) GetObjectExtra (pnl);
8170   if (udp == NULL) return;
8171 
8172   ObjectRect (pnl, &r);
8173   InsetRect (&r, 4, 4);
8174 
8175   sb = GetSlateHScrollBar ((SlatE) pnl);
8176   offset = GetBarValue (sb);
8177 
8178   SelectFont (SetSmallFont ());
8179 
8180   /* draw top (new) letters */
8181 
8182   if (udp->aln2 != NULL)
8183   {
8184     MoveTo (r.left, r.top + 8 + 3 * udp->lineheight);
8185     for (i = 0, j = offset; i < udp->maxchars && j < udp->aln_length; i++, j++) {
8186       PaintChar (udp->aln2 [j]);
8187     }
8188   }
8189 
8190   /* draw bottom (old) letters */
8191 
8192   if (udp->aln1 != NULL) 
8193   {
8194     MoveTo (r.left, r.top + 8 + 5 * udp->lineheight);
8195     for (i = 0, j = offset; i < udp->maxchars && j < udp->aln_length; i++, j++) {
8196       PaintChar (udp->aln1 [j]);
8197     }
8198   }
8199 
8200   /* draw recombination arrows */
8201 
8202   arrowwidth = MIN (6, udp->charwidth);
8203   if (udp->recomb1 >= offset && udp->recomb1 <= offset + udp->maxchars) {
8204     left = r.left + udp->charwidth * (udp->recomb1 - offset);
8205     LoadRect (&x, left, r.top, left + arrowwidth, r.top + 6);
8206     CopyBits (&x, leftTriFillSym);
8207   }
8208 
8209   if (udp->recomb2 >= offset && udp->recomb2 <= offset + udp->maxchars) {
8210     left = r.left + udp->charwidth * (udp->recomb2 - offset - 1);
8211     LoadRect (&x, left, r.top, left + arrowwidth, r.top + 6);
8212     CopyBits (&x, rightTriFillSym);
8213   }
8214 
8215   if (udp->aln1 == NULL || udp->aln2 == NULL) 
8216   {
8217         return;
8218   }
8219   /* draw red mismatch lines */
8220 
8221   Red ();
8222   top = r.top + 8 + 4 * udp->lineheight - Ascent ();
8223   bottom = top + udp->lineheight - 2;
8224 
8225   for (i = 0, j = offset; i < udp->maxchars && j < udp->aln_length; i++, j++) {
8226     ch1 = udp->aln1 [j];
8227     ch2 = udp->aln2 [j];
8228     if (ch1 == ch2) {
8229     } else if (ch1 == '-' || ch2 == '-') {
8230     } else {
8231       left = r.left + i * udp->charwidth + udp->charwidth / 2 - 1;
8232       MoveTo (left, top);
8233       LineTo (left, bottom);
8234     }
8235   }
8236   Black ();
8237 
8238   /* draw top (new) tick marks and coordinates */
8239 
8240   bottom = r.top + 8 + 3 * udp->lineheight - Ascent () - 2;
8241   top = bottom - 5;
8242   i = 0;
8243   j = offset;
8244   pos = AlnMgr2MapSeqAlignToBioseq (udp->salp, j, 2);
8245   while (pos < 1 && i < udp->maxchars && j < udp->aln_length) {
8246     i++;
8247     j++;
8248     pos = AlnMgr2MapSeqAlignToBioseq (udp->salp, j, 2);
8249   }
8250   for (; i < udp->maxchars + udp->log10_aln_length && j < udp->aln_length; i++, j++) {
8251     ch1 = udp->aln2 [j];
8252     if (ch1 != '-') {
8253       if (udp->revcomp) {
8254         realpos = (udp->newbsp->length - pos - 1);
8255       } else {
8256         realpos = pos;
8257       }
8258       if (((realpos + 1) % 10) == 0) {
8259         left = r.left + i * udp->charwidth + udp->charwidth / 2 - 1;
8260         if (i < udp->maxchars) {
8261           MoveTo (left, top);
8262           LineTo (left, bottom);
8263         }
8264         sprintf (str, "%ld", (long) (realpos + 1));
8265         len = StringLen (str);
8266         if (len <= j + 1) {
8267           k = i - len + 1;
8268           q = 0;
8269           if (k < 0) {
8270             q -= k;
8271             k = 0;
8272           }
8273           if (q < len) {
8274             left = r.left + k * udp->charwidth;
8275             MoveTo (left, r.top + 8 + udp->lineheight);
8276             while (k < udp->maxchars && q < len) {
8277               PaintChar (str [q]);
8278               k++;
8279               q++;
8280             }
8281           }
8282         }
8283       } else if (((realpos + 1) % 5) == 0) {
8284         left = r.left + i * udp->charwidth + udp->charwidth / 2 - 1;
8285         if (i < udp->maxchars) {
8286           MoveTo (left, top + 3);
8287           LineTo (left, bottom);
8288         }
8289       }
8290       pos++;
8291     }
8292   }
8293 
8294   /* draw bottom (old) tick marks and coordinates */
8295 
8296   top = r.top + 8 + 6 * udp->lineheight - Ascent () + 2;
8297   bottom = top + 5;
8298   i = 0;
8299   j = offset;
8300   pos = AlnMgr2MapSeqAlignToBioseq (udp->salp, j, 1);
8301   while (pos < 1 && i < udp->maxchars && j < udp->aln_length) {
8302     i++;
8303     j++;
8304     pos = AlnMgr2MapSeqAlignToBioseq (udp->salp, j, 1);
8305   }
8306   for (; i < udp->maxchars + udp->log10_aln_length && j < udp->aln_length; i++, j++) {
8307     ch1 = udp->aln1 [j];
8308     if (ch1 != '-') {
8309       if (((pos + 1) % 10) == 0) {
8310         left = r.left + i * udp->charwidth + udp->charwidth / 2 - 1;
8311         if (i < udp->maxchars) {
8312           MoveTo (left, top);
8313           LineTo (left, bottom);
8314         }
8315         sprintf (str, "%ld", (long) (pos + 1));
8316         len = StringLen (str);
8317         if (len <= j + 1) {
8318           k = i - len + 1;
8319           q = 0;
8320           if (k < 0) {
8321             q -= k;
8322             k = 0;
8323           }
8324           if (q < len) {
8325             left = r.left + k * udp->charwidth;
8326             MoveTo (left, r.top + 8 + 7 * udp->lineheight);
8327             while (k < udp->maxchars && q < len) {
8328               PaintChar (str [q]);
8329               k++;
8330               q++;
8331             }
8332           }
8333         }
8334       } else if (((pos + 1) % 5) == 0) {
8335         left = r.left + i * udp->charwidth + udp->charwidth / 2 - 1;
8336         if (i < udp->maxchars) {
8337           MoveTo (left, top);
8338           LineTo (left, bottom - 3);
8339         }
8340       }
8341       pos++;
8342     }
8343   }
8344   SelectFont (systemFont);
8345 }
8346 
8347 static void LetScrl (
8348   BaR sb,
8349   SlatE slt,
8350   Int4 newval,
8351   Int4 oldval
8352 )
8353 
8354 {
8355   RecT        r;
8356   UpsDataPtr  udp;
8357 
8358   udp = (UpsDataPtr) GetObjectExtra (slt);
8359   if (udp == NULL) return;
8360 
8361   ObjectRect (udp->letters, &r);
8362   InsetRect (&r, 4, 4);
8363   Select (udp->letters);
8364   if (ABS (oldval - newval) < udp->maxchars) {
8365     ScrollRect (&r, (oldval - newval) * udp->charwidth, 0);
8366   } else {
8367     InsetRect (&r, -2, -2);
8368     InvalRect (&r);
8369   }
8370   Update ();
8371 }
8372 
8373 static void DtlClck (
8374   VieweR vwr,
8375   SegmenT pict,
8376   PoinT pt
8377 )
8378 
8379 {
8380   Int4        goHere;
8381   Int4        offset;
8382   Int4        maxover2;
8383   PntInfo     pnt;
8384   BaR         sb;
8385   UpsDataPtr  udp;
8386   ValNodePtr  vnp;
8387 
8388   udp = (UpsDataPtr) GetViewerData (vwr);
8389   if (udp == NULL) return;
8390 
8391   sb = GetSlateHScrollBar ((SlatE) udp->letters);
8392 
8393   MapViewerToWorld (vwr, pt, &pnt);
8394   maxover2 = udp->maxchars / 2;
8395   if (pnt.x <= 0) {
8396     pnt.x = 0;
8397   } else if (pnt.x >= udp->aln_length) {
8398     pnt.x = udp->aln_length  - udp->maxchars;
8399   } else if (pnt.x >= maxover2) {
8400 
8401     offset = GetBarValue (sb);
8402 
8403     /* look for clicks within 5 pixels of an indel start or a mismatch */
8404 
8405     goHere = -1;
8406     for (vnp = udp->indels; vnp != NULL && goHere < 0; vnp = vnp->next) {
8407       if (ABS (pnt.x - vnp->data.intvalue) < udp->scaleX * 5) {
8408         goHere = vnp->data.intvalue;
8409       }
8410     }
8411     for (vnp = udp->mismatches; vnp != NULL && goHere < 0; vnp = vnp->next) {
8412       if (ABS (pnt.x - vnp->data.intvalue) < udp->scaleX * 5) {
8413         goHere = vnp->data.intvalue;
8414       }
8415     }
8416 
8417     if (goHere >= 0) {
8418       pnt.x = goHere;
8419     } else {
8420       /* if already visible, no need to scroll */
8421       if (pnt.x - maxover2 > offset && pnt.x - maxover2 < offset + maxover2 - 5) return;
8422       if (pnt.x - maxover2 < offset && pnt.x - maxover2 > offset - maxover2 + 5) return;
8423     }
8424 
8425     /* go left 1/2 screen so desired point is in the middle */
8426 
8427     pnt.x -= maxover2;
8428   }
8429 
8430   ResetClip ();
8431   SetBarValue (sb, pnt.x);
8432   Update ();
8433 }
8434 
8435 static void FrameVwr (
8436   VieweR vwr,
8437   SegmenT pict
8438 )
8439 
8440 {
8441   RecT  r;
8442 
8443   ResetClip ();
8444   ObjectRect (vwr, &r);
8445   FrameRect (&r);
8446 }
8447 
8448 static int LIBCALLBACK SortVnpByInt (VoidPtr ptr1, VoidPtr ptr2)
8449 
8450 {
8451   ValNodePtr  vnp1;
8452   ValNodePtr  vnp2;
8453 
8454   if (ptr1 == NULL || ptr2 == NULL) return 0;
8455   vnp1 = *((ValNodePtr PNTR) ptr1);
8456   vnp2 = *((ValNodePtr PNTR) ptr2);
8457   if (vnp1 == NULL || vnp2 == NULL) return 0;
8458 
8459   if (vnp1->data.intvalue > vnp2->data.intvalue) {
8460     return 1;
8461   } else if (vnp1->data.intvalue < vnp2->data.intvalue) {
8462     return -1;
8463   }
8464 
8465   return 0;
8466 }
8467 
8468 
8469 static void UpdateSequenceFormMessage (ForM f, Int2 mssg)
8470 
8471 {
8472   BaseFormPtr        bfp;
8473   StdEditorProcsPtr  sepp;
8474 
8475   bfp = (BaseFormPtr) GetObjectExtra (f);
8476   if (bfp == NULL) return;
8477   switch (mssg) {
8478     case VIB_MSG_CLOSE :
8479       Remove (f);
8480       break;
8481     case VIB_MSG_QUIT :
8482       QuitProc ();
8483       break;
8484     default :
8485       sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
8486       if (sepp != NULL && sepp->handleMessages != NULL) {
8487         sepp->handleMessages (f, mssg);
8488       }
8489       break;
8490   }
8491 }
8492 
8493 static void FreeUdpFields (UpsDataPtr udp)
8494 {
8495   Uint2       entityID;
8496 
8497   udp->ovpict     = DeletePicture (udp->ovpict);
8498   udp->dtpict     = DeletePicture (udp->dtpict);
8499   udp->salp       = SeqAlignFree (udp->salp);
8500   entityID        = ObjMgrGetEntityIDForPointer (udp->newbsp);
8501   udp->newbsp     = ObjMgrFreeByEntityID (entityID);
8502   udp->seq1       = MemFree (udp->seq1);
8503   udp->seq2       = MemFree (udp->seq2);
8504   udp->aln1       = MemFree (udp->aln1);
8505   udp->aln1       = NULL;
8506   udp->aln2       = MemFree (udp->aln2);
8507   udp->aln2       = NULL;
8508   udp->indels     = ValNodeFree (udp->indels);
8509   udp->mismatches = ValNodeFree (udp->mismatches);
8510   udp->transl_except_list = ValNodeFree (udp->transl_except_list);
8511   udp->affected_variation_features = ValNodeFree (udp->affected_variation_features);
8512 }
8513 
8514 static void CleanupUpdateSequenceForm (GraphiC g, VoidPtr data)
8515 
8516 {
8517   UpsDataPtr  udp;
8518 
8519   udp = (UpsDataPtr) data;
8520   if (udp != NULL)
8521     FreeUdpFields (udp);
8522   StdCleanupFormProc (g, data);
8523 }
8524 
8525 static CharPtr txt1 =
8526   "Sequence Relationship displays sequence lengths";
8527 
8528 static CharPtr txt2 =
8529   "Alignment Details displays sequence positions";
8530 
8531 static CharPtr txt3 =
8532   "Click above to scroll Alignment Text position";
8533 
8534 /*------------------------------------------------------------------*/
8535 /*                                                                  */
8536 /* DetermineButtonState () -- Enable/disable buttons based on the   */
8537 /*                            nature of the alignment.              */
8538 /*                                                                  */
8539 /*------------------------------------------------------------------*/
8540 
8541 static void DetermineButtonState (UpsDataPtr   udp,
8542                                   ButtoN PNTR  replaceButtonPtr,
8543                                   ButtoN PNTR  extend5ButtonPtr,
8544                                   ButtoN PNTR  extend3ButtonPtr,
8545                                   ButtoN PNTR  patchButtonPtr)
8546 {
8547   BioSourcePtr       biop1;
8548   BioSourcePtr       biop2;
8549   SeqMgrDescContext  dcontext;
8550   Uint2              entityID;
8551   SeqMgrFeatContext  fcontext;
8552   OrgRefPtr          orp1;
8553   OrgRefPtr          orp2;
8554   SeqDescrPtr        sdp;
8555   SeqFeatPtr         sfp;
8556 
8557   /* If no alignment then disable the patch button */
8558 
8559   if (udp->salp == NULL) {
8560     if (udp->do_update && patchButtonPtr != NULL && *patchButtonPtr != NULL) {
8561       Disable (*patchButtonPtr);
8562     }
8563     if (!udp->do_update)
8564     {
8565       Disable (*replaceButtonPtr);
8566     }
8567   }
8568 
8569   /* Extend 5' */
8570 
8571   else if (udp->new5 > udp->old5 && udp->new3 < udp->old3) {
8572     SetValue (udp->rmc, UPDATE_EXTEND5);
8573     Disable (*extend3ButtonPtr);
8574     udp->recomb2 = udp->aln_length;
8575     if (! udp->do_update) {
8576       Disable (*replaceButtonPtr);
8577     }
8578   }
8579 
8580   /* Extend 3' */
8581 
8582   else if (udp->new5 < udp->old5 && udp->new3 > udp->old3) {
8583     SetValue (udp->rmc, UPDATE_EXTEND3);
8584     Disable (*extend5ButtonPtr);
8585     udp->recomb1 = 0;
8586     if (! udp->do_update) {
8587       Disable (*replaceButtonPtr);
8588     }
8589   }
8590 
8591   /* Replace */
8592 
8593   else {
8594     SetValue (udp->rmc, UPDATE_REPLACE);
8595     Disable (*extend5ButtonPtr);
8596     Disable (*extend3ButtonPtr);
8597     udp->recomb1 = 0;
8598     udp->recomb2 = udp->aln_length;
8599   }
8600   
8601   switch (udp->rmcval)
8602   {
8603     case UPDATE_REPLACE:
8604       if (Enabled (*replaceButtonPtr))
8605       {
8606         SetValue (udp->rmc, UPDATE_REPLACE);
8607       }
8608       break;
8609     case UPDATE_EXTEND5:
8610       if (Enabled (*extend5ButtonPtr))
8611       {
8612         SetValue (udp->rmc, UPDATE_EXTEND5);
8613       }
8614       break;
8615     case UPDATE_EXTEND3:
8616       if (Enabled (*extend3ButtonPtr))
8617       {
8618         SetValue (udp->rmc, UPDATE_EXTEND3);
8619       }
8620       break;
8621     case UPDATE_PATCH:
8622       if (Enabled (*patchButtonPtr))
8623       {
8624         SetValue (udp->rmc, UPDATE_PATCH);
8625       }
8626       break;
8627   }
8628 
8629   /* If no features, must be sequence update only */
8630 
8631   entityID = ObjMgrGetEntityIDForPointer (udp->newbsp);
8632   if (! SeqMgrFeaturesAreIndexed (entityID))
8633     SeqMgrIndexFeatures (entityID, NULL);
8634 
8635   sfp = SeqMgrGetNextFeature (udp->newbsp, NULL, 0, 0, &fcontext);
8636   if (sfp == NULL) {
8637     SetValue (udp->sfb, UPDATE_SEQUENCE_ONLY);
8638     Disable (udp->sfb);
8639     Disable (udp->replace_all);
8640     Disable (udp->nobm);
8641   }
8642 
8643   /* If different organisms, must be feature propagation only */
8644 
8645   orp1 = NULL;
8646   orp2 = NULL;
8647   sdp = SeqMgrGetNextDescriptor (udp->oldbsp, NULL, Seq_descr_source, &dcontext);
8648   if (sdp != NULL) {
8649     biop1 = (BioSourcePtr) sdp->data.ptrvalue;
8650     if (biop1 != NULL) {
8651       orp1 = biop1->org;
8652     }
8653   }
8654   sdp = SeqMgrGetNextDescriptor (udp->newbsp, NULL, Seq_descr_source, &dcontext);
8655   if (sdp != NULL) {
8656     biop2 = (BioSourcePtr) sdp->data.ptrvalue;
8657     if (biop2 != NULL) {
8658       orp2 = biop2->org;
8659     }
8660   }
8661   if (orp1 != NULL && orp2 != NULL) {
8662     if (StringICmp (orp1->taxname, orp2->taxname) != 0) {
8663       if (sfp != NULL) {
8664         SetValue (udp->sfb, UPDATE_FEATURES_ONLY);
8665         Disable (udp->sfb);
8666         udp->diffOrgs = TRUE;
8667         if (FALSE == udp->isSet)
8668           Message (MSG_OK, "Organisms are different, so features will"
8669                    " be propagated, but sequence will not be changed");
8670       } else {
8671         /* no features, cannot do anything */
8672         SetValue (udp->sfb, UPDATE_CHOICE_NOT_SET);
8673         Disable (udp->sfb);
8674         Disable (udp->replace_all);
8675         Disable (udp->nobm);
8676         if (FALSE == udp->isSet)
8677           Message (MSG_OK, "Organisms are different, no features"
8678                    " to propagate, so nothing to do");
8679       }
8680       Disable (udp->rmc);
8681     }
8682   }
8683 
8684   /* If either sequence is not raw and not indexer version, only allow feature propagation */
8685   if (!indexerVersion &&
8686       (udp->oldbsp->repr != Seq_repr_raw || udp->newbsp->repr != Seq_repr_raw)) {
8687     SetValue (udp->sfb, UPDATE_FEATURES_ONLY);
8688     Disable (udp->sfb);
8689   }
8690 
8691   /* Disable accept button unless rmc and sfb are both preset */
8692 
8693   UpdateAccept (udp->rmc);
8694 
8695 }
8696 
8697 static void ChangeUpdateReplaceAll (ButtoN b)
8698 {
8699   UpsDataPtr udp;
8700   
8701   if (b == NULL) return;
8702   udp = (UpsDataPtr) GetObjectExtra (b);
8703   if (udp == NULL) return;
8704  
8705   if (GetStatus (b))
8706   {
8707         Disable (udp->nobm);
8708   }
8709   else
8710   {
8711         Enable (udp->nobm);
8712   }
8713   /* update accept button */
8714   UpdateAccept (udp->rmc);
8715 }
8716 
8717 static void CancelUpdate (ButtoN b)
8718 {
8719   UpsDataPtr udp;
8720   
8721   if (b == NULL) return;
8722   udp = (UpsDataPtr) GetObjectExtra (b);
8723   if (udp == NULL) return;
8724   CloseOutSequenceUpdateLog (udp);
8725   StdCancelButtonProc (b);
8726 }
8727 
8728 static GrouP CreateUpdateOperationsGroup (GrouP parent, UpsDataPtr udp)
8729 {
8730   GrouP  g;
8731   GrouP  gp1, gp2, gp3;
8732   ButtoN b1 = NULL, b2 = NULL, b3 = NULL, b4 = NULL;
8733   
8734   if (udp == NULL) return NULL;
8735   
8736   g = HiddenGroup (parent, -1, 0, NULL);
8737   SetGroupSpacing (g, 5, 5);
8738   
8739   gp1 = NormalGroup (g, 4, 0, "Alignment Relationship", programFont, NULL);
8740   udp->rmc = HiddenGroup (gp1, 4, 0, UpdateButtons);
8741   SetObjectExtra (udp->rmc, (Pointer) udp, NULL);
8742   SetGroupSpacing (udp->rmc, 10, 5);
8743   if (udp->do_update) {
8744     b1 = RadioButton (udp->rmc, "Replace");
8745   } else {
8746     b1= RadioButton (udp->rmc, "Extend Both Ends");
8747   }
8748   b2 = RadioButton (udp->rmc, "Extend 5'");
8749   b3 = RadioButton (udp->rmc, "Extend 3'");
8750   if (udp->do_update) {
8751     b4 = RadioButton (udp->rmc, "Patch");
8752   } else {
8753     b4 = NULL;
8754   }
8755 
8756   if (udp->do_update) {
8757     gp2 = NormalGroup (g, 4, 0, "Update Operation", programFont, NULL);
8758     udp->sfb = HiddenGroup (gp2, 3, 0, UpdateAccept);
8759     SetObjectExtra (udp->sfb, (Pointer) udp, NULL);
8760     SetGroupSpacing (udp->sfb, 10, 5);
8761     RadioButton (udp->sfb, "Sequence");
8762     RadioButton (udp->sfb, "Features");
8763     RadioButton (udp->sfb, "Sequence + Features");
8764   
8765     udp->keepProteinIDs = CheckBox (g, "Keep Protein IDs", NULL);
8766   
8767     gp3 = NormalGroup (g, 1, 0, "Feature Policy", programFont, NULL);
8768     udp->replace_all = CheckBox (gp3, "Replace All Features", ChangeUpdateReplaceAll);
8769     SetObjectExtra (udp->replace_all, (Pointer) udp, NULL);
8770     SetValue (udp->replace_all, FALSE);
8771     
8772     udp->nobm = NormalGroup (gp3, 5, 0, "Duplicate Features Only", programFont, UpdateAccept);
8773     SetObjectExtra (udp->nobm, (Pointer) udp, NULL);
8774     SetGroupSpacing (udp->nobm, 10, 5);
8775     RadioButton (udp->nobm, "New");
8776     RadioButton (udp->nobm, "Old");
8777     RadioButton (udp->nobm, "Both");
8778     RadioButton (udp->nobm, "Merge");
8779     RadioButton (udp->nobm, "Replace");
8780   
8781     AlignObjects (ALIGN_CENTER, (HANDLE) gp1, (HANDLE) gp2, 
8782                   (HANDLE) udp->keepProteinIDs,
8783                   (HANDLE) gp3,  NULL);
8784   }
8785   /* Enable/disable buttons based on the nature of the alignment */
8786     
8787   DetermineButtonState (udp, &b1, &b2, &b3, &b4);
8788   return g;
8789   
8790 }
8791 
8792 
8793 static void ChangeProteinUpdateStatus (ButtoN b)
8794 {
8795   UpsDataPtr udp;
8796   
8797   udp = (UpsDataPtr) GetObjectExtra (b);
8798   if (udp == NULL) return;
8799   SetProteinOptionsEnable (udp);
8800 }
8801 
8802 static void SkipUpdate (UpsDataPtr udp)
8803 {
8804   Char     acc_str [256];
8805   SeqIdPtr sip, sip_next;
8806   
8807   if (udp == NULL) return;
8808 
8809   OpenSequenceUpdateLog (udp);
8810   if (udp->log_fp != NULL && udp->oldbsp != NULL && udp->oldbsp->id != NULL)
8811   {
8812     sip = SeqIdFindBest (udp->oldbsp->id, 0);
8813     if (sip != NULL)
8814     {
8815       sip_next = sip->next;
8816       sip->next = NULL;
8817       SeqIdWrite (sip, acc_str, PRINTID_REPORT, sizeof (acc_str));
8818       fprintf (udp->log_fp, "Skipped update for %s\n", acc_str);
8819             udp->data_in_log = TRUE;
8820             sip->next = sip_next;
8821     }
8822   }
8823   
8824   /* if we are updating a set from a SeqSub, we don't want to free the SeqSub yet */
8825   if (udp->seqsubsep != NULL)
8826   {
8827     udp->newbsp = NULL;
8828   }
8829   FreeUdpFields (udp);
8830   UpdateNextBioseqInFastaSet (udp); 
8831 }
8832 
8833 static GrouP CreateExtraUpdateOptionsGroup (GrouP g, UpsDataPtr udp)
8834 {
8835   GrouP y, protein_options = NULL;
8836   
8837   if (udp == NULL || g == NULL) return NULL;
8838 
8839   y = HiddenGroup (g, -1, 0, NULL);
8840   
8841   udp->add_cit_subs = CheckBox (y, "Add Cit-subs for Updated Sequences", NULL);
8842   udp->update_quality_scores_btn = NULL;
8843   if (! ISA_aa (udp->oldbsp->mol) && udp->do_update)
8844   {
8845     udp->update_quality_scores_btn = CheckBox (y, "Replace Quality Scores", NULL);
8846     SetStatus (udp->update_quality_scores_btn, TRUE);
8847 
8848     udp->update_proteins = CheckBox (y, "Update Proteins for Updated Sequences", ChangeProteinUpdateStatus);
8849     SetObjectExtra (udp->update_proteins, (Pointer) udp, NULL);
8850     SetStatus (udp->update_proteins, FALSE);
8851     protein_options = HiddenGroup (y, 1, 0, NULL);
8852     udp->truncate_proteins_btn = CheckBox (protein_options,
8853                                      "Truncate retranslated proteins at stops",
8854                                            NULL);
8855     SetStatus (udp->truncate_proteins_btn,
8856                udp->truncate_proteins);
8857     udp->extend_proteins3_btn = CheckBox (protein_options,
8858                                   "Extend retranslated proteins without stops",
8859                                          NULL);
8860     udp->extend_proteins5_btn = CheckBox (protein_options,
8861                                   "Extend retranslated proteins without starts",
8862                                          NULL);
8863     udp->correct_cds_genes_btn = CheckBox (protein_options, "Correct CDS genes", NULL);
8864   
8865     SetStatus (udp->extend_proteins3_btn, udp->extend_proteins3);
8866     SetStatus (udp->extend_proteins5_btn, udp->extend_proteins5);
8867     SetStatus (udp->correct_cds_genes_btn, udp->correct_cds_genes);
8868   }
8869   AlignObjects (ALIGN_CENTER, (HANDLE) udp->add_cit_subs, 
8870                 (HANDLE) udp->update_quality_scores_btn,
8871                 (HANDLE) udp->update_proteins,
8872                 (HANDLE) protein_options,
8873                 NULL);
8874   return y;
8875 }
8876 
8877 static void SkipUpdateBtn (ButtoN b)
8878 {
8879   UpsDataPtr udp;
8880   
8881   udp = (UpsDataPtr) GetObjectExtra (b);
8882   if (udp == NULL) return;
8883   SafeHide (udp->form);
8884   Remove (udp->form);
8885 
8886   SkipUpdate (udp);  
8887 }
8888 
8889 /*------------------------------------------------------------------*/
8890 /*                                                                  */
8891 /* UpdateSequenceForm () -- Compares two sequences and displays a   */
8892 /*                          window giving the user options on how   */
8893 /*                          to update one from the other.           */
8894 /*                                                                  */
8895 /*------------------------------------------------------------------*/
8896 
8897 static ForM UpdateSequenceForm (UpsDataPtr udp)
8898 {
8899   ButtoN             b;
8900   GrouP              c, g, y, k, x, z = NULL;
8901   Uint2              hgt;
8902   GrouP              ppt0, ppt1, ppt2, ppt3;
8903   RecT               r;
8904   BaR                sb;
8905   Int4               scaleX;
8906   SeqIdPtr           sip;
8907   Char               strid1 [MAX_ID_LEN], strid2 [MAX_ID_LEN], txt0 [256];
8908   CharPtr            title;
8909   WindoW             w;
8910   GrouP              misc_options;
8911   Int4               prompt_width = 400;
8912   GrouP              left_panel;
8913   GrouP              right_panel;
8914 
8915   /* Check parameters */
8916 
8917   if ((udp->oldbsp == NULL) || (udp->newbsp == NULL))
8918     return NULL;
8919 
8920   /* Create window */
8921 
8922   if (udp->do_update) {
8923     title = "Update Sequence";
8924   } else {
8925     title = "Extend Sequence";
8926   }
8927   w = FixedWindow (-50, -33, -10, -10, title, NULL);
8928 
8929   if (w == NULL)
8930     return NULL;
8931   
8932   if (FALSE == udp->isSet)
8933     SetObjectExtra (w, (Pointer) udp, CleanupUpdateSequenceForm);
8934   udp->form = (ForM) w;
8935   
8936   /* Get string IDs for the Bioseqs */
8937 
8938   sip = SeqIdFindWorst (udp->oldbsp->id);
8939   SeqIdWrite (sip, strid1, PRINTID_REPORT, sizeof (strid1) - 1);
8940   sip = SeqIdFindWorst (udp->newbsp->id);
8941   SeqIdWrite (sip, strid2, PRINTID_REPORT, sizeof (strid2) - 1);
8942   if (StringNICmp (strid2, "SequinUpdateSequence", 20) == 0 &&
8943       udp->newbsp->id->next != NULL) {
8944     sip = SeqIdFindWorst (udp->newbsp->id->next);
8945     SeqIdWrite (sip, strid2, PRINTID_REPORT, sizeof (strid2) - 1);
8946   }
8947 
8948   /* FIll in some of the data structure */
8949   /* for passing to the callbacks.      */
8950 
8951   udp->formmessage = UpdateSequenceFormMessage;
8952 
8953 #ifdef WIN_MAC
8954   udp->activate = UpdateSequenceFormActivated;
8955   SetActivate (w, UpdateSequenceFormActivate);
8956 #endif
8957 
8958   udp->diffOrgs = FALSE;
8959 
8960   CalculateOverhangs (udp);
8961 
8962   /* Display the sequences */
8963 
8964   sprintf (txt0,
8965            "New sequence: %s - Length: %ld\nOld Sequence: %s - Length: %ld",
8966            strid2, (long) udp->newbsp->length, strid1,
8967            (long) udp->oldbsp->length);
8968   ppt0 = MultiLinePrompt (w, txt0, prompt_width, programFont);
8969   
8970   x = HiddenGroup (w, 2, 0, NULL);
8971   left_panel = HiddenGroup (x, -1, 0, NULL);
8972   y = left_panel;
8973   
8974   ppt1 = MultiLinePrompt (y, txt1, prompt_width, programFont);
8975   udp->overview = CreateViewer (y, prompt_width + Nlm_vScrollBarWidth, 100,
8976                                 FALSE, FALSE);
8977   
8978   ppt2 = MultiLinePrompt (y, txt2, prompt_width, programFont);
8979   udp->details = CreateViewer (y, prompt_width + Nlm_vScrollBarWidth, 80,
8980                                FALSE, FALSE);
8981   
8982   ppt3 = MultiLinePrompt (y, txt3, prompt_width, programFont);
8983     
8984 #ifdef WIN_MAC
8985   hgt = 90;
8986 #else
8987   hgt = 110;
8988 #endif
8989   udp->letters = AutonomousPanel4 (y, prompt_width + Nlm_vScrollBarWidth, hgt,
8990                                    LetDraw, NULL, LetScrl, 0, NULL, NULL);
8991   SetObjectExtra (udp->letters, (Pointer) udp, NULL);
8992   
8993   if (indexerVersion && shftKey) {
8994     ButtoN  b;
8995     z = HiddenGroup (y, 2, 0, NULL);
8996     SetGroupSpacing (z, 10, 3);
8997     b = PushButton (z, "Print Graphic", PrintGAln);
8998     SetObjectExtra (b, (Pointer) udp, NULL);
8999     b = PushButton (z, "Display Alignment", PrintTAln);
9000     SetObjectExtra (b, (Pointer) udp, NULL);
9001   }
9002   
9003   udp->ovpict = NULL;
9004   udp->dtpict = NULL;
9005 
9006   AlignObjects (ALIGN_CENTER, (HANDLE) udp->overview,
9007                 (HANDLE) udp->details, (HANDLE) udp->letters,
9008                 (HANDLE) ppt1, (HANDLE) ppt2,
9009                 (HANDLE) ppt3, NULL);
9010 
9011   right_panel = HiddenGroup (x, -1, 0, NULL);
9012   y = right_panel;
9013 
9014   k = HiddenGroup (y, -1, 0, NULL);
9015   g = CreateUpdateOperationsGroup (k, udp);
9016   misc_options = CreateExtraUpdateOptionsGroup (k, udp);  
9017   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) misc_options, NULL);
9018   
9019   c = HiddenGroup (w, 5, 0, NULL);
9020   if (udp->isSet)
9021   {
9022     udp->accept = DefaultButton (c, "Accept", AcceptRMCOrExtendSet);
9023     SetObjectExtra (udp->accept, (Pointer) udp, NULL);
9024     udp->acceptAll = DefaultButton (c, "Accept All", AcceptRMCOrExtendAll);
9025     SetObjectExtra (udp->acceptAll, (Pointer) udp, NULL);
9026     b = PushButton (c, "Skip", SkipUpdateBtn);
9027     SetObjectExtra (b, (Pointer) udp, NULL);  
9028   }
9029   else
9030   {
9031     udp->accept = DefaultButton (c, "Accept", AcceptRMCOrExtend);
9032     SetObjectExtra (udp->accept, (Pointer) udp, NULL);
9033   }
9034   
9035   b = PushButton (c, "Cancel", CancelUpdate);
9036   SetObjectExtra (b, (Pointer) udp, NULL);  
9037   UpdateButtons (udp->rmc);
9038 
9039   AlignObjects (ALIGN_CENTER,     
9040                 (HANDLE) ppt0,
9041                 (HANDLE) x,
9042                 (HANDLE) c, (HANDLE) z, NULL);
9043   RealizeWindow (w);
9044   
9045   udp->ovpict = MakeAlignPicture (udp, strid1, strid2, udp->salp);
9046   scaleX = CalculateBestScale (udp, udp->overview, udp->ovpict);
9047   AttachPicture (udp->overview, udp->ovpict, 0, 0, UPPER_LEFT,
9048                  scaleX, 1, FrameVwr);
9049   
9050   udp->dtpict = MakeAlignDetails (udp, strid1, strid2, udp->salp);
9051   scaleX = CalculateBestScale (udp, udp->details, udp->dtpict);
9052   udp->scaleX = scaleX;
9053   AttachPicture (udp->details, udp->dtpict, 0, 0, UPPER_LEFT,
9054                  scaleX, 1, FrameVwr);
9055   SetViewerData (udp->details, (Pointer) udp, NULL);
9056   SetViewerProcs (udp->details, DtlClck, NULL, NULL, NULL);
9057   
9058   udp->indels = ValNodeSort (udp->indels, SortVnpByInt);
9059   udp->mismatches = ValNodeSort (udp->mismatches, SortVnpByInt);
9060   
9061   SelectFont (SetSmallFont ());
9062   ObjectRect (udp->letters, &r);
9063   InsetRect (&r, 4, 4);
9064   udp->lineheight = LineHeight ();
9065   udp->charwidth = MaxCharWidth ();
9066   udp->maxchars = (r.right-r.left-2+udp->charwidth - 1) / udp->charwidth;
9067   SelectFont (systemFont);
9068   
9069   sb = GetSlateHScrollBar ((SlatE) udp->letters);
9070   SetBarMax (sb, udp->aln_length - (Int4) udp->maxchars);
9071   CorrectBarPage (sb, (Int4) udp->maxchars - 1, (Int4) udp->maxchars - 1);
9072   
9073   udp->recomb1 = -1;
9074   udp->recomb2 = -1;
9075   
9076   return (ForM) w;
9077 }
9078 
9079 
9080 /*=====================================================================*/
9081 /*                                                                     */
9082 /* PrepareToUpdateSequences ()                                         */
9083 /*                                                                     */
9084 /*=====================================================================*/
9085 
9086 static Boolean PrepareToUpdateSequences (UpsDataPtr udp)
9087 {
9088   ForM         f;
9089 
9090   if ( ! PrepareUpdatePtr (udp)) 
9091   {
9092     CloseOutSequenceUpdateLog (udp);
9093     return FALSE;       
9094   }
9095 
9096   if (TRUE == udp->useGUI)
9097   {
9098     if (udp->salp == NULL && udp->do_update &&
9099         (udp->no_aln_choice == UPDATE_REPLACE_THIS
9100          || udp->no_aln_choice == UPDATE_SKIP_THIS
9101          || udp->no_aln_choice == UPDATE_REPLACE_ALL
9102          || udp->no_aln_choice == UPDATE_REPLACE_THIS)) 
9103     {
9104       CalculateOverhangs (udp);
9105       DoAcceptRMCOrExtendSet (udp);
9106       UpdateNextBioseqInFastaSet (udp);
9107     }
9108     else
9109     {
9110       f = UpdateSequenceForm (udp);
9111       if (f == NULL) 
9112       {
9113         CloseOutSequenceUpdateLog (udp);        
9114         return FALSE;
9115       }
9116       Show (f);
9117       Select (f);
9118       SendHelpScrollMessage (helpForm, "Edit Menu", "Update Sequence");
9119     }
9120   }
9121   else {
9122     CalculateOverhangs (udp);
9123     DoAcceptRMCOrExtendSet (udp);
9124   }
9125   return TRUE;
9126 }
9127 
9128 /*=====================================================================*/
9129 /*                                                                     */
9130 /* FindMatchingBioseq () -- Callback function for exploring Bioseqs.   */
9131 /*                          Finds the bioseq that matches a given      */
9132 /*                          string ID.                                 */
9133 /*                                                                     */
9134 /*=====================================================================*/
9135 
9136 static Boolean LIBCALLBACK FindMatchingBioseq (BioseqPtr bsp,
9137                                         SeqMgrBioseqContextPtr bContext)
9138 {
9139   Char          currentId[MAX_ID_LEN];
9140   UpdateDataPtr pUpdateData;
9141   Int2          result;
9142   SeqIdPtr      sip, sip_next;
9143 
9144   pUpdateData = (UpdateDataPtr) bContext->userdata;
9145 
9146   /* Get the string IDs for the current Bioseq */
9147   
9148   for (sip = bsp->id; sip != NULL; sip = sip->next) 
9149   {
9150     sip_next = sip->next;
9151     sip->next = NULL;
9152     SeqIdWrite (sip, currentId, PRINTID_TEXTID_ACC_ONLY,
9153                     sizeof (currentId) - 1);
9154 
9155     /* Compare it to the string ID of the new Bioseq */
9156 
9157     result = StringICmp (pUpdateData->newId, currentId);
9158 
9159     /* if TEXTID_ACC_ONLY doesn't match, try PRINTID_REPORT */
9160     if (result != 0)
9161     {
9162       SeqIdWrite (sip, currentId, PRINTID_REPORT,
9163                         sizeof (currentId) - 1);
9164 
9165       /* Compare it to the string ID of the new Bioseq */
9166 
9167       result = StringICmp (pUpdateData->newId, currentId);
9168     }
9169 
9170           sip->next = sip_next;
9171     /* If they match, save the Bioseq and quit searching */
9172 
9173     if (0 == result) {
9174       pUpdateData->matchingBsp = bsp;
9175       return FALSE;
9176     }
9177   }
9178 
9179   /* Else continue */
9180 
9181   return TRUE;
9182 }
9183 
9184 static Boolean SkipProteinInNucUpdate (SeqEntryPtr sep, UpsDataPtr udp)
9185 {
9186   Char       newId[MAX_ID_LEN];
9187   SeqIdPtr   sip;
9188   BioseqPtr  bsp;
9189   Boolean    rval = FALSE;
9190   MsgAnswer  ans;
9191   
9192   if (sep == NULL || ! IS_Bioseq (sep) || sep->data.ptrvalue == NULL || udp == NULL)
9193   {
9194     return FALSE;
9195   }
9196    
9197   bsp = (BioseqPtr) sep->data.ptrvalue;
9198   if (ISA_na (bsp->mol))
9199   {
9200     return FALSE;
9201   }
9202   
9203   sip = SeqIdFindWorst (bsp->id);
9204   SeqIdWrite (sip, newId, PRINTID_REPORT, sizeof (newId) - 1);
9205   ans = Message (MSG_YN, "Found a protein (%s) in the update file, expecting "
9206          "only nucleotides.  Do you want to skip this sequence and continue?", newId);
9207   if (ans == ANS_YES)
9208   {
9209     rval = TRUE;
9210     fprintf (udp->log_fp, "Skipped protein Bioseq (%s) in nucleotide update\n", newId);
9211           udp->data_in_log = TRUE;
9212   }
9213   return rval;
9214 }
9215 
9216 static void RemoveUpdateSet (UpsDataPtr udp)
9217 {
9218 #if 0
9219   ObjMgrPtr omp;