NCBI C Toolkit Cross Reference

C/sequin/sequin8.c


  1 /*   sequin8.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:  sequin8.c
 27 *
 28 * Author:  Jonathan Kans
 29 *
 30 * Version Creation Date:   2/3/98
 31 *
 32 * $Revision: 6.557 $
 33 *
 34 * File Description: 
 35 *
 36 * Modifications:  
 37 * --------------------------------------------------------------------------
 38 * Date     Name        Description of modification
 39 * -------  ----------  -----------------------------------------------------
 40 *
 41 *
 42 * ==========================================================================
 43 */
 44 
 45 #include "sequin.h"
 46 #include <objsub.h>
 47 #include <valid.h>
 48 #include <cdrgn.h>
 49 #include <suggslp.h>
 50 #include <toasn3.h>
 51 #include <subutil.h>
 52 #include <explore.h>
 53 #include <medarch.h>
 54 #include <medutil.h>
 55 #include <tofasta.h>
 56 #include <asn2gnbk.h>
 57 #include <alignmgr2.h>
 58 #include <spidey.h>
 59 #include <blast.h>
 60 #include <salpanel.h>
 61 #include <seqpanel.h>
 62 #include <edutil.h>
 63 #include <tax3api.h>
 64 #include <asn2gnbp.h> /* included for discrepancy report */
 65 #include <algo/blast/api/twoseq_api.h>
 66 #include <algo/blast/api/blast_seqalign.h>
 67 
 68 #include <macrodlg.h>
 69 #include <macroapi.h>
 70 #include <alignval.h>
 71 #include <pubdesc.h>
 72 
 73 #define DEFLINE_MAX_LEN          380
 74 #define TEXT_MAX_LEN             64
 75 #define DEFLINE_MAX_GENENAME_LEN 64
 76 #define ALL_FEATURES             255
 77 
 78 typedef struct evidenceformdata {
 79   FEATURE_FORM_BLOCK
 80 
 81   LisT           objlist;
 82   TexT           findthis;
 83   Uint2          itemtype;
 84   Uint2          subtype;
 85   PopuP          evdence;
 86   Uint2          exp_ev;
 87   ValNodePtr     head;
 88   Boolean        stringfound;
 89   Char           findStr [128];
 90   ButtoN         case_insensitive;
 91   ButtoN         when_string_not_present;
 92 } EvidenceFormData, PNTR 
 93 
 94 EvidenceFormPtr;
 95 
 96 typedef struct codebreakformdata {
 97   FEATURE_FORM_BLOCK
 98   PopuP  aminoAcidPopup;
 99   Char   currentCodonStr [4];
100   TexT   codonText;
101   ButtoN acceptButton;
102 } CodeBreakFormData, PNTR CodeBreakFormPtr;
103 
104 static Boolean IsRealImpFeat (Uint2 subtype)
105 
106 {
107   if (subtype >= FEATDEF_allele && subtype <= FEATDEF_site_ref) return TRUE;
108   if (subtype == FEATDEF_oriT) return TRUE;
109   return FALSE;
110 }
111 
112 
113 
114 static void BreakIntoAGroup (BioseqSetPtr parent, Uint1 _class, SeqEntryPtr list)
115 
116 {
117   BioseqSetPtr  bssp;
118   Int2          count;
119   SeqEntryPtr   sep;
120   SeqEntryPtr   tmp;
121 
122   while (list != NULL) {
123     bssp = BioseqSetNew ();
124     if (bssp == NULL) return;
125     bssp->_class = _class;
126     sep = SeqEntryNew ();
127     if (sep == NULL) return;
128     sep->choice = 2;
129     sep->data.ptrvalue = (Pointer) bssp;
130     if (parent->seq_set != NULL) {
131       tmp = parent->seq_set;
132       while (tmp->next != NULL) {
133         tmp = tmp->next;
134       }
135       tmp->next = sep;
136     } else {
137       parent->seq_set = sep;
138     }
139     bssp->seq_set = list;
140     for (tmp = list, count = 0; tmp != NULL && count < 99; tmp = tmp->next, count++) continue;
141     if (tmp != NULL) {
142       list = tmp->next;
143       tmp->next = NULL;
144     } else {
145       list = NULL;
146     }
147   }
148 }
149 
150 
151 extern Int2 LIBCALLBACK MakeGroupsOf200 (Pointer data)
152 
153 {
154   BioseqSetPtr      bssp;
155   ObjMgrDataPtr     omdptop;
156   ObjMgrData        omdata;
157   OMProcControlPtr  ompcp;
158   Uint2             parenttype;
159   Pointer           parentptr;
160   SeqEntryPtr       sep;
161   AsnIoPtr       aip;
162   Uint1          _class;
163   Int2           count;
164   Char           file [FILENAME_MAX];
165   SeqEntryPtr    list;
166   SeqEntryPtr    next;
167   Char           output [PATH_MAX];
168   Char           path [PATH_MAX];
169   CharPtr        ptr;
170   SeqSubmitPtr   ssp;
171   Char           str [FILENAME_MAX];
172   SeqEntryPtr    tmp;
173 #ifdef WIN_MAC
174   FILE           *f;
175 #endif
176 
177   ompcp = (OMProcControlPtr) data;
178   if (ompcp == NULL) return OM_MSG_RET_ERROR;
179   if (ompcp->input_itemtype != OBJ_BIOSEQSET) {
180     Message (MSG_ERROR, "Must select Bioseq-set!");
181     return OM_MSG_RET_ERROR;
182   }
183   bssp = (BioseqSetPtr) ompcp->input_data; 
184   if (bssp == NULL) return OM_MSG_RET_ERROR;
185   sep = SeqMgrGetSeqEntryForData (bssp);
186   
187   _class = bssp->_class;
188   if (_class != 7 && _class != 13 && _class != 14 &&
189       _class != 15 && _class != 16 && _class != 18) { 
190     Message (MSG_ERROR, "Can only use this for GenBank, Mut, Pop, Phy, Eco, and WGS sets!");
191     return OM_MSG_RET_ERROR;
192   }
193 
194   SaveSeqEntryObjMgrData (sep, &omdptop, &omdata);
195   GetSeqEntryParent (sep, &parentptr, &parenttype);
196 
197   list = bssp->seq_set;
198   bssp->seq_set = NULL;
199   bssp->_class = 7;
200   BreakIntoAGroup (bssp, _class, list);
201 
202   SeqMgrLinkSeqEntry (sep, parenttype, parentptr);
203   RestoreSeqEntryObjMgrData (sep, omdptop, &omdata);
204   PropagateFromGenBankBioseqSet (sep, TRUE);
205 
206   if (parenttype == OBJ_SEQSUB) {
207     if (GetOutputFileName (path, sizeof (path), "")) {
208       ssp = (SeqSubmitPtr) parentptr;
209       if (ssp != NULL && ssp->datatype == 1) {
210         sep = (SeqEntryPtr) ssp->data;
211         ptr = StringRChr (path, DIRDELIMCHR);
212         if (ptr != NULL) {
213           ptr++;
214           StringNCpy_0 (file, ptr, sizeof (file));
215           *ptr = '\0';
216           tmp = bssp->seq_set;
217           count = 0;
218           while (tmp != NULL) {
219             next = tmp->next;
220             tmp->next = NULL;
221             ssp->data = (Pointer) tmp;
222             StringCpy (output, path);
223             count++;
224             if (count < 10) {
225               sprintf (str, "%s0%1d", file, (int) count);
226             } else {
227               sprintf (str, "%s%2d", file, (int) count);
228             }
229             FileBuildPath (output, NULL, str);
230 #ifdef WIN_MAC
231             f = FileOpen (output, "r");
232             if (f != NULL) {
233               FileClose (f);
234             } else {
235               FileCreate (output, "TEXT", "ttxt");
236             }
237 #endif
238             aip = AsnIoOpen (output, "w");
239             if (aip != NULL) {
240               SeqSubmitAsnWrite (ssp, aip, NULL);
241             }
242             AsnIoClose (aip);
243             tmp->next = next;
244             tmp = next;
245           }
246           ssp->data = (Pointer) sep;
247         }
248       }
249     }
250   }
251 
252   ObjMgrSetDirtyFlag (ompcp->input_entityID, TRUE);
253   ObjMgrSendMsg (OM_MSG_UPDATE, ompcp->input_entityID, 0, 0);
254   Update ();  
255   return OM_MSG_RET_DONE;
256 }
257 
258 extern void ParseInNucUpdates (IteM i)
259 
260 {
261   BaseFormPtr  bfp;
262   SeqEntryPtr  sep;
263 
264 #ifdef WIN_MAC
265   bfp = currentFormDataPtr;
266 #else
267   bfp = GetObjectExtra (i);
268 #endif
269   if (bfp == NULL) return;
270   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
271   if (sep == NULL) return;
272   Message (MSG_OK, "Not yet implemented");
273 }
274 
275 #undef NLM_EXTERN
276 #ifdef NLM_IMPORT
277 #define NLM_EXTERN NLM_IMPORT
278 #else
279 #define NLM_EXTERN extern
280 #endif
281 
282 static Int2 GeneticCodeFromCrp (CdRegionPtr crp)
283 
284 {
285   Int2            code;
286   GeneticCodePtr  gcp;
287   Char            name [256];
288   ValNodePtr      tmp;
289 
290   code = 0;
291   name [0] = '\0';
292   gcp = crp->genetic_code;
293   if (gcp != NULL) {
294     tmp = (ValNodePtr) gcp->data.ptrvalue;
295     for (tmp = (ValNodePtr) gcp->data.ptrvalue; tmp != NULL; tmp = tmp->next) {
296       switch (tmp->choice) {
297         case 1 :
298           if (name [0] == '\0') {
299             StringNCpy_0 (name, (CharPtr) tmp->data.ptrvalue, sizeof (name));
300           }
301           break;
302         case 2 :
303           code = tmp->data.intvalue;
304           break;
305         default :
306           break;
307       }
308     }
309     if (code == 0) {
310       gcp = GeneticCodeFind (code, name);
311       if (gcp != NULL) {
312         for (tmp = (ValNodePtr) gcp->data.ptrvalue; tmp != NULL; tmp = tmp->next) {
313           switch (tmp->choice) {
314             case 2 :
315               code = tmp->data.intvalue;
316               break;
317             default :
318               break;
319           }
320         }
321       }
322     }
323   }
324   return code;
325 }
326 
327 extern void ExtendSeqLocToPosition (SeqLocPtr slp, Boolean end5, Int4 pos)
328 {
329   Uint1          strand;
330   SeqLocPtr      slp_to_change, slp_index;
331   Int4           extent_to_change;
332   Int4           start, stop;
333   SeqIdPtr       sip;
334   BioseqPtr      bsp;
335   
336   if (slp == NULL || pos < 0) return;
337   
338   bsp = BioseqFindFromSeqLoc (slp);
339   if (bsp == NULL) return;
340 
341   slp_to_change = NULL;
342   strand = SeqLocStrand (slp);
343   switch (slp->choice)
344   {
345     case SEQLOC_INT:
346       slp_to_change = slp;
347       break;
348     case SEQLOC_MIX:
349         case SEQLOC_PACKED_INT:
350       sip = SeqLocId (slp);
351       if (sip == NULL) return; /* can only process if all on one bioseq */
352       slp_to_change = NULL;
353       if ((strand == Seq_strand_minus && end5)
354         || (strand != Seq_strand_minus && !end5))
355       {
356         extent_to_change = 0;
357         for (slp_index = (SeqLocPtr)slp->data.ptrvalue; slp_index != NULL; slp_index = slp_index->next)
358         {
359           stop = GetOffsetInBioseq (slp_index, bsp, SEQLOC_STOP);
360           if (stop > extent_to_change)
361           {
362             slp_to_change = slp_index;
363             extent_to_change = stop;
364           }
365         }
366       }
367       else
368       {
369         extent_to_change = bsp->length;
370         for (slp_index = (SeqLocPtr)slp->data.ptrvalue; slp_index != NULL; slp_index = slp_index->next)
371         {
372           start = GetOffsetInBioseq (slp_index, bsp, SEQLOC_START);
373           if (start < extent_to_change)
374           {
375             slp_to_change = slp_index;
376             extent_to_change = start;
377           }
378         }
379       }
380       break;
381   }
382 
383   if (slp_to_change != NULL)
384   {
385     if ((strand == Seq_strand_minus && end5)
386       || (strand != Seq_strand_minus && !end5))
387     {
388       start = GetOffsetInBioseq (slp_to_change, bsp, SEQLOC_START);
389       stop = pos;
390     }
391     else
392     {
393       start = pos;
394       stop = GetOffsetInBioseq (slp_to_change, bsp, SEQLOC_STOP);
395     }
396     if (start < 0 
397         || stop > bsp->length - 1
398         || start > stop)
399     {
400       return;
401     }
402     expand_seq_loc (start, stop, strand, slp_to_change);
403   }
404 }
405 
406 
407 static void ExtendOnePartialFeatureExEx (SeqFeatPtr sfp, Boolean extend5, Boolean extend3, Boolean stop_at_gap)
408 {
409   BioseqPtr   bsp;
410   Boolean     partial3, partial5;
411   Int4        start_diff;
412   CdRegionPtr crp;
413 
414   if (sfp == NULL) return;
415   bsp = BioseqFindFromSeqLoc (sfp->location);
416   if (bsp == NULL) return;
417   CheckSeqLocForPartial (sfp->location, &partial5, &partial3);
418   if (partial5 && extend5)
419   {
420     if (stop_at_gap) {
421       start_diff = ExtendSeqLocToEndOrGap (sfp->location, bsp, TRUE);
422     } else {
423       start_diff = ExtendSeqLocToEnd (sfp->location, bsp, TRUE);
424     }
425     if (start_diff > 0 && sfp->data.choice == SEQFEAT_CDREGION) {
426       crp = (CdRegionPtr) sfp->data.value.ptrvalue;
427       if (crp != NULL) {
428           if (crp->frame == 0) {
429               crp->frame = 1;
430           }
431           crp->frame = (crp->frame + start_diff - 1) % 3 + 1;
432       }
433     }
434   }
435   if (partial3 && extend3)
436   {
437     if (stop_at_gap) {
438       ExtendSeqLocToEndOrGap (sfp->location, bsp, FALSE);
439     } else {
440       ExtendSeqLocToEnd (sfp->location, bsp, FALSE);
441     }
442   }
443 }
444 
445 
446 static void ExtendOnePartialFeatureEx (SeqFeatPtr sfp, Boolean extend5, Boolean extend3)
447 {
448   ExtendOnePartialFeatureExEx (sfp, extend5, extend3, FALSE);
449 }
450 
451 
452 static void ExtendOnePartialFeatureToEndOrGap (SeqFeatPtr sfp, Pointer userdata)
453 {
454   ExtendOnePartialFeatureExEx (sfp, TRUE, TRUE, TRUE);
455 }
456 
457 
458 static void ExtendOnePartialFeature (SeqFeatPtr sfp, Pointer userdata)
459 {
460   ExtendOnePartialFeatureEx (sfp, TRUE, TRUE);
461 }
462 
463 extern void ExtendPartialFeatures (IteM i)
464 {
465   BaseFormPtr       bfp;
466   SeqEntryPtr       sep, old_scope;
467   SelStructPtr      sel;
468   SeqFeatPtr        sfp;
469   SeqMgrFeatContext fcontext;
470 
471 #ifdef WIN_MAC
472   bfp = currentFormDataPtr;
473 #else
474   bfp = GetObjectExtra (i);
475 #endif
476   if (bfp == NULL) return;
477   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
478   if (sep == NULL) return;
479   sel = ObjMgrGetSelected ();
480   WatchCursor ();
481   Update ();
482   old_scope = SeqEntrySetScope(sep);
483   if (sel == NULL)
484   {
485     VisitFeaturesInSep (sep, NULL, ExtendOnePartialFeature);
486   }
487   else
488   {
489     while (sel != NULL)
490     {
491       if (sel->entityID == bfp->input_entityID
492         && sel->itemtype == OBJ_SEQFEAT)
493       {
494         sfp = SeqMgrGetDesiredFeature (bfp->input_entityID, NULL, sel->itemID, 0, NULL, &fcontext);
495         if (sfp != NULL)
496         {
497           ExtendOnePartialFeature (sfp, NULL);
498         }
499       }
500       sel = sel->next;
501     }
502   }
503   SeqEntrySetScope(old_scope);
504   ArrowCursor ();
505   Update ();
506   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
507   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
508 }
509 
510 
511 typedef struct extendpartialfeaturesform {
512   FORM_MESSAGE_BLOCK
513   DialoG feature_type;
514   ButtoN extend5;
515   ButtoN extend3;
516   ButtoN stop_at_gaps;
517   DialoG string_constraint;
518   ButtoN leave_dlg_up;
519 } ExtendPartialFeaturesFormData, PNTR ExtendPartialFeaturesFormPtr;
520 
521 static void DoExtendPartialFeatures (ButtoN b)
522 {
523   ExtendPartialFeaturesFormPtr f;
524   SeqEntryPtr sep;
525   AECRActionPtr action;
526   ApplyActionPtr fake_apply;
527   FeatureFieldPtr feature_field;
528   ValNodePtr vnp;
529   StringConstraintPtr scp;
530   ValNodePtr object_list;
531   Boolean    extend5, extend3, stop_at_gaps;
532 
533   f = (ExtendPartialFeaturesFormPtr) GetObjectExtra (b);
534   if (f == NULL) return;
535 
536   sep = GetTopSeqEntryForEntityID (f->input_entityID);
537   if (sep == NULL) return;
538 
539   /* note - this is a small amount of hackery, designed to put off adding "extend partial features" as a macro language action.
540    * if this is ever added, this code should be moved to macroapi.c.
541    */
542   feature_field = FeatureFieldNew ();
543   vnp = DialogToPointer (f->feature_type);
544   if (vnp == NULL) {
545     feature_field->type = Feature_type_any;
546   } else {
547     feature_field->type = vnp->choice;
548     vnp = ValNodeFree (vnp);
549   }
550   fake_apply = ApplyActionNew ();
551   ValNodeAddPointer (&(fake_apply->field), FieldType_feature_field, feature_field);
552   action = AECRActionNew ();
553   ValNodeAddPointer (&(action->action), ActionChoice_apply, fake_apply);
554   
555   scp = DialogToPointer (f->string_constraint);
556   if (scp != NULL) {
557     ValNodeAddPointer (&(action->constraint), ConstraintChoice_string, scp);
558   }
559   object_list = GetObjectListForAECRAction (sep, action);
560   action = AECRActionFree (action);
561 
562   extend5 = GetStatus (f->extend5);
563   extend3 = GetStatus (f->extend3);
564   stop_at_gaps = GetStatus (f->stop_at_gaps);
565   for (vnp = object_list; vnp != NULL; vnp = vnp->next) {
566     if (vnp->choice == OBJ_SEQFEAT && vnp->data.ptrvalue != NULL) {
567       ExtendOnePartialFeatureExEx (vnp->data.ptrvalue, extend5, extend3, stop_at_gaps);
568     }
569   }
570   object_list = ValNodeFree (object_list);
571   ArrowCursor ();
572   Update ();
573   ObjMgrSetDirtyFlag (f->input_entityID, TRUE);
574   ObjMgrSendMsg (OM_MSG_UPDATE, f->input_entityID, 0, 0);
575   if (!GetStatus (f->leave_dlg_up)) {
576     Remove (f->form);
577   }
578 }
579 
580 
581 extern void ExtendPartialFeaturesWithConstraint (IteM i)
582 {
583   BaseFormPtr       bfp;
584   ExtendPartialFeaturesFormPtr f;
585   ValNodePtr          feature_list = NULL;
586   ValNode             vn;
587   WindoW              w;
588   GrouP               h, g, c;
589   PrompT              p1, p2;
590   ButtoN              b;
591 
592 #ifdef WIN_MAC
593   bfp = currentFormDataPtr;
594 #else
595   bfp = GetObjectExtra (i);
596 #endif
597   if (bfp == NULL) return;
598 
599   f = (ExtendPartialFeaturesFormPtr) MemNew (sizeof (ExtendPartialFeaturesFormData));
600   if (f == NULL) return;
601     
602   w = FixedWindow (-50, -33, -10, -10, "Extend Partial Features", StdCloseWindowProc);
603   SetObjectExtra (w, f, StdCleanupExtraProc);
604   f->form = (ForM) w;
605   f->input_entityID = bfp->input_entityID;
606   
607   h = HiddenGroup (w, -1, 0, NULL);
608   SetGroupSpacing (h, 10, 10);
609 
610   p1 = StaticPrompt (h, "Feature Type to Extend", 0, dialogTextHeight, programFont, 'c');
611   ValNodeAddPointer (&feature_list, Feature_type_any, StringSave ("Any"));
612   AddAllFeaturesToChoiceList (&feature_list);
613   
614   f->feature_type = ValNodeSelectionDialog (h, feature_list, TALL_SELECTION_LIST, ValNodeStringName,
615                                 ValNodeSimpleDataFree, ValNodeStringCopy,
616                                 ValNodeChoiceMatch, "feature type", 
617                                 NULL, NULL, FALSE);
618   vn.choice = Feature_type_any;
619   vn.data.ptrvalue = NULL;
620   vn.next = NULL;
621   PointerToDialog (f->feature_type, &vn);
622 
623   g = HiddenGroup (h, 2, 0, NULL);
624   f->extend5 = CheckBox (g, "Extend partial 5'", NULL);
625   SetStatus (f->extend5, TRUE);
626   f->extend3 = CheckBox (g, "Extend partial 3'", NULL);
627   SetStatus (f->extend3, TRUE);
628 
629   f->stop_at_gaps = CheckBox (h, "Stop at gaps", NULL);
630   SetStatus (f->stop_at_gaps, TRUE);
631   
632   p2 = StaticPrompt (h, "Optional Constraint", 0, dialogTextHeight, programFont, 'c');
633   f->string_constraint = StringConstraintDialog (h, "Where feature text", FALSE, NULL, NULL);
634   
635   c = HiddenGroup (h, 3, 0, NULL);
636   b = PushButton (c, "Accept", DoExtendPartialFeatures);
637   SetObjectExtra (b, f, NULL);
638   PushButton (c, "Cancel", StdCancelButtonProc);
639   f->leave_dlg_up = CheckBox (c, "Leave Dialog Up", NULL);
640 
641   AlignObjects (ALIGN_CENTER, (HANDLE) p1,
642                               (HANDLE) f->feature_type,
643                               (HANDLE) g,
644                               (HANDLE) f->stop_at_gaps,
645                               (HANDLE) p2,
646                               (HANDLE) f->string_constraint,
647                               (HANDLE) c,
648                               NULL);
649   Show (w);
650 }
651 
652 
653 static Boolean HasValidStartCodon (SeqFeatPtr cds)
654 {
655   ByteStorePtr  bs;
656   CharPtr       prot;
657 
658   if (cds == NULL) return FALSE;
659 
660   bs = ProteinFromCdRegionEx (cds, TRUE, FALSE);
661 
662   if (bs == NULL) return FALSE;
663   prot = BSMerge (bs, NULL);
664   bs = BSFree (bs);
665   if (prot == NULL) return FALSE;
666   if (prot [0] != 'M') return FALSE;
667   return TRUE;
668 }
669 
670 static void FixReadingFrame (
671   CdRegionPtr crp,
672   SeqLocPtr slp,
673   BioseqPtr bsp,
674   Int4 start
675 )
676 {
677   Int4 offset;
678 
679   if (crp == NULL || slp == NULL) return;
680 
681   if (SeqLocStrand (slp) == Seq_strand_minus)
682   {
683     offset = bsp->length - start;
684   }
685   else
686   {
687     offset = start;
688   }
689   start = offset % 3;
690   start = start + 1;
691   crp->frame = start;
692 }
693 
694 extern void RecomputeSuggestedIntervalsForCDS 
695 (Uint2          entityID,
696  BioseqPtr PNTR batchbsp,
697  Int4Ptr        count,
698  MonitorPtr     mon,
699  SeqFeatPtr     sfp)
700 {
701   Int2           code;
702   CdRegionPtr    crp;
703   BioseqPtr      nucbsp;
704   BioseqPtr      protbsp;
705   SeqIdPtr       sip;
706   SeqLocPtr      slp;
707   Char           str [256];
708   Char           tmp [256];
709   Boolean        partial3, partial5;
710 
711   if (sfp == NULL || sfp->data.choice != SEQFEAT_CDREGION) return;
712   crp = (CdRegionPtr) sfp->data.value.ptrvalue;
713   if (crp == NULL) return;
714 
715   code = GeneticCodeFromCrp (crp);
716 
717   nucbsp = GetBioseqGivenSeqLoc (sfp->location, entityID);
718   if (nucbsp != NULL && batchbsp != NULL && *batchbsp != NULL 
719       && nucbsp != *batchbsp) {
720     ClearBatchSuggestNucleotide ();
721     *batchbsp = nucbsp;
722     SetBatchSuggestNucleotide (*batchbsp, code);
723 /*    Message (MSG_POSTERR, "Recompute Suggest is reverting to slower processing"); */
724   }
725   sip = SeqLocId (sfp->product);
726   if (sip != NULL) {
727     protbsp = BioseqFind (sip);
728     if (nucbsp != NULL && protbsp != NULL &&
729         ISA_na (nucbsp->mol) && ISA_aa (protbsp->mol) &&
730         nucbsp->length > 0 && protbsp->length > 0) {
731       str [0] = '\0';
732       tmp [0] = '\0';
733       sip = SeqIdFindWorst (protbsp->id);
734       SeqIdWrite (sip, tmp, PRINTID_REPORT, sizeof (tmp));
735       if (count != NULL)
736       {
737         (*count) ++;
738         if (mon != NULL)
739         {
740           sprintf (str, "Processing sequence %d [%s]", *count, tmp);
741           MonitorStrValue (mon, str);
742           Update ();
743         }
744       }
745       slp = PredictCodingRegion (nucbsp, protbsp, code);
746       if (slp == NULL) return;
747 
748       /* correct for partial conditions */
749       CheckSeqLocForPartial (sfp->location, &partial5, &partial3);
750 
751       sfp->location = SeqLocFree (sfp->location);
752       sfp->location = slp;
753 
754       /* if no valid start codon, cds is 5' partial */
755       if (! HasValidStartCodon (sfp))
756       {
757         partial5 = TRUE;
758       }
759 
760       if (partial5 || partial3)
761       {
762 #if 0 
763         /* removed, per DeAnne's request */     
764         if (partial5)
765         {
766           start = GetOffsetInBioseq (sfp->location, nucbsp, SEQLOC_START);
767           FixReadingFrame (crp, sfp->location, nucbsp, start);
768           ExtendSeqLocToEnd (sfp->location, nucbsp, TRUE);
769         }
770 #endif        
771         if (partial3)
772         {
773           ExtendSeqLocToEnd (sfp->location, nucbsp, FALSE);
774         }
775         SetSeqLocPartial (sfp->location, partial5, partial3);
776       }
777       sfp->partial = LocationHasNullsBetween (sfp->location);
778       sfp->partial |= partial5 || partial3;
779     }
780   }
781 }
782 
783 extern void RecomputeIntervalsForOneCDS (SeqFeatPtr sfp, RecompDataPtr rdp)
784 {
785   SeqFeatPtr gene_to_update = NULL;
786   SeqLocPtr      orig_loc = NULL;
787   
788   if (sfp == NULL || sfp->data.choice != SEQFEAT_CDREGION || rdp == NULL)
789   {
790     return;
791   }
792 
793   if (rdp->fix_genes)
794   {
795     gene_to_update = SeqMgrGetOverlappingGene (sfp->location, NULL);
796     orig_loc = (SeqLocPtr) AsnIoMemCopy (sfp->location, 
797                                          (AsnReadFunc) SeqLocAsnRead,
798                                          (AsnWriteFunc) SeqLocAsnWrite);
799   }
800   RecomputeSuggestedIntervalsForCDS (rdp->entityID, &(rdp->batchbsp),
801                                      &(rdp->count), rdp->mon, sfp);
802 
803   if (gene_to_update != NULL)
804   {
805     UpdateGeneLocation (gene_to_update, orig_loc,
806                         sfp->location, rdp->entityID);
807   }
808   orig_loc = SeqLocFree (orig_loc);
809   
810 }
811 
812 static Boolean RecomputeSuggCallback (GatherContextPtr gcp)
813 {
814   RecompDataPtr  rdp;
815   SeqFeatPtr     sfp;
816 
817   if (gcp == NULL) return TRUE;
818   if (gcp->thistype != OBJ_SEQFEAT) return TRUE;
819   rdp = (RecompDataPtr) gcp->userdata;
820   if (rdp == NULL) return TRUE;
821   sfp = (SeqFeatPtr) gcp->thisitem;
822   if (sfp == NULL || sfp->data.choice != SEQFEAT_CDREGION) return TRUE;
823 
824   RecomputeIntervalsForOneCDS (sfp, rdp);
825   return TRUE;
826 }
827 
828 extern void RecomputeSuggestEx (Uint2 entityID, Boolean fix_genes, Boolean recompute_all)
829 
830 {
831   Int2              code;
832   GatherScope       gs;
833   SeqEntryPtr       nucsep;
834   RecompData        rd;
835   SeqEntryPtr       sep;
836   SelStructPtr      sel;
837   SeqFeatPtr        sfp;
838   SeqMgrFeatContext fcontext;
839 
840   sep = GetTopSeqEntryForEntityID (entityID);
841   if (sep == NULL) return;
842   sel = ObjMgrGetSelected ();
843   WatchCursor ();
844   Update ();
845   rd.count = 0;
846   rd.mon = MonitorStrNewEx ("Correcting Coding Regions", 20, FALSE);
847   rd.batchbsp = NULL;
848   rd.no_stop_at_end_of_complete_cds = FALSE;
849   rd.fix_genes = fix_genes;
850   rd.entityID = entityID;
851   nucsep = FindNucSeqEntry (sep);
852   if (nucsep != NULL && IS_Bioseq (nucsep)) {
853     rd.batchbsp = (BioseqPtr) nucsep->data.ptrvalue;
854   }
855   if (rd.batchbsp != NULL) {
856     code = SeqEntryToGeneticCode (sep, NULL, NULL, 0);
857     SetBatchSuggestNucleotide (rd.batchbsp, code);
858   }
859   if (sel == NULL || recompute_all)
860   {
861     MemSet ((Pointer) (&gs), 0, sizeof (GatherScope));
862     gs.seglevels = 1;
863     gs.get_feats_location = FALSE;
864     MemSet((Pointer)(gs.ignore), (int)(TRUE), (size_t)(OBJ_MAX * sizeof(Boolean)));
865     gs.ignore[OBJ_BIOSEQ] = FALSE;
866     gs.ignore[OBJ_BIOSEQ_SEG] = FALSE;
867     gs.ignore[OBJ_SEQFEAT] = FALSE;
868     gs.ignore[OBJ_SEQANNOT] = FALSE;
869     GatherEntity (entityID, (Pointer) (&rd), RecomputeSuggCallback, &gs);
870   }
871   else
872   {
873     while (sel != NULL)
874     {
875       if (sel->entityID == entityID
876         && sel->itemtype == OBJ_SEQFEAT)
877       {
878         sfp = SeqMgrGetDesiredFeature (entityID, NULL, sel->itemID, 0, NULL, &fcontext);
879         if (sfp != NULL && sfp->idx.subtype == FEATDEF_CDS)
880         {
881           RecomputeIntervalsForOneCDS (sfp, &rd);
882         }
883       }
884       sel = sel->next;
885     }
886   }
887   MonitorFree (rd.mon);
888   if (rd.batchbsp != NULL) {
889     ClearBatchSuggestNucleotide ();
890   }
891   ArrowCursor ();
892   Update ();
893   ObjMgrSetDirtyFlag (entityID, TRUE);
894   ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
895 }
896 
897 extern void RecomputeSuggest (IteM i)
898 {
899   BaseFormPtr       bfp;
900 
901 #ifdef WIN_MAC
902   bfp = currentFormDataPtr;
903 #else
904   bfp = GetObjectExtra (i);
905 #endif
906   if (bfp == NULL)
907   {
908     return;
909   }
910   RecomputeSuggestEx (bfp->input_entityID, FALSE, FALSE);
911 }
912 
913 extern void RecomputeSuggestFixGenes (IteM i)
914 {
915   BaseFormPtr       bfp;
916 
917 #ifdef WIN_MAC
918   bfp = currentFormDataPtr;
919 #else
920   bfp = GetObjectExtra (i);
921 #endif
922   if (bfp == NULL)
923   {
924     return;
925   }
926   RecomputeSuggestEx (bfp->input_entityID, TRUE, FALSE);
927 }
928 
929 
930 static Boolean RetranslateCDSCallback (GatherContextPtr gcp)
931 
932 {
933   RecompDataPtr  rdp;
934   SeqFeatPtr     sfp;
935 
936   if (gcp == NULL) return TRUE;
937   if (gcp->thistype != OBJ_SEQFEAT) return TRUE;
938   rdp = (RecompDataPtr) gcp->userdata;
939   if (rdp == NULL) return TRUE;
940   sfp = (SeqFeatPtr) gcp->thisitem;
941   return RetranslateOneCDS (sfp, gcp->entityID, rdp->include_stop,
942                             rdp->no_stop_at_end_of_complete_cds);
943 }
944 
945 extern void RetranslateCdRegionsEx (
946   Uint2   entityID,
947   Boolean include_stop,
948   Boolean no_stop_at_end_of_complete_cds )
949 
950 {
951   GatherScope  gs;
952   RecompData   rd;
953   SeqEntryPtr  sep;
954 
955   sep = GetTopSeqEntryForEntityID (entityID);
956   if (sep == NULL) return;
957   WatchCursor ();
958   Update ();
959   rd.count = 0;
960   rd.mon = MonitorStrNewEx ("Correcting Coding Regions", 20, FALSE);
961   rd.include_stop = include_stop;
962   rd.no_stop_at_end_of_complete_cds = no_stop_at_end_of_complete_cds;
963   MemSet ((Pointer) (&gs), 0, sizeof (GatherScope));
964   gs.seglevels = 1;
965   gs.get_feats_location = FALSE;
966   MemSet((Pointer)(gs.ignore), (int)(TRUE), (size_t)(OBJ_MAX * sizeof(Boolean)));
967   gs.ignore[OBJ_BIOSEQ] = FALSE;
968   gs.ignore[OBJ_BIOSEQ_SEG] = FALSE;
969   gs.ignore[OBJ_SEQFEAT] = FALSE;
970   gs.ignore[OBJ_SEQANNOT] = FALSE;
971   GatherEntity (entityID, (Pointer) (&rd), RetranslateCDSCallback, &gs);
972   MonitorFree (rd.mon);
973   ArrowCursor ();
974   Update ();
975   ObjMgrSetDirtyFlag (entityID, TRUE);
976   ObjMgrSendMsg (OM_MSG_UPDATE, entityID, 0, 0);
977 }
978 
979 static void RetranslateCdRegions (
980   IteM i,
981   Boolean include_stop,
982   Boolean no_stop_at_end_of_complete_cds )
983 
984 {
985   BaseFormPtr  bfp;
986 
987 #ifdef WIN_MAC
988   bfp = currentFormDataPtr;
989 #else
990   bfp = GetObjectExtra (i);
991 #endif
992   if (bfp == NULL) return;
993   RetranslateCdRegionsEx (bfp->input_entityID, include_stop, no_stop_at_end_of_complete_cds);
994 }
995 
996 extern void RetranslateCdRegionsNoStop (IteM i)
997 
998 {
999   RetranslateCdRegions (i, FALSE, FALSE);
1000 }
1001 
1002 extern void RetranslateCdRegionsDoStop (IteM i)
1003 
1004 {
1005   RetranslateCdRegions (i, TRUE, FALSE);
1006 }
1007 
1008 extern void RetranslateCdRegionsNoStopExceptEndCompleteCDS (IteM i)
1009 {
1010   RetranslateCdRegions (i, TRUE, TRUE);
1011 }
1012 
1013 
1014 static void DoReprocessPeptides (SeqFeatPtr sfp, Pointer userdata)
1015 
1016 {
1017   SeqFeatPtr    bestprot;
1018   ByteStorePtr  bs;
1019   BioseqPtr     bsp;
1020   Char          ch;
1021   MolInfoPtr    mip;
1022   Boolean       partial5;
1023   Boolean       partial3;
1024   CharPtr       prot;
1025   ProtRefPtr    prp;
1026   CharPtr       ptr;
1027   SeqEntryPtr   sep;
1028   SeqIdPtr      sip;
1029   ValNodePtr    vnp;
1030 
1031   if (sfp->data.choice != SEQFEAT_PROT) return;
1032   if (sfp->product == NULL) return;
1033   prp = (ProtRefPtr) sfp->data.value.ptrvalue;
1034   if (prp == NULL) return;
1035   if (prp->processed < 1 || prp->processed > 4) return;
1036   CheckSeqLocForPartial (sfp->location, &partial5, &partial3);
1037   sip = SeqLocId (sfp->product);
1038   if (sip == NULL) return;
1039   bsp = BioseqFind (sip);
1040   if (bsp != NULL && ISA_aa (bsp->mol) && bsp->repr == Seq_repr_raw) {
1041     bestprot = FindBestProtein (sfp->idx.entityID, sfp->product);
1042     prot = GetSequenceByFeature (sfp);
1043     if (prot == NULL) return;
1044     ptr = prot;
1045     ch = *ptr;
1046     while (ch != '\0') {
1047       *ptr = TO_UPPER (ch);
1048       ptr++;
1049       ch = *ptr;
1050     }
1051     bs = BSNew (1000);
1052     if (bs != NULL) {
1053       ptr = prot;
1054       BSWrite (bs, (VoidPtr) ptr, (Int4) StringLen (ptr));
1055     }
1056     bsp->repr = Seq_repr_raw;
1057     bsp->mol = Seq_mol_aa;
1058     bsp->seq_data = SeqDataFree (bsp->seq_data, bsp->seq_data_type);
1059     bsp->seq_data = (SeqDataPtr) bs;
1060     bsp->seq_data_type = Seq_code_ncbieaa;
1061     bsp->length = BSLen (bs);
1062     sep = SeqMgrGetSeqEntryForData (bsp);
1063     if (sep == NULL) return;
1064     if (bestprot != NULL) {
1065       bestprot->location = SeqLocFree (bestprot->location);
1066       bestprot->location = CreateWholeInterval (sep);
1067       SetSeqLocPartial (bestprot->location, partial5, partial3);
1068       bestprot->partial = (partial5 || partial3);
1069     }
1070     vnp = SeqEntryGetSeqDescr (sep, Seq_descr_molinfo, NULL);
1071     if (vnp == NULL) {
1072       vnp = CreateNewDescriptor (sep, Seq_descr_molinfo);
1073       if (vnp != NULL) {
1074         mip = MolInfoNew ();
1075         vnp->data.ptrvalue = (Pointer) mip;
1076         if (mip != NULL) {
1077           mip->biomol = 8;
1078           mip->tech = 13;
1079         }
1080       }
1081     }
1082     if (vnp != NULL) {
1083       mip = (MolInfoPtr) vnp->data.ptrvalue;
1084       if (mip != NULL) {
1085         if (partial5 && partial3) {
1086           mip->completeness = 5;
1087         } else if (partial5) {
1088           mip->completeness = 3;
1089         } else if (partial3) {
1090           mip->completeness = 4;
1091         /*
1092         } else if (partial) {
1093           mip->completeness = 2;
1094         */
1095         } else {
1096           mip->completeness = 0;
1097         }
1098       }
1099     }
1100   }
1101 }
1102 
1103 extern void ReprocessPeptideProducts (IteM i);
1104 extern void ReprocessPeptideProducts (IteM i)
1105 
1106 {
1107   BaseFormPtr  bfp;
1108   SeqEntryPtr  sep;
1109 
1110 #ifdef WIN_MAC
1111   bfp = currentFormDataPtr;
1112 #else
1113   bfp = GetObjectExtra (i);
1114 #endif
1115   if (bfp == NULL) return;
1116   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1117   if (sep == NULL) return;
1118   VisitFeaturesInSep (sep, NULL, DoReprocessPeptides);
1119   Update ();
1120   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1121   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1122 }
1123 
1124 static void DoReprocessMrnas (SeqFeatPtr sfp, Pointer userdata)
1125 
1126 {
1127   ByteStorePtr  bs;
1128   BioseqPtr     bsp;
1129   Char          ch;
1130   MolInfoPtr    mip;
1131   Boolean       partial5;
1132   Boolean       partial3;
1133   CharPtr       prot;
1134   CharPtr       ptr;
1135   RnaRefPtr     rrp;
1136   SeqEntryPtr   sep;
1137   SeqIdPtr      sip;
1138   ValNodePtr    vnp;
1139 
1140   if (sfp->data.choice != SEQFEAT_RNA) return;
1141   if (sfp->product == NULL) return;
1142   rrp = (RnaRefPtr) sfp->data.value.ptrvalue;
1143   if (rrp == NULL) return;
1144   if (rrp->type != 2) return;
1145   CheckSeqLocForPartial (sfp->location, &partial5, &partial3);
1146   sip = SeqLocId (sfp->product);
1147   if (sip == NULL) return;
1148   bsp = BioseqFind (sip);
1149   if (bsp != NULL && ISA_na (bsp->mol) && bsp->repr == Seq_repr_raw) {
1150     prot = GetSequenceByFeature (sfp);
1151     if (prot == NULL) return;
1152     ptr = prot;
1153     ch = *ptr;
1154     while (ch != '\0') {
1155       *ptr = TO_UPPER (ch);
1156       ptr++;
1157       ch = *ptr;
1158     }
1159     bs = BSNew (1000);
1160     if (bs != NULL) {
1161       ptr = prot;
1162       BSWrite (bs, (VoidPtr) ptr, (Int4) StringLen (ptr));
1163     }
1164     bsp->repr = Seq_repr_raw;
1165     bsp->mol = Seq_mol_na;
1166     bsp->seq_data = SeqDataFree (bsp->seq_data, bsp->seq_data_type);
1167     bsp->seq_data = (SeqDataPtr) bs;
1168     bsp->seq_data_type = Seq_code_iupacna;
1169     bsp->length = BSLen (bs);
1170     sep = SeqMgrGetSeqEntryForData (bsp);
1171     if (sep == NULL) return;
1172     vnp = SeqEntryGetSeqDescr (sep, Seq_descr_molinfo, NULL);
1173     if (vnp == NULL) {
1174       vnp = CreateNewDescriptor (sep, Seq_descr_molinfo);
1175       if (vnp != NULL) {
1176         mip = MolInfoNew ();
1177         vnp->data.ptrvalue = (Pointer) mip;
1178         if (mip != NULL) {
1179           mip->biomol = 8;
1180           mip->tech = 13;
1181         }
1182       }
1183     }
1184     if (vnp != NULL) {
1185       mip = (MolInfoPtr) vnp->data.ptrvalue;
1186       if (mip != NULL) {
1187         if (partial5 && partial3) {
1188           mip->completeness = 5;
1189         } else if (partial5) {
1190           mip->completeness = 3;
1191         } else if (partial3) {
1192           mip->completeness = 4;
1193         /*
1194         } else if (partial) {
1195           mip->completeness = 2;
1196         */
1197         } else {
1198           mip->completeness = 0;
1199         }
1200       }
1201     }
1202   }
1203 }
1204 
1205 extern void ReprocessmRNAProducts (IteM i);
1206 extern void ReprocessmRNAProducts (IteM i)
1207 
1208 {
1209   BaseFormPtr  bfp;
1210   SeqEntryPtr  sep;
1211 
1212 #ifdef WIN_MAC
1213   bfp = currentFormDataPtr;
1214 #else
1215   bfp = GetObjectExtra (i);
1216 #endif
1217   if (bfp == NULL) return;
1218   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1219   if (sep == NULL) return;
1220   VisitFeaturesInSep (sep, NULL, DoReprocessMrnas);
1221   Update ();
1222   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1223   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1224 }
1225 
1226 /*
1227  * ApplyCodeBreakToCDS
1228  */
1229  
1230 static Boolean ApplyCodeBreakToCDS (SeqFeatPtr sfp, CharPtr codonStr, Uint1 aaNum)
1231 {
1232   Uint1            aaChar;
1233   SeqLocPtr        aaSlp;
1234   Int4             aaPosition;
1235   SeqPntPtr        aaSpp;
1236   CharPtr          basePtr;
1237   CharPtr          bases;
1238   CodeBreakPtr     cbp;
1239   CdRegionPtr      crp;
1240   Int4             dnaLen;
1241   SeqLocPtr        dnaSlp;
1242   CodeBreakPtr     lastCbp;
1243   SeqCodeTablePtr  sctp;
1244   Int4             total;
1245   Boolean          added_code_breaks = FALSE;
1246   
1247   if (sfp == NULL || codonStr == NULL)
1248   {
1249     return FALSE;
1250   }
1251 
1252   /* Get the nucleotide sequence */
1253 
1254   dnaLen = SeqLocLen (sfp->location);
1255   if (dnaLen < 1)
1256     return FALSE;
1257 
1258   crp = (CdRegionPtr) sfp->data.value.ptrvalue;
1259 
1260   bases = ReadCodingRegionBases (sfp->location, dnaLen, crp->frame, &total);
1261 
1262   /* Search for the selected codon in the */
1263   /* nucleotide sequence.  If found, add  */
1264   /* it as a codebreak.                   */
1265 
1266   basePtr = bases;
1267   aaPosition = 0;
1268   while (basePtr[0] != '\0') {
1269     if (StringNCmp (basePtr, codonStr, 3) == 0) {
1270 
1271       /* Create a new seq point object with the aa location */
1272 
1273       aaSpp = SeqPntNew ();
1274       aaSpp->point  = aaPosition;
1275       aaSpp->strand = Seq_strand_plus;
1276       aaSpp->id = SeqLocId (sfp->product);
1277       aaSpp->fuzz   = NULL;
1278 
1279       /* Make a SeqLoc using the seq point */
1280 
1281       aaSlp = (SeqLocPtr) ValNodeNew (NULL);
1282       aaSlp->choice = SEQLOC_PNT;
1283       aaSlp->data.ptrvalue = (Pointer) aaSpp;
1284 
1285       /* Convert the seqloc to a DNA location */
1286 
1287       dnaSlp = aaLoc_to_dnaLoc (sfp, aaSlp);
1288 
1289       /* Create the code break using the DNA location */
1290 
1291       cbp = CodeBreakNew ();
1292       cbp->loc = dnaSlp;
1293       sctp = SeqCodeTableFind (Seq_code_ncbieaa);
1294       aaChar = (Uint1) GetSymbolForResidue (sctp, aaNum);
1295       cbp->aa.value.intvalue = aaChar;
1296       cbp->aa.choice = 1; /* ncbieaa */
1297 
1298       /* Insert the code break into the CDS's */
1299       /* existing list of code breaks.        */
1300 
1301       lastCbp = crp->code_break;
1302       if (lastCbp == NULL)
1303       {
1304               crp->code_break = cbp;        
1305       }
1306       else 
1307       {
1308         while (lastCbp->next != NULL)
1309         {
1310           lastCbp = lastCbp->next;          
1311         }
1312               lastCbp->next = cbp;
1313               cbp->next = NULL;
1314       }
1315 
1316       added_code_breaks = TRUE;
1317     }
1318     basePtr += 3;
1319     aaPosition++;
1320   }
1321 
1322   return added_code_breaks;
1323 }
1324 
1325 /*---------------------------------------------------------------------*/
1326 /*                                                                     */
1327 /* ApplyCodeBreak_FeatureCallback () -- Called for each CDS feature in */
1328 /*                                      a Bioseq.  Checks for any      */
1329 /*                                      nucleotide triplets that match */
1330 /*                                      the one in the given code      */
1331 /*                                      break and sets a code break    */
1332 /*                                      for each one that is found.    */
1333 /*                                                                     */
1334 /*---------------------------------------------------------------------*/
1335 
1336 static Boolean LIBCALLBACK ApplyCodeBreak_FeatureCallback (SeqFeatPtr sfp,
1337                                         SeqMgrFeatContextPtr fcontext)
1338 {
1339   Uint1            aaNum;
1340   CodeBreakFormPtr cbfp;
1341   Char             codonStr [4];
1342   Int2             i;
1343 
1344   cbfp = (CodeBreakFormPtr) fcontext->userdata;
1345 
1346 
1347   /* Get the selected Amino Acid and codon triplet */
1348 
1349   GetTitle (cbfp->codonText, codonStr, sizeof (codonStr));
1350   for (i = 0; i < 3; i++)
1351     codonStr [i] = TO_UPPER (codonStr [i]);
1352 
1353   aaNum = (Uint1) GetValue (cbfp->aminoAcidPopup);
1354   aaNum += 63;
1355 
1356   /*
1357   if (aaNum >= 74)
1358   {
1359         aaNum++;
1360   }
1361   if (aaNum >= 79)
1362   {
1363         aaNum++;
1364   }
1365   */
1366 
1367   if (ApplyCodeBreakToCDS (sfp, codonStr, aaNum))
1368   {
1369     /* Retranslate the CDS */
1370 
1371     RetranslateOneCDS (sfp, fcontext->entityID, TRUE, FALSE);
1372     
1373   }
1374   
1375   /* Return TRUE to continue on to the next CDS feature */
1376 
1377   return TRUE;
1378 }
1379 
1380 /*---------------------------------------------------------------------*/
1381 /*                                                                     */
1382 /* ApplyCodeBreak_BioseqCallback () -- Called by SeqMgrExploreBioseqs  */
1383 /*                                     for each Bioseq.  Searches the  */
1384 /*                                     Bioseq for CDS features and adds*/
1385 /*                                     the given code break to any     */
1386 /*                                     found.                          */
1387 /*                                                                     */
1388 /*---------------------------------------------------------------------*/
1389 
1390 static Boolean LIBCALLBACK ApplyCodeBreak_BioseqCallback (BioseqPtr bsp,
1391                                          SeqMgrBioseqContextPtr bcontext)
1392 {
1393   Boolean featureFilterArray [SEQFEAT_MAX];
1394 
1395   /* Set up to explore only CDS features */
1396 
1397   MemSet ((Pointer) (featureFilterArray),
1398           (int) FALSE,
1399           SEQFEAT_MAX);
1400 
1401   featureFilterArray[SEQFEAT_CDREGION] = TRUE;
1402 
1403   /* Explore the Bioseq's CDS features, marking the */
1404   /* ones with internal stop codons as pseudo.      */
1405 
1406   SeqMgrExploreFeatures (bsp, bcontext->userdata,
1407                          ApplyCodeBreak_FeatureCallback, NULL,
1408                          featureFilterArray, NULL);
1409 
1410   /* Return TRUE to continue on to the next Bioseq */
1411 
1412   return TRUE;
1413 }
1414 
1415 /*---------------------------------------------------------------------*/
1416 /*                                                                     */
1417 /* DoAddCodeBreak_Callback () -- Called when the 'Apply' button is     */
1418 /*                               pressed in the "Add Code Break"       */
1419 /*                               window.  Adds the entered code break  */
1420 /*                               to all CDS features.                  */
1421 /*                                                                     */
1422 /*---------------------------------------------------------------------*/
1423 
1424 static void DoAddCodeBreak_Callback (ButtoN b)
1425 {
1426   CodeBreakFormPtr  cbfp;
1427 
1428   cbfp = (CodeBreakFormPtr) GetObjectExtra (b);
1429 
1430   /* Change to the "working" cursor */
1431 
1432   Hide (cbfp->form);
1433   WatchCursor ();
1434   Update ();
1435 
1436   /* Visit all the Bioseqs, where we will */
1437   /* then explore their CDS features.     */
1438 
1439   SeqMgrExploreBioseqs (cbfp->input_entityID, NULL, (Pointer) cbfp,
1440                         ApplyCodeBreak_BioseqCallback, TRUE, FALSE, TRUE);
1441 
1442   /* Restore the cursor and force an update */
1443 
1444   ArrowCursor ();
1445   Update ();
1446   ObjMgrSetDirtyFlag (cbfp->input_entityID, TRUE);
1447   ObjMgrSendMsg (OM_MSG_UPDATE, cbfp->input_entityID, 0, 0);
1448   Remove (cbfp->form);
1449 }
1450 
1451 /*---------------------------------------------------------------------*/
1452 /*                                                                     */
1453 /* PopulateAAPopup () -- Creates a popup list of amino acids.          */
1454 /*                                                                     */
1455 /*     NOTE : This function is identical to (and identically named as) */
1456 /*            a function in cdrgn.c                                    */
1457 /*                                                                     */
1458 /*---------------------------------------------------------------------*/
1459 
1460 static void PopulateAAPopup (PopuP AAitem)
1461 
1462 {
1463   Char             ch;
1464   Uint1            first;
1465   Uint1            i;
1466   Char             item [77];
1467   Uint1            last;
1468   SeqCodeTablePtr  sctp;
1469   CharPtr          str;
1470 
1471   sctp = SeqCodeTableFind (Seq_code_ncbieaa);
1472   first = FirstResidueInCode (sctp);
1473   last = LastResidueInCode (sctp);
1474   PopupItem (AAitem, " ");
1475   for (i = 65; i <= last; i++) {
1476     /*
1477     if (i == 74 || i == 79) {
1478       continue;
1479     }
1480     */
1481     ch = GetSymbolForResidue (sctp, i);
1482     str = (CharPtr) GetNameForResidue (sctp, i);
1483     sprintf (item, "%c    %s", ch, str);
1484     PopupItem (AAitem, item);
1485   } 
1486   SetValue (AAitem, 1); 
1487 }
1488 
1489 /*---------------------------------------------------------------------*/
1490 /*                                                                     */
1491 /* IsLegalCodon () - Determines if a three base string is a legal      */
1492 /*                   codon.                                            */
1493 /*                                                                     */
1494 /*---------------------------------------------------------------------*/
1495 
1496 static Boolean IsLegalCodon (CharPtr codonStr)
1497 {
1498   Int2 i;
1499   Char baseChar;
1500 
1501   /* Only allow three characters */
1502 
1503   if (StringLen (codonStr) > 3)
1504     return FALSE;
1505 
1506   /* Allow only the character A,C,G,T,U and */
1507   /* convert the U to a T.                  */
1508 
1509   i = 0;
1510   while (i < 3) {
1511 
1512     if (codonStr [i] == '\0')
1513       break;
1514 
1515     baseChar = codonStr [i];
1516     
1517     if (StringChr ("acgtuACGTU", baseChar) == NULL)
1518       return FALSE;
1519     if ('U' == baseChar)
1520       codonStr [i] = 'T';
1521     else if ('u' == baseChar)
1522       codonStr [i] = 't';
1523     
1524     i++;
1525   }
1526 
1527   /* If we made it this far, it's a valid codon */
1528 
1529   return TRUE;
1530 }
1531 
1532 /*---------------------------------------------------------------------*/
1533 /*                                                                     */
1534 /* CodonText_Callback () -- Called whenever a keystoke is entered in   */
1535 /*                          Codon text field.  Validates to see if the */
1536 /*                          keystroke should be allowed.               */
1537 /*                                                                     */
1538 /*---------------------------------------------------------------------*/
1539 
1540 static void CodonText_Callback (TexT codonText)
1541 
1542 {
1543   CodeBreakFormPtr  cbfp;
1544   Int2              aaNum;
1545   Char              newCodonStr [5];
1546 
1547   /* Get the currect code break data */
1548 
1549   cbfp = (CodeBreakFormPtr) GetObjectExtra (codonText);
1550   if (cbfp == NULL)
1551     return;
1552 
1553   /* If the new codon string is not legal */
1554   /* then reset to the previous text.     */
1555 
1556   GetTitle (codonText, newCodonStr, sizeof (newCodonStr));
1557 
1558   if (!IsLegalCodon (newCodonStr))
1559     StringCpy (newCodonStr, cbfp->currentCodonStr);
1560   else
1561     StringCpy (cbfp->currentCodonStr, newCodonStr);
1562 
1563   SafeSetTitle (cbfp->codonText, newCodonStr);
1564 
1565   /* Only enable the accept button if */
1566   /* we have a full codon.            */
1567 
1568   if (StringLen (newCodonStr) != 3) {
1569     SafeDisable (cbfp->acceptButton);
1570     return;
1571   }
1572 
1573   /* See if an amino acid has been selected yet */
1574 
1575   aaNum = GetValue (cbfp->aminoAcidPopup);
1576   if (aaNum <= 1) {
1577     SafeDisable (cbfp->acceptButton);
1578     return;
1579   }
1580 
1581   /* If we made it this far then we have both a codon and */
1582   /* an amino acid, so enable the accept button.          */
1583  
1584   SafeEnable (cbfp->acceptButton);
1585 }
1586 
1587 /*---------------------------------------------------------------------*/
1588 /*                                                                     */
1589 /* SelectAminoAcid_Callback () -- Called whenever a new amino acid is  */
1590 /*                                selected in the Amino Acid Popup.    */
1591 /*                                Toggles 'Accept' button base on      */
1592 /*                                current state.                       */
1593 /*                                                                     */
1594 /*---------------------------------------------------------------------*/
1595 
1596 static void SelectAminoAcid_Callback (PopuP p)
1597 {
1598   CodeBreakFormPtr  cbfp;
1599   Char              codonStr [4];
1600   Int2              aaNum;
1601 
1602   /* Get the currect code break data */
1603 
1604   cbfp = (CodeBreakFormPtr) GetObjectExtra (p);
1605   if (cbfp == NULL)
1606     return;
1607 
1608   /* Only enable the accept button if */
1609   /* we have a full codon.            */
1610 
1611   GetTitle (cbfp->codonText, codonStr, sizeof (codonStr));
1612   if (StringLen (codonStr) != 3) {
1613     SafeDisable (cbfp->acceptButton);
1614     return;
1615   }
1616 
1617   /* Get the newly selected amino acid */
1618 
1619   aaNum = GetValue (cbfp->aminoAcidPopup);
1620 
1621   /* If an amino acid is selected then */
1622   /* enable the accept button.         */
1623 
1624   if (aaNum > 1)
1625     SafeEnable (cbfp->acceptButton);
1626   else
1627     SafeDisable (cbfp->acceptButton);
1628 }
1629 
1630 /*---------------------------------------------------------------------*/
1631 /*                                                                     */
1632 /* AddGlobalCodeBreak () -- Gets a nucleotide triplet and an amino     */
1633 /*                          acid from the user and adds them as        */
1634 /*                          codebreaks for all CDS features.           */
1635 /*                                                                     */
1636 /*---------------------------------------------------------------------*/
1637 
1638 extern void AddGlobalCodeBreak (IteM i);
1639 extern void AddGlobalCodeBreak (IteM i)
1640 
1641 {
1642   BaseFormPtr      bfp;
1643   WindoW           breakWin;
1644   GrouP            mainGroup;
1645   GrouP            buttGroup;
1646   CodeBreakFormPtr cbfp;
1647 
1648   /* Get the current state of things */
1649 
1650 #ifdef WIN_MAC
1651   bfp = currentFormDataPtr;
1652 #else
1653   bfp = GetObjectExtra (i);
1654 #endif
1655   if (bfp == NULL)
1656     return;
1657 
1658   cbfp = (CodeBreakFormPtr) MemNew (sizeof (EvidenceFormData));
1659 
1660   /* Create a window to get the codon and */
1661   /* the Amino acid from the user.        */
1662 
1663   breakWin = FixedWindow (-50, -33, -10, -10,
1664                           "Add Code Break", StdCloseWindowProc);
1665   SetObjectExtra (breakWin, cbfp, StdCleanupFormProc);
1666   cbfp->form = (ForM) breakWin;
1667   cbfp->formmessage = NULL;
1668   cbfp->input_entityID = bfp->input_entityID;
1669 
1670   mainGroup = HiddenGroup (breakWin, -2, 0, NULL);
1671 
1672   /* Create a text entry box for the nucl. codon */
1673 
1674   StaticPrompt (mainGroup, "Triplet Codon", 0, popupMenuHeight,
1675                 programFont, 'l');
1676   cbfp->codonText = DialogText (mainGroup, "", 3, CodonText_Callback);
1677   SetObjectExtra (cbfp->codonText, cbfp, NULL);
1678   cbfp->currentCodonStr [0] = '\0';
1679 
1680   /* Add a Popup list of Amino Acids */
1681 
1682   StaticPrompt (mainGroup, "Amino Acid", 0, popupMenuHeight,
1683                 programFont, 'l');
1684   cbfp->aminoAcidPopup = PopupList (mainGroup, TRUE,
1685                                     SelectAminoAcid_Callback);
1686   PopulateAAPopup (cbfp->aminoAcidPopup);
1687   SetObjectExtra (cbfp->aminoAcidPopup, cbfp, NULL);
1688 
1689   /* Add Accept and Cancel buttons */
1690 
1691   buttGroup = HiddenGroup (breakWin, 2, 0, NULL);
1692   cbfp->acceptButton = DefaultButton (buttGroup, "Accept",
1693                                    DoAddCodeBreak_Callback);
1694   SetObjectExtra (cbfp->acceptButton, cbfp, NULL);
1695   SafeDisable (cbfp->acceptButton);
1696   PushButton (buttGroup, "Cancel", StdCancelButtonProc);
1697 
1698   /* Line things up and display the window */
1699 
1700   AlignObjects (ALIGN_CENTER, (HANDLE) mainGroup, (HANDLE) buttGroup, NULL);
1701   RealizeWindow (breakWin);
1702   Show (breakWin);
1703   Update ();
1704 
1705 }
1706 
1707 static void ParseCodonQualToCodeBreakCallback (SeqFeatPtr sfp, Pointer userdata)
1708 {
1709   SeqCodeTablePtr sctp;
1710   GBQualPtr       gqual, prev_qual = NULL, next_qual;
1711   CharPtr         cp;
1712   Char            codon_text[4];
1713   Char            symbol_text [4];
1714   Uint1           aaNum;
1715   Int4            i;
1716   Boolean         converted_qual;
1717   
1718   if (sfp == NULL || sfp->data.choice != SEQFEAT_CDREGION || userdata == NULL)
1719   {
1720     return;
1721   }
1722   
1723   sctp = (SeqCodeTablePtr) userdata;
1724   
1725   for (gqual = sfp->qual; gqual != NULL; gqual = next_qual)
1726   {
1727     next_qual = gqual->next;
1728     converted_qual = FALSE;
1729     if (StringCmp (gqual->qual, "codon") == 0)
1730     {
1731       cp = StringSearch (gqual->val, "seq:\"");
1732       if (cp != NULL)
1733       {
1734         cp += 5;
1735         StringNCpy (codon_text, cp, 3);
1736         codon_text [3] = 0;
1737         for (i = 0; i < 3; i++)
1738           codon_text [i] = TO_UPPER (codon_text [i]);
1739 
1740         cp = StrChr (cp, ':');
1741         if (cp != NULL)
1742         {
1743           cp++;
1744           StringNCpy (symbol_text, cp, 3);
1745           symbol_text [3] = 0;
1746           aaNum = FindResidueByName (symbol_text, sctp);         
1747           if (ApplyCodeBreakToCDS (sfp, codon_text, aaNum))
1748           {
1749             /* Retranslate the CDS */
1750 
1751             RetranslateOneCDS (sfp, sfp->idx.entityID, TRUE, FALSE);
1752             
1753             /* remove the codon qual */
1754             if (prev_qual == NULL)
1755             {
1756               sfp->qual = gqual->next;
1757             }
1758             else
1759             {
1760               prev_qual->next = gqual->next;
1761             }
1762             gqual->next = NULL;
1763             GBQualFree (gqual);
1764             converted_qual = TRUE;
1765           }
1766         }
1767       }
1768     }
1769     if (!converted_qual)
1770     {
1771       prev_qual = gqual;
1772     }
1773   }
1774 }
1775 
1776 extern void ParseCodonQualToCodeBreak (IteM i)
1777 {
1778   BaseFormPtr      bfp;
1779   SeqEntryPtr      sep;
1780   SeqCodeTablePtr  sctp;
1781   
1782 #ifdef WIN_MAC
1783   bfp = currentFormDataPtr;
1784 #else
1785   bfp = GetObjectExtra (i);
1786 #endif
1787   if (bfp == NULL) return;
1788 
1789   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1790   if (sep == NULL) return;
1791   
1792   WatchCursor ();
1793   Update ();
1794   
1795   sctp = SeqCodeTableFind (Seq_code_ncbieaa);
1796   
1797   VisitFeaturesInSep (sep, sctp, ParseCodonQualToCodeBreakCallback);
1798   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1799   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1800   ArrowCursor ();
1801   Update ();
1802 }
1803 
1804 static void CorrectGenCodeIndexedCallback (SeqFeatPtr sfp, Pointer userdata)
1805 {
1806   CdRegionPtr     crp;
1807   GeneticCodePtr  gc;
1808   Int2Ptr         pGenCode;
1809   ValNodePtr      vnp;
1810   Boolean         need_replacement = FALSE;
1811 
1812   if (sfp == NULL || sfp->data.choice != SEQFEAT_CDREGION 
1813       || sfp->data.value.ptrvalue == NULL
1814       || userdata == NULL) return;
1815  
1816   pGenCode = (Int2Ptr) userdata;
1817   crp = (CdRegionPtr) sfp->data.value.ptrvalue;
1818   if (crp->genetic_code != NULL
1819       && crp->genetic_code->choice == 254) {
1820     if (crp->genetic_code->data.ptrvalue == NULL) {
1821       vnp = ValNodeNew (NULL);
1822       vnp->choice = 2;
1823       vnp->data.intvalue = (Int4) *pGenCode;
1824     } else {
1825       vnp = crp->genetic_code->data.ptrvalue;
1826       if (vnp->next == NULL && vnp->choice == 2) {
1827         vnp->data.intvalue = (Int4) *pGenCode;
1828       } else {
1829         need_replacement = TRUE;
1830       }
1831     }
1832   } else {
1833     need_replacement = TRUE;
1834   }
1835   if (need_replacement) {
1836     gc = GeneticCodeNew ();
1837     if (gc == NULL) return;
1838     crp->genetic_code = GeneticCodeFree (crp->genetic_code);
1839     vnp = ValNodeNew (NULL);
1840     gc->data.ptrvalue = vnp;
1841     if (vnp != NULL) {
1842       vnp->choice = 2;
1843       vnp->data.intvalue = (Int4) *pGenCode;
1844     }
1845     crp->genetic_code = gc;
1846   }
1847 }
1848 
1849 static void CorrectGenCodesBioseqCallback (BioseqPtr bsp, Pointer userdata)
1850 {
1851   SeqMgrFeatContext fcontext;
1852   SeqFeatPtr        sfp;
1853 
1854   if (bsp == NULL || userdata == NULL) return;
1855   for (sfp = SeqMgrGetNextFeature (bsp, NULL, SEQFEAT_CDREGION, FEATDEF_CDS, &fcontext);
1856        sfp != NULL;
1857        sfp = SeqMgrGetNextFeature (bsp, sfp, SEQFEAT_CDREGION, FEATDEF_CDS, &fcontext)) {
1858     CorrectGenCodeIndexedCallback (sfp, userdata);
1859   }
1860 
1861 }
1862 
1863 typedef struct gencodescan {
1864   Boolean mito;
1865   Boolean plastid;
1866   Int2    nuclCode;
1867   Int2    mitoCode;
1868   Boolean already_found;
1869 } GenCodeScanData, PNTR GenCodeScanPtr;
1870 
1871 static void JustGetGenCodeFromOrgRef (OrgRefPtr orp, GenCodeScanPtr gp)
1872 {
1873   if (orp == NULL || orp->orgname == NULL || gp == NULL || gp->already_found) return;
1874 
1875   gp->nuclCode = orp->orgname->gcode;
1876   gp->mitoCode = orp->orgname->mgcode;
1877 }
1878 
1879 static void JustGetGenCodeFromBiop (BioSourcePtr biop, GenCodeScanPtr gp)
1880 {
1881   if (biop == NULL || gp == NULL) return;
1882   if (gp->already_found && !biop->is_focus) return;
1883 
1884   gp->mito = (Boolean) (biop->genome == GENOME_kinetoplast ||
1885                         biop->genome == GENOME_mitochondrion ||
1886                         biop->genome == GENOME_hydrogenosome);
1887 
1888   gp->plastid = (Boolean) (biop->genome == GENOME_chloroplast ||
1889                                 biop->genome == GENOME_chromoplast ||
1890                                 biop->genome == GENOME_plastid ||
1891                                 biop->genome == GENOME_cyanelle ||
1892                                 biop->genome == GENOME_apicoplast ||
1893                                 biop->genome == GENOME_leucoplast ||
1894                                 biop->genome == GENOME_proplastid);
1895 
1896   JustGetGenCodeFromOrgRef (biop->org, gp);
1897   gp->already_found = TRUE;
1898 }
1899 
1900 
1901 static void JustGetGenCodeFromFeat (SeqFeatPtr sfp, Pointer userdata) 
1902 {
1903   GenCodeScanPtr gp;
1904 
1905   if (sfp == NULL || userdata == NULL || sfp->data.choice != SEQFEAT_BIOSRC) return;
1906 
1907   gp = (GenCodeScanPtr) userdata;
1908 
1909   JustGetGenCodeFromBiop (sfp->data.value.ptrvalue, gp);
1910 }
1911 
1912 static void JustGetGenCodeFromDesc (SeqDescrPtr sdp, Pointer userdata)
1913 {
1914   GenCodeScanPtr gp;
1915 
1916   if (sdp == NULL || userdata == NULL || sdp->choice != Seq_descr_source) return;
1917 
1918   gp = (GenCodeScanPtr) userdata;
1919 
1920   JustGetGenCodeFromBiop (sdp->data.ptrvalue, gp);
1921 }
1922 
1923 static Int2 JustGetGenCodeForSeqEntry (SeqEntryPtr sep) 
1924 {
1925   GenCodeScanData gd;
1926 
1927   gd.already_found = FALSE;
1928   gd.mito = FALSE;
1929   gd.mitoCode = 0;
1930   gd.nuclCode = 0;
1931   gd.plastid = FALSE;
1932 
1933   VisitDescriptorsInSep (sep, &gd, JustGetGenCodeFromDesc);
1934   VisitFeaturesInSep (sep, &gd, JustGetGenCodeFromFeat);
1935 
1936   if (gd.plastid) {
1937     return 11;
1938   } else if (gd.mito) {
1939     return gd.mitoCode;
1940   } else {
1941     return gd.nuclCode;
1942   }
1943 }
1944 
1945 
1946 extern void CorrectGenCodes (SeqEntryPtr sep, Uint2 entityID)
1947 
1948 {
1949   BioseqSetPtr  bssp;
1950   Int2          genCode;
1951 
1952   if (sep == NULL) return;
1953   if (IS_Bioseq_set (sep)) {
1954     bssp = (BioseqSetPtr) sep->data.ptrvalue;
1955     if (bssp != NULL && (bssp->_class == 7 ||
1956                          (IsPopPhyEtcSet (bssp->_class)))) {
1957       for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
1958         CorrectGenCodes (sep, entityID);
1959       }
1960       return;
1961     }
1962   }
1963 
1964   genCode = JustGetGenCodeForSeqEntry(sep);
1965   VisitFeaturesInSep (sep, &genCode, CorrectGenCodeIndexedCallback);
1966   VisitBioseqsInSep (sep, &genCode, CorrectGenCodesBioseqCallback);
1967 }
1968 
1969 extern void CorrectCDSGenCodes (IteM i)
1970 
1971 {
1972   BaseFormPtr  bfp;
1973   SeqEntryPtr  sep;
1974 
1975 #ifdef WIN_MAC
1976   bfp = currentFormDataPtr;
1977 #else
1978   bfp = GetObjectExtra (i);
1979 #endif
1980   if (bfp == NULL) return;
1981   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
1982   if (sep == NULL) return;
1983   CorrectGenCodes (sep, bfp->input_entityID);
1984   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
1985   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
1986 }
1987 
1988 static BioseqPtr SqnGetBioseqGivenSeqLoc (SeqLocPtr slp, Uint2 entityID)
1989 
1990 {
1991   BioseqPtr    bsp;
1992   SeqEntryPtr  sep;
1993   SeqIdPtr     sip;
1994   SeqLocPtr    tmp;
1995 
1996   if (slp == NULL) return NULL;
1997   bsp = NULL;
1998   sip = SeqLocId (slp);
1999   if (sip != NULL) {
2000     bsp = BioseqFind (sip);
2001   } else {
2002     tmp = SeqLocFindNext (slp, NULL);
2003     if (tmp != NULL) {
2004       sip = SeqLocId (tmp);
2005       if (sip != NULL) {
2006         bsp = BioseqFind (sip);
2007         if (bsp != NULL) {
2008           sep = SeqMgrGetSeqEntryForData (bsp);
2009           entityID = ObjMgrGetEntityIDForChoice (sep);
2010           bsp = GetBioseqGivenSeqLoc (slp, entityID);
2011         }
2012       }
2013     }
2014   }
2015   return bsp;
2016 }
2017 
2018 static BioseqPtr GetBioseqReferencedByAnnot (SeqAnnotPtr sap, Uint2 entityID)
2019 
2020 {
2021   SeqAlignPtr   align;
2022   BioseqPtr     bsp;
2023   DenseDiagPtr  ddp;
2024   DenseSegPtr   dsp;
2025   SeqFeatPtr    feat;
2026   SeqGraphPtr   graph;
2027   SeqIdPtr      sip;
2028   SeqLocPtr     slp;
2029   StdSegPtr     ssp;
2030   SeqLocPtr     tloc;
2031 
2032   if (sap == NULL) return NULL;
2033   switch (sap->type) {
2034     case 1 :
2035       feat = (SeqFeatPtr) sap->data;
2036       while (feat != NULL) {
2037         slp = feat->location;
2038         if (slp != NULL) {
2039           bsp = SqnGetBioseqGivenSeqLoc (slp, entityID);
2040           if (bsp != NULL) return bsp;
2041         }
2042         feat = feat->next;
2043       }
2044       break;
2045     case 2 :
2046       align = (SeqAlignPtr) sap->data;
2047       while (align != NULL) {
2048         if (align->segtype == 1) {
2049           ddp = (DenseDiagPtr) align->segs;
2050           if (ddp != NULL) {
2051             for (sip = ddp->id; sip != NULL; sip = sip->next) {
2052               bsp = BioseqFind (sip);
2053               if (bsp != NULL) return bsp;
2054             }
2055           }
2056         } else if (align->segtype == 2) {
2057           dsp = (DenseSegPtr) align->segs;
2058           if (dsp != NULL) {
2059             for (sip = dsp->ids; sip != NULL; sip = sip->next) {
2060               bsp = BioseqFind (sip);
2061               if (bsp != NULL) return bsp;
2062             }
2063           }
2064         } else if (align->segtype == 3) {
2065           ssp = (StdSegPtr) align->segs;
2066           if (ssp != NULL && ssp->loc != NULL) {
2067             for (tloc = ssp->loc; tloc != NULL; tloc = tloc->next) {
2068               bsp = BioseqFind (SeqLocId (tloc));
2069               if (bsp != NULL) return bsp;
2070             }
2071           }
2072         }
2073         align = align->next;
2074       }
2075       break;
2076     case 3 :
2077       graph = (SeqGraphPtr) sap->data;
2078       while (graph != NULL) {
2079         slp = graph->loc;
2080         if (slp != NULL) {
2081           bsp = SqnGetBioseqGivenSeqLoc (slp, entityID);
2082           if (bsp != NULL) return bsp;
2083         }
2084         graph = graph->next;
2085       }
2086       break;
2087     default :
2088       break;
2089   }
2090   return NULL;
2091 }
2092 
2093 static Int4 GetScore (ScorePtr score)
2094 
2095 {
2096   ObjectIdPtr  id;
2097 
2098   while (score != NULL) {
2099     id = score->id;
2100     if (id != NULL) {
2101       if (StringICmp (id->str, "score") == 0) {
2102         if (score->choice == 1) {
2103           return (score->value.intvalue);
2104         }
2105       }
2106     }
2107     score = score->next;
2108   }
2109   return 0;
2110 }
2111 
2112 static Int4 FindScore (SeqAlignPtr align)
2113 
2114 {
2115   if (align == NULL) return 0;
2116   if (align->score != NULL) {
2117     return GetScore (align->score);
2118   }
2119   return 0;
2120 }
2121 
2122 static int LIBCALLBACK SortByScoreCallback (VoidPtr ptr1, VoidPtr ptr2)
2123 
2124 {
2125   SeqAlignPtr   sap1;
2126   SeqAlignPtr   sap2;
2127   Int4          score1;
2128   Int4          score2;
2129 
2130   if (ptr1 != NULL && ptr2 != NULL) {
2131     sap1 = *((SeqAlignPtr PNTR) ptr1);
2132     sap2 = *((SeqAlignPtr PNTR) ptr2);
2133     if (sap1 != NULL && sap2 != NULL) {
2134       score1 = FindScore (sap1);
2135       score2 = FindScore (sap2);
2136       if (score1 < score2) {
2137         return 1;
2138       } else if (score1 > score2) {
2139         return -1;
2140       } else {
2141         return 0;
2142       }
2143     } else {
2144       return 0;
2145     }
2146   } else {
2147     return 0;
2148   }
2149 }
2150 
2151 static SeqAlignPtr SortBySeqAlignScore (SeqAlignPtr list)
2152 
2153 {
2154   SeqAlignPtr  align;
2155   Int4         count, i;
2156   SeqAlignPtr  PNTR head;
2157 
2158   if (list == NULL) return 0;
2159   count = 0;
2160   for (align = list; align != NULL; align = align->next) {
2161     count++;
2162   }
2163   head = MemNew (sizeof (SeqAlignPtr) * (size_t) (count + 1));
2164   if (head == NULL) return 0;
2165   for (align = list, i = 0; align != NULL && i < count; i++) {
2166     head [i] = align;
2167     align = align->next;
2168   }
2169   HeapSort (head, (size_t) count, sizeof (SeqAlignPtr), SortByScoreCallback);
2170   for (i = 0; i < count; i++) {
2171     align = head [i];
2172     align->next = head [i + 1];
2173   }
2174   list = head [0];
2175   MemFree (head);
2176   return list;
2177 }
2178 
2179 static void TakeTop10Alignments (SeqAnnotPtr sap)
2180 
2181 {
2182   SeqAlignPtr  align;
2183   MsgAnswer    ans;
2184   Int2         count;
2185   SeqAlignPtr  next;
2186 
2187   if (sap == NULL || sap->type != 2 || sap->data == NULL) return;
2188   count = 0;
2189   for (align = (SeqAlignPtr) sap->data; align != NULL; align = align->next) {
2190     count++;
2191   }
2192   if (count <= 10) return;
2193   ans = Message (MSG_YN, "Do you want to take only the top 10 (out of %d) alignments?", (int) count);
2194   if (ans == ANS_NO) return;
2195   sap->data = SortBySeqAlignScore ((SeqAlignPtr) sap->data);
2196   for (align = (SeqAlignPtr) sap->data, count = 0; align != NULL && count < 10; align = align->next) {
2197     count++;
2198   }
2199   next = align->next;
2200   align->next = NULL;
2201   align = next;
2202   while (align != NULL) {
2203     next = align->next;
2204     align->next = NULL;
2205     SeqAlignFree (align);
2206     align = next;
2207   }
2208 }
2209 
2210 static void DoOnePub (PubdescPtr pdp)
2211 
2212 {
2213   ValNodePtr    citartptr = NULL;
2214   Int4          muid = 0;
2215   Int4          pmid = 0;
2216   ValNodePtr    tmp = NULL;
2217   ValNodePtr    vnp;
2218 
2219   if (pdp != NULL) {
2220     for (vnp = pdp->pub; vnp != NULL; vnp = vnp->next) {
2221       if (vnp->choice == PUB_Muid) {
2222         muid = vnp->data.intvalue;
2223       } else if (vnp->choice == PUB_PMid) {
2224         pmid = vnp->data.intvalue;
2225       } else if (vnp->choice == PUB_Article) {
2226         citartptr = vnp;
2227       }
2228     }
2229     if (pmid != 0) {
2230       tmp = MedArchGetPubPmId (pmid);
2231       muid = MedArchPm2Mu (pmid);
2232     } else if (muid != 0) {
2233       tmp = MedArchGetPub (muid);
2234       pmid = MedArchMu2Pm (muid);
2235     } else if (citartptr != NULL) {
2236       muid = MedArchCitMatch (citartptr);
2237       if (muid != 0) {
2238         tmp = MedArchGetPub (muid);
2239         pmid = MedArchMu2Pm (muid);
2240       }
2241     }
2242     if (tmp != NULL) {
2243       MedlineToISO (tmp);
2244       if (pmid != 0) {
2245         ValNodeAddInt (&tmp, PUB_PMid, pmid);
2246       }
2247       if (muid != 0) {
2248         ValNodeAddInt (&tmp, PUB_Muid, muid);
2249       }
2250       pdp->pub = PubEquivFree (pdp->pub);
2251       pdp->pub = tmp;
2252     }
2253   }
2254 }
2255 
2256 static void DoLookupPub (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
2257 
2258 {
2259   BioseqPtr     bsp;
2260   BioseqSetPtr  bssp;
2261   PubdescPtr    pdp;
2262   SeqAnnotPtr   sap;
2263   ValNodePtr    sdp;
2264   SeqFeatPtr    sfp;
2265 
2266   if (IS_Bioseq (sep)) {
2267     bsp = (BioseqPtr) sep->data.ptrvalue;
2268     sap = bsp->annot;
2269     sdp = bsp->descr;
2270   } else if (IS_Bioseq_set (sep)) {
2271     bssp = (BioseqSetPtr) sep->data.ptrvalue;
2272     sap = bssp->annot;
2273     sdp = bssp->descr;
2274   } else return;
2275   while (sap != NULL) {
2276     if (sap->type == 1) {
2277       for (sfp = (SeqFeatPtr) sap->data; sfp != NULL; sfp = sfp->next) {
2278         if (sfp->data.choice == SEQFEAT_PUB) {
2279           pdp = (PubdescPtr) sfp->data.value.ptrvalue;
2280           DoOnePub (pdp);
2281         }
2282       }
2283     }
2284     sap = sap->next;
2285   }
2286   while (sdp != NULL) {
2287     if (sdp->choice == Seq_descr_pub) {
2288       pdp = (PubdescPtr) sdp->data.ptrvalue;
2289       DoOnePub (pdp);
2290     }
2291     sdp = sdp->next;
2292   }
2293 }
2294 
2295 extern void LookupAllPubs (IteM i);
2296 extern void LookupAllPubs (IteM i)
2297 
2298 {
2299   BaseFormPtr  bfp;
2300   MonitorPtr   mon = NULL;
2301   SeqEntryPtr  sep;
2302   ErrSev       sev;
2303 
2304 
2305   if (! useMedarch) return;
2306 #ifdef WIN_MAC
2307   bfp = currentFormDataPtr;
2308 #else
2309   bfp = GetObjectExtra (i);
2310 #endif
2311   if (bfp == NULL) return;
2312   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
2313   if (sep == NULL) return;
2314   sev = ErrSetMessageLevel (SEV_FATAL);
2315   WatchCursor ();
2316   mon = MonitorStrNewEx ("Processing Publications", 40, FALSE);
2317   MonitorStrValue (mon, "Connecting to MedArch");
2318   Update ();
2319   if (! MedArchInit ()) {
2320     MonitorFree (mon);
2321     ArrowCursor ();
2322     Update ();
2323     Message (MSG_POST, "Unable to connect to MedArch");
2324     return;
2325   }
2326   SeqEntryExplore (sep, NULL, DoLookupPub);
2327   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
2328   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
2329   MonitorStrValue (mon, "Closing MedArch");
2330   Update ();
2331   MedArchFini ();
2332   MonitorFree (mon);
2333   ArrowCursor ();
2334   Update ();
2335   ErrSetMessageLevel (sev);
2336   ErrClear ();
2337   ErrShow ();
2338 }
2339 
2340 static void LookupPublications (SeqAnnotPtr sap)
2341 
2342 {
2343   MonitorPtr  mon = NULL;
2344   PubdescPtr  pdp;
2345   SeqFeatPtr  sfp;
2346   ValNodePtr  tmp;
2347   Int4        uid;
2348   Boolean     usingMedarch = FALSE;
2349   ValNodePtr  vnp;
2350 
2351   if (! useMedarch) return;
2352   if (sap == NULL || sap->type != 1) return;
2353   for (sfp = (SeqFeatPtr) sap->data; sfp != NULL; sfp = sfp->next) {
2354     if (sfp->data.choice == SEQFEAT_PUB) {
2355       pdp = (PubdescPtr) sfp->data.value.ptrvalue;
2356       if (pdp != NULL) {
2357         vnp = pdp->pub;
2358         if (vnp != NULL && vnp->next == NULL) {
2359           if (vnp->choice == PUB_Muid || vnp->choice == PUB_PMid) {
2360             if (! usingMedarch) {
2361               WatchCursor ();
2362               mon = MonitorStrNewEx ("Processing Publications", 40, FALSE);
2363               MonitorStrValue (mon, "Connecting to MedArch");
2364               Update ();
2365               if (MedArchInit ()) {
2366                 usingMedarch = TRUE;
2367               } else {
2368                 MonitorFree (mon);
2369                 ArrowCursor ();
2370                 Update ();
2371                 Message (MSG_POST, "Unable to connect to MedArch");
2372                 return;
2373               }
2374             }
2375           }
2376           tmp = NULL;
2377           if (vnp->choice == PUB_Muid) {
2378             uid = vnp->data.intvalue;
2379             tmp = MedArchGetPub (uid);
2380           } else if (vnp->choice == PUB_PMid) {
2381             uid = vnp->data.intvalue;
2382             tmp = MedArchGetPubPmId (uid);
2383           }
2384           if (tmp != NULL) {
2385             MedlineToISO (tmp);
2386             tmp->next = vnp;
2387             pdp->pub = tmp;
2388           }
2389         }
2390       }
2391     }
2392   }
2393   if (usingMedarch) {
2394     MonitorStrValue (mon, "Closing MedArch");
2395     Update ();
2396     MedArchFini ();
2397     MonitorFree (mon);
2398     ArrowCursor ();
2399     Update ();
2400   }
2401 }
2402 
2403 static void PromotePubs (SeqFeatPtr first, BioseqPtr bsp, Uint2 entityID)
2404 
2405 {
2406   MsgAnswer    ans;
2407   Boolean      asked = FALSE;
2408   PubdescPtr   pdp;
2409   SeqDescrPtr  sdp;
2410   SeqEntryPtr  sep;
2411   SeqFeatPtr   sfp;
2412   ValNode      vn;
2413 
2414   MemSet ((Pointer) &vn, 0, sizeof (ValNode));
2415   vn.choice = SEQLOC_WHOLE;
2416   vn.data.ptrvalue = (Pointer) SeqIdFindBest (bsp->id, 0);
2417   vn.next = NULL;
2418 
2419   for (sfp = first; sfp != NULL; sfp = sfp->next) {
2420     if (sfp->data.choice == SEQFEAT_PUB) {
2421       if (SeqLocCompare (sfp->location, &vn) == SLC_A_EQ_B) {
2422         if (! asked) {
2423           ans = Message (MSG_YN, "Do you wish to convert full-length publication features to descriptors?");
2424           if (ans == ANS_NO) return;
2425           asked = TRUE;
2426         }
2427       }
2428     }
2429   }
2430 
2431   sep = GetBestTopParentForData (entityID, bsp);
2432   for (sfp = first; sfp != NULL; sfp = sfp->next) {
2433     if (sfp->data.choice == SEQFEAT_PUB) {
2434       if (SeqLocCompare (sfp->location, &vn) == SLC_A_EQ_B) {
2435         sfp->idx.deleteme = TRUE;
2436         sfp->data.choice = SEQFEAT_COMMENT;
2437         pdp = (PubdescPtr) sfp->data.value.ptrvalue;
2438         sfp->data.value.ptrvalue = NULL;
2439         sdp = CreateNewDescriptor (sep, Seq_descr_pub);
2440         if (sdp != NULL) {
2441           sdp->data.ptrvalue = (Pointer) pdp;
2442         }
2443       }
2444     }
2445   }
2446 
2447   DeleteMarkedObjects (entityID, 0, NULL);
2448 }
2449 
2450 extern Uint2 SmartAttachSeqAnnotToSeqEntry (Uint2 entityID, SeqAnnotPtr sap, ValNodePtr PNTR err_list)
2451 
2452 {
2453   BioseqPtr      bsp;
2454   Int2           genCode;
2455   SeqEntryPtr    oldscope;
2456   OMProcControl  ompc;
2457   SeqEntryPtr    sep;
2458   SeqFeatPtr     sfp = NULL;
2459 
2460   if (sap == NULL) return entityID;
2461   bsp = GetBioseqReferencedByAnnot (sap, entityID);
2462   if (bsp == NULL) {
2463     oldscope = SeqEntrySetScope (NULL);
2464     if (oldscope != NULL) {
2465       bsp = GetBioseqReferencedByAnnot (sap, entityID);
2466       SeqEntrySetScope (oldscope);
2467     }
2468   }
2469   if (bsp != NULL) {
2470     sep = SeqMgrGetSeqEntryForData (bsp);
2471     entityID = ObjMgrGetEntityIDForChoice (sep);
2472     if (sap->type == 1) {
2473       sfp = (SeqFeatPtr) sap->data;
2474       sep = GetBestTopParentForData (entityID, bsp);
2475       genCode = SeqEntryToGeneticCode (sep, NULL, NULL, 0);
2476       SetEmptyGeneticCodes (sap, genCode);
2477       LookupPublications (sap);
2478     } else if (sap->type == 2) {
2479       TakeTop10Alignments (sap);
2480     }
2481     MemSet ((Pointer) &ompc, 0, sizeof (OMProcControl));
2482     ompc.input_entityID = entityID;
2483     ompc.input_itemID = GetItemIDGivenPointer (entityID, OBJ_BIOSEQ, (Pointer) bsp);
2484     ompc.input_itemtype = OBJ_BIOSEQ;
2485     ompc.output_itemtype = OBJ_SEQANNOT;
2486     ompc.output_data = (Pointer) sap;
2487     if (! AttachDataForProc (&ompc, FALSE)) {
2488       if (err_list == NULL) {
2489         Message (MSG_ERROR, "SmartAttachSeqAnnotToSeqEntry failed");
2490       } else {
2491         ValNodeAddPointer  (err_list, 0, StringSave ("SmartAttachSeqAnnotToSeqEntry failed"));
2492       }
2493     } else if (sfp != NULL) {
2494       PromoteXrefs (sfp, bsp, entityID);
2495       PromotePubs (sfp, bsp, entityID);
2496     }
2497   } else {
2498     if (err_list == NULL) {
2499       Message (MSG_ERROR, "Feature table identifiers do not match record");
2500     } else {
2501       ValNodeAddPointer (err_list, 0, StringSave ("Feature table identifiers do not match record"));
2502     }
2503   }
2504   return entityID;
2505 }
2506 
2507 typedef struct removeformdata {
2508   FEATURE_FORM_BLOCK
2509 
2510   Boolean        is_feature;
2511   LisT           objlist;
2512   TexT           findthis;
2513   TexT           fromTxt;
2514   TexT           toTxt;
2515   Uint2          itemtype;
2516   Uint2          subtype;
2517   CharPtr        extra_string;
2518   ValNodePtr     head;
2519   Boolean        stringfound;
2520   Char           findStr [128];
2521   Boolean        take_action_when_string_present;
2522   GrouP          string_constraint_type;
2523   ButtoN         case_insensitive;
2524   Int4           from;
2525   Int4           to;
2526   ValNodePtr     bsplist;
2527   ValNodePtr     bssplist;
2528 } RemoveFormData, PNTR RemoveFormPtr;
2529 
2530 static Boolean ObjectInRange (SeqFeatPtr sfp, Int4 from, Int4 to)
2531 
2532 {
2533   SeqMgrFeatContext  context;
2534 
2535   if (sfp == NULL || from < 0 || to < 0) return TRUE;
2536   if (SeqMgrGetDesiredFeature (sfp->idx.entityID, NULL, 0, 0, sfp, &context) == sfp) {
2537     if (context.left > to) return FALSE;
2538     if (context.right < from) return FALSE;
2539   }
2540   return TRUE;
2541 }
2542 
2543 
2544 static void RemoveFeatureCallback (SeqFeatPtr sfp, Pointer userdata)
2545 {
2546   RemoveFormPtr rfp;
2547   SeqIdPtr      sip;
2548   BioseqPtr     productbsp, productcdna;
2549   BioseqSetPtr  productnps;
2550   
2551   if (sfp == NULL || userdata == NULL) return;
2552 
2553   rfp = (RemoveFormPtr) userdata;
2554   if (rfp == NULL) return;
2555   if (sfp->idx.subtype == rfp->subtype ||
2556       (rfp->subtype == FEATDEF_IMP && IsRealImpFeat (sfp->idx.subtype)) ||
2557       rfp->subtype == ALL_FEATURES) 
2558   {
2559     if ((rfp->from == -1 && rfp->to == -1) || ObjectInRange (sfp, rfp->from, rfp->to)) 
2560     {
2561       if (sfp->data.choice == SEQFEAT_CDREGION) 
2562       {
2563         if (sfp->product != NULL) 
2564         {
2565           sip = SeqLocId (sfp->product);
2566           if (sip != NULL) 
2567           {
2568             productbsp = BioseqFind (sip);
2569             if (productbsp != NULL) 
2570             {
2571               ValNodeAddPointer (&(rfp->bsplist), 0, (Pointer) productbsp);
2572             }
2573           }
2574         }
2575       } 
2576       else if (sfp->data.choice == SEQFEAT_RNA) 
2577       {
2578         if (sfp->product != NULL) 
2579         {
2580           sip = SeqLocId (sfp->product);
2581           if (sip != NULL) 
2582           {
2583             productcdna = BioseqFind (sip);
2584             if (productcdna != NULL && productcdna->idx.parenttype == OBJ_BIOSEQSET) 
2585             {
2586               productnps = (BioseqSetPtr) productcdna->idx.parentptr;
2587               if (productnps != NULL && productnps->_class == BioseqseqSet_class_nuc_prot) 
2588               {
2589                 ValNodeAddPointer (&(rfp->bssplist), 0, (Pointer) productnps);
2590               }
2591             }
2592           }
2593         }
2594       }
2595       sfp->idx.deleteme = TRUE;  
2596     }
2597   }
2598 }
2599 
2600 static void RemoveFeatures (SeqEntryPtr sep, RemoveFormPtr rfp)
2601 {
2602   FeaturesWithTextData fd;
2603   Char           str [32];
2604   Int4           swap;
2605   long int       val;
2606   
2607   GetTitle (rfp->findthis, rfp->findStr, sizeof (rfp->findStr) - 1);
2608   fd.search_text = rfp->findStr;
2609   fd.no_text = StringHasNoText (rfp->findStr);
2610   fd.seqFeatChoice = 0;
2611   fd.featDefChoice = 0;
2612   fd.case_insensitive = GetStatus (rfp->case_insensitive);
2613   fd.whole_word = FALSE;
2614   fd.act_when_string_not_present = ! rfp->take_action_when_string_present;
2615   fd.userdata = rfp;
2616   fd.callback = RemoveFeatureCallback;
2617   GetTitle (rfp->fromTxt, str, sizeof (str) - 1);
2618   if ((! StringHasNoText (str)) && sscanf (str, "%ld", &val) == 1 && val >= 0) {
2619     rfp->from = (Int4) val;
2620   } else {
2621     rfp->from = -1;
2622   }
2623   GetTitle (rfp->toTxt, str, sizeof (str) - 1);
2624   if ((! StringHasNoText (str)) && sscanf (str, "%ld", &val) == 1 && val >= 0) {
2625     rfp->to = (Int4) val;
2626   } else {
2627     rfp->to = -1;
2628   }
2629   if (rfp->from > rfp->to) {
2630     swap = rfp->from;
2631     rfp->from = rfp->to;
2632     rfp->to = swap;
2633   }
2634   OperateOnSeqEntryFeaturesWithText (sep, &fd);
2635   DeleteMarkedObjects (rfp->input_entityID, OBJ_SEQENTRY, (Pointer) sep);
2636 }
2637 
2638 
2639 static Boolean IsUserObjectType (SeqDescrPtr sdp, CharPtr string)
2640 {
2641   UserObjectPtr uop;
2642   ObjectIdPtr   oip;
2643 
2644   if (sdp == NULL || sdp->choice != Seq_descr_user) return FALSE;
2645   if (StringHasNoText (string)) return TRUE;
2646 
2647   uop = (UserObjectPtr) sdp->data.ptrvalue;
2648   if (uop == NULL) return FALSE;
2649   oip = uop->type;
2650   if (oip == NULL || StringICmp (oip->str, string) != 0) return FALSE;
2651   return TRUE;
2652 }
2653 
2654 
2655 static void RemoveDescriptorCallback (SeqDescrPtr sdp, Pointer userdata)
2656 {
2657   ObjValNodePtr ovp;
2658   RemoveFormPtr rfp;
2659   
2660   if (sdp == NULL || userdata == NULL || sdp->extended == 0) return;
2661   rfp = (RemoveFormPtr) userdata;
2662   if (rfp == NULL) return;
2663   
2664   ovp = (ObjValNodePtr) sdp;
2665     
2666   if (sdp->choice == rfp->subtype) 
2667   {
2668     if (sdp->choice != Seq_descr_user || IsUserObjectType (sdp, rfp->extra_string)) {
2669       ovp->idx.deleteme = TRUE; 
2670     }
2671   }
2672 }
2673 
2674 static void RemoveDescriptors (SeqEntryPtr sep, RemoveFormPtr rfp)
2675 {
2676   DescriptorsWithTextData dd;
2677   Char                    str [32];
2678   Int4                    swap;
2679   long int                val;
2680   
2681   GetTitle (rfp->findthis, rfp->findStr, sizeof (rfp->findStr) - 1);
2682   dd.search_text = rfp->findStr;
2683   dd.no_text = StringHasNoText (rfp->findStr);
2684   dd.case_insensitive = GetStatus (rfp->case_insensitive);
2685   dd.whole_word = FALSE;
2686   dd.act_when_string_not_present = ! rfp->take_action_when_string_present;
2687   dd.userdata = rfp;
2688   dd.callback = RemoveDescriptorCallback;
2689   GetTitle (rfp->fromTxt, str, sizeof (str) - 1);
2690   if ((! StringHasNoText (str)) && sscanf (str, "%ld", &val) == 1 && val >= 0) {
2691     rfp->from = (Int4) val;
2692   } else {
2693     rfp->from = -1;
2694   }
2695   GetTitle (rfp->toTxt, str, sizeof (str) - 1);
2696   if ((! StringHasNoText (str)) && sscanf (str, "%ld", &val) == 1 && val >= 0) {
2697     rfp->to = (Int4) val;
2698   } else {
2699     rfp->to = -1;
2700   }
2701   if (rfp->from > rfp->to) {
2702     swap = rfp->from;
2703     rfp->from = rfp->to;
2704     rfp->to = swap;
2705   }
2706   OperateOnSeqEntryDescriptorsWithText (sep, &dd);
2707   DeleteMarkedObjects (rfp->input_entityID, OBJ_SEQENTRY, (Pointer) sep);
2708 }
2709 
2710 static void DoRemoveAsnObject (ButtoN b)
2711 
2712 {
2713   MsgAnswer      ans;
2714   BioseqPtr      bsp;
2715   BioseqSetPtr   bssp;
2716   Uint4          itemID;
2717   OMProcControl  ompc;
2718   RemoveFormPtr  rfp;
2719   SeqEntryPtr    sep;
2720   ValNodePtr     tmp;
2721   Int2           val;
2722   ValNodePtr     vnp;
2723   Boolean        removed_some_features;
2724 
2725   rfp = GetObjectExtra (b);
2726   if (rfp == NULL) return;
2727   sep = GetTopSeqEntryForEntityID (rfp->input_entityID);
2728   if (sep == NULL) return;
2729   Hide (rfp->form);
2730   WatchCursor ();
2731   Update ();
2732   if (rfp->is_feature) {
2733     rfp->itemtype = OBJ_SEQFEAT;
2734   } else {
2735     rfp->itemtype = OBJ_SEQDESC;
2736   }
2737 
2738   if (rfp->itemtype == 0) return;
2739 
2740   removed_some_features = FALSE;
2741   
2742   if (GetValue (rfp->string_constraint_type) == 1)
2743   {
2744         rfp->take_action_when_string_present = TRUE;
2745   }
2746   else
2747   {
2748     rfp->take_action_when_string_present = FALSE;
2749   }
2750 
2751   val = 1;
2752   for (vnp = rfp->head; vnp != NULL; vnp = vnp->next)
2753   {
2754     if (GetItemStatus (rfp->objlist, val))
2755     {
2756       rfp->subtype = vnp->choice;
2757       rfp->extra_string = NULL;
2758       if (rfp->subtype != 0) {
2759         if (rfp->is_feature) {
2760           RemoveFeatures (sep, rfp);
2761           removed_some_features = TRUE;
2762         } else {
2763           if (rfp->subtype == Seq_descr_user && StringCmp (vnp->data.ptrvalue, "User") != 0) {
2764             rfp->extra_string = vnp->data.ptrvalue;
2765           }
2766           RemoveDescriptors (sep, rfp);
2767         }
2768       }
2769     }
2770     val ++;
2771   }
2772 
2773   if (removed_some_features) {
2774     if (rfp->bsplist != NULL) {
2775       ans = Message (MSG_YN, "Remove protein products?");
2776       if (ans == ANS_YES) {
2777         for (tmp = rfp->bsplist; tmp != NULL; tmp = tmp->next) {
2778           bsp = (BioseqPtr) tmp->data.ptrvalue;
2779           itemID = GetItemIDGivenPointer (rfp->input_entityID, OBJ_BIOSEQ, (Pointer) bsp);
2780           if (itemID > 0) {
2781             MemSet ((Pointer) (&ompc), 0, sizeof (OMProcControl));
2782             ompc.do_not_reload_from_cache = TRUE;
2783             ompc.input_entityID = rfp->input_entityID;
2784             ompc.input_itemID = itemID;
2785             ompc.input_itemtype = OBJ_BIOSEQ;
2786             if (! DetachDataForProc (&ompc, FALSE)) {
2787               Message (MSG_POSTERR, "DetachDataForProc failed");
2788             }
2789             SeqMgrDeleteFromBioseqIndex (bsp);
2790           }
2791         }
2792         ans = Message (MSG_YN, "Renormalize Nuc-Prot sets?");
2793         if (ans == ANS_YES)
2794         {
2795           RemoveOrphanProteins (rfp->input_entityID, sep);
2796           RenormalizeNucProtSets (sep, TRUE);           
2797         }
2798       }
2799     }
2800     if (rfp->bssplist != NULL) {
2801       ans = Message (MSG_YN, "Remove cDNA nuc-prot products?");
2802       if (ans == ANS_YES) {
2803         for (tmp = rfp->bssplist; tmp != NULL; tmp = tmp->next) {
2804           bssp = (BioseqSetPtr) tmp->data.ptrvalue;
2805           itemID = GetItemIDGivenPointer (rfp->input_entityID, OBJ_BIOSEQSET, (Pointer) bssp);
2806           if (itemID > 0) {
2807             MemSet ((Pointer) (&ompc), 0, sizeof (OMProcControl));
2808             ompc.do_not_reload_from_cache = TRUE;
2809             ompc.input_entityID = rfp->input_entityID;
2810             ompc.input_itemID = itemID;
2811             ompc.input_itemtype = OBJ_BIOSEQSET;
2812             if (! DetachDataForProc (&ompc, FALSE)) {
2813               Message (MSG_POSTERR, "DetachDataForProc failed");
2814             }
2815           }
2816         }
2817       }
2818     }
2819   }
2820   ArrowCursor ();
2821   Update ();
2822   ObjMgrSetDirtyFlag (rfp->input_entityID, TRUE);
2823   ObjMgrSendMsg (OM_MSG_UPDATE, rfp->input_entityID, 0, 0);
2824   ObjMgrDeSelect (0, 0, 0, 0, NULL);
2825   Remove (rfp->form);
2826 }
2827 
2828 static void RemoveDefLinesCallback (SeqEntryPtr sep, Pointer mydata, Int4 index, Int2 indent)
2829 
2830 {
2831   BioseqPtr      bsp;
2832   BioseqSetPtr   bssp;
2833   ValNodePtr     nextsdp;
2834   Pointer PNTR   prevsdp;
2835   ValNodePtr     sdp;
2836 
2837   if (sep == NULL || sep->data.ptrvalue == NULL) return;
2838   if (IS_Bioseq (sep)) {
2839     bsp = (BioseqPtr) sep->data.ptrvalue;
2840     sdp = bsp->descr;
2841     prevsdp = (Pointer PNTR) &(bsp->descr);
2842   } else if (IS_Bioseq_set (sep)) {
2843     bssp = (BioseqSetPtr) sep->data.ptrvalue;
2844     sdp = bssp->descr;
2845     prevsdp = (Pointer PNTR) &(bssp->descr);
2846   } else return;
2847 
2848   while (sdp != NULL) {
2849     nextsdp = sdp->next;
2850     if (sdp->choice == Seq_descr_title)
2851     {
2852       *(prevsdp) = sdp->next;
2853       sdp->next = NULL;
2854       SeqDescFree (sdp);
2855     } else {
2856       prevsdp = (Pointer PNTR) &(sdp->next);
2857     }
2858     sdp = nextsdp;
2859   }
2860 }
2861 
2862 extern void RemoveDefLinesToolBtn (ButtoN b)
2863 {
2864   BaseFormPtr  bfp;
2865   SeqEntryPtr  sep;
2866 
2867   bfp = (BaseFormPtr) GetObjectExtra (b);
2868   if (bfp == NULL) return;
2869 
2870   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
2871   if (sep == NULL) return;
2872   
2873   WatchCursor ();
2874   Update ();
2875 
2876   SeqEntryExplore (sep, NULL, RemoveDefLinesCallback);
2877 
2878   ArrowCursor ();
2879   Update ();
2880   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
2881   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
2882   ObjMgrDeSelect (0, 0, 0, 0, NULL);
2883   CommonApplyToAllProc (bfp, ADD_TITLE);
2884 }
2885 
2886 int LIBCALLBACK SortByVnpChoice (VoidPtr ptr1, VoidPtr ptr2)
2887 
2888 {
2889   ValNodePtr   vnp1;
2890   ValNodePtr   vnp2;
2891 
2892   if (ptr1 != NULL && ptr2 != NULL) {
2893     vnp1 = *((ValNodePtr PNTR) ptr1);
2894     vnp2 = *((ValNodePtr PNTR) ptr2);
2895     if (vnp1 != NULL && vnp2 != NULL) {
2896       if (vnp1->choice > vnp2->choice) {
2897         return 1;
2898       } else if (vnp1->choice < vnp2->choice) {
2899         return -1;
2900       } else {
2901         return 0;
2902       }
2903     } else {
2904       return 0;
2905     }
2906   } else {
2907     return 0;
2908   }
2909 }
2910 
2911 static void RemoveMessageProc (ForM f, Int2 mssg)
2912 
2913 {
2914   RemoveFormPtr  rfp;
2915 
2916   rfp = (RemoveFormPtr) GetObjectExtra (f);
2917   if (rfp != NULL) {
2918     if (rfp->appmessage != NULL) {
2919       rfp->appmessage (f, mssg);
2920     }
2921   }
2922 }
2923 
2924 static void CleanupRemovePage (GraphiC g, VoidPtr data)
2925 
2926 {
2927   RemoveFormPtr  rfp;
2928 
2929   rfp = (RemoveFormPtr) data;
2930   if (rfp != NULL) {
2931     ValNodeFreeData (rfp->head);
2932     ValNodeFree (rfp->bsplist);
2933     ValNodeFree (rfp->bssplist);
2934   }
2935   StdCleanupFormProc (g, data);
2936 }
2937 
2938 static CharPtr descNames [] = {
2939   " ", " ", " ", " ", "Name",
2940   "Title", " ", "Comment", "Numbering",
2941   "MapLoc", "PIR", "GenBank", "Publication",
2942   "Region", "User", "SWISS-PROT", "dbXREF",
2943   "EMBL", "Create Date", "Update Date", "PRF",
2944   "PDB", "Heterogen", "BioSource", "MolInfo", NULL
2945 };
2946 
2947 /*
2948 #ifdef INTERNAL_NCBI_SEQUIN
2949 #define LISTHEIGHT 16
2950 #else
2951 #define LISTHEIGHT 8
2952 #endif
2953 */
2954 
2955 CharPtr MostUsedDescriptorList[] = { "Title" };
2956 
2957 static Boolean isMostUsedDescriptor (CharPtr descname)
2958 {
2959   Int2 i;
2960 
2961   if (descname == NULL) return FALSE;
2962 
2963   for (i=0; i < sizeof (MostUsedDescriptorList) / sizeof (CharPtr); i++)
2964   {
2965     if (StringCmp (descname, MostUsedDescriptorList[i]) == 0)
2966       return TRUE;
2967   }
2968   return FALSE;
2969 }
2970 
2971 static int LIBCALLBACK SortMostUsedDescriptorsFirst (VoidPtr ptr1, VoidPtr ptr2)
2972 
2973 {
2974   ValNodePtr   vnp1;
2975   ValNodePtr   vnp2;
2976   CharPtr      str1;
2977   CharPtr      str2;
2978   Boolean      str1_is_most_used;
2979   Boolean      str2_is_most_used;
2980 
2981   /* Check parameters */
2982 
2983   if ((NULL == ptr1) || (NULL == ptr2))
2984     return 0;
2985 
2986   vnp1 = *((ValNodePtr PNTR) ptr1);
2987   vnp2 = *((ValNodePtr PNTR) ptr2);
2988   if ((NULL == vnp1) || (NULL == vnp2))
2989     return 0;
2990 
2991   str1 = (CharPtr) vnp1->data.ptrvalue;
2992   str2 = (CharPtr) vnp2->data.ptrvalue;
2993   if ((NULL == str1) || (NULL == str2))
2994     return 0;
2995 
2996   str1_is_most_used = isMostUsedDescriptor (str1);
2997   str2_is_most_used = isMostUsedDescriptor (str2);
2998 
2999   if ((str1_is_most_used && str2_is_most_used)
3000     || (!str1_is_most_used && !str2_is_most_used))
3001   {
3002     return SortVnpByString (ptr1, ptr2);
3003   }
3004   else if (str1_is_most_used)
3005   {
3006     return -1;
3007   }
3008   else
3009   {
3010     return 1;
3011   }
3012 }
3013 
3014 extern ValNodePtr BuildDescriptorValNodeList (void)
3015 {
3016   Int4 j;
3017   ValNodePtr vnp;
3018   ValNodePtr head = NULL;
3019   
3020   for (j = 1; descNames [j] != NULL; j++) {
3021     if (StringHasNoText (descNames [j])) continue;
3022     vnp = ValNodeNew (head);
3023     if (head == NULL) {
3024       head = vnp;
3025     }
3026     if (vnp != NULL) {
3027       vnp->choice = j;
3028       vnp->data.ptrvalue = StringSave (descNames [j]);
3029     }
3030   }
3031   head = SortValNode (head, SortMostUsedDescriptorsFirst);
3032   return head;
3033 }
3034 
3035 
3036 static void RemoveAsnObject (IteM i, Boolean feature)
3037 
3038 {
3039   BaseFormPtr        bfp;
3040   ButtoN             b;
3041   GrouP              c;
3042   GrouP              g;
3043   GrouP              h;
3044   ValNodePtr         head;
3045   GrouP              k;
3046   Int2               listHeight;
3047   GrouP              m;
3048   RemoveFormPtr      rfp;
3049   SeqEntryPtr        sep;
3050   StdEditorProcsPtr  sepp;
3051   CharPtr            title;
3052   ValNodePtr         vnp;
3053   WindoW             w;
3054 
3055 #ifdef WIN_MAC
3056   bfp = currentFormDataPtr;
3057 #else
3058   bfp = GetObjectExtra (i);
3059 #endif
3060   if (bfp == NULL) return;
3061   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3062   if (sep == NULL) return;
3063   rfp = (RemoveFormPtr) MemNew (sizeof (RemoveFormData));
3064   if (rfp == NULL) return;
3065   if (feature) {
3066     title = "Feature Removal";
3067   } else {
3068     title = "Descriptor Removal";
3069   }
3070   w = FixedWindow (-50, -33, -10, -10, title, StdCloseWindowProc);
3071   SetObjectExtra (w, rfp, CleanupRemovePage);
3072   rfp->form = (ForM) w;
3073   rfp->formmessage = RemoveMessageProc;
3074 
3075   sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
3076   if (sepp != NULL) {
3077     SetActivate (w, sepp->activateForm);
3078     rfp->appmessage = sepp->handleMessages;
3079   }
3080 
3081   rfp->input_entityID = bfp->input_entityID;
3082   rfp->input_itemID = bfp->input_itemID;
3083   rfp->input_itemtype = bfp->input_itemtype;
3084 
3085   h = HiddenGroup (w, -1, 0, NULL);
3086   SetGroupSpacing (h, 10, 10);
3087 
3088   g = HiddenGroup (h, 0, 2, NULL);
3089   rfp->is_feature = feature;
3090   if (feature) {
3091     StaticPrompt (g, "Feature", 0, 0, programFont, 'c');
3092   } else {
3093     StaticPrompt (g, "Descriptor", 0, 0, programFont, 'c');
3094   }
3095   if (indexerVersion) {
3096     listHeight = 16;
3097   } else {
3098     listHeight = 8;
3099   }
3100   rfp->objlist = MultiList (g, 16, listHeight, NULL);
3101   head = NULL;
3102   if (feature) {
3103     head = BuildFeatureValNodeList (TRUE, "All", ALL_FEATURES, TRUE, FALSE);
3104   } else {
3105     head = BuildDescriptorValNodeList();
3106     vnp = ValNodeNew (NULL);
3107     vnp->choice = Seq_descr_user;
3108     vnp->data.ptrvalue = StringSave ("StructuredComment");
3109     ValNodeInsert (&(head->next), vnp, SortVnpByString);
3110   }
3111   if (head != NULL) {
3112 
3113     for (vnp = head; vnp != NULL; vnp = vnp->next) {
3114       ListItem (rfp->objlist, (CharPtr) vnp->data.ptrvalue);
3115     }
3116   }
3117   rfp->head = head;
3118   rfp->bsplist = NULL;
3119   rfp->bssplist = NULL;
3120 
3121   k = NormalGroup (h, 0, 3, "Optional string constraint", NULL, NULL);
3122   rfp->string_constraint_type = HiddenGroup (k, 0, 2, NULL);
3123   RadioButton (rfp->string_constraint_type, "Remove when text is present");
3124   RadioButton (rfp->string_constraint_type, "Remove when text is not present");
3125   SetValue (rfp->string_constraint_type, 1);
3126   rfp->findthis = DialogText (k, "", 14, NULL);
3127   rfp->case_insensitive = CheckBox (k, "Case Insensitive", NULL);
3128 
3129   m = NULL;
3130   if (feature) {
3131     m = HiddenGroup (h, 4, 0, NULL);
3132     StaticPrompt (m, "From", 0, dialogTextHeight, programFont, 'l');
3133     rfp->fromTxt = DialogText (m, "", 6, NULL);
3134     StaticPrompt (m, "To", 0, dialogTextHeight, programFont, 'l');
3135     rfp->toTxt = DialogText (m, "", 6, NULL);
3136   }
3137 
3138   c = HiddenGroup (h, 4, 0, NULL);
3139   b = DefaultButton (c, "Accept", DoRemoveAsnObject);
3140   SetObjectExtra (b, rfp, NULL);
3141   PushButton (c, "Cancel", StdCancelButtonProc);
3142 
3143   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) k, (HANDLE) c, (HANDLE) m, NULL);
3144   RealizeWindow (w);
3145   Show (w);
3146   Update ();
3147 }
3148 
3149 extern void RemoveDescriptor (IteM i)
3150 
3151 {
3152   RemoveAsnObject (i, FALSE);
3153 }
3154 
3155 #define SLCT_FEAT    1
3156 #define SLCT_DESC    2
3157 #define SLCT_BIOSEQ  3
3158 #define SLCT_PUB     4
3159 
3160 typedef struct selectformdata {
3161   FEATURE_FORM_BLOCK
3162 
3163   Int2           type;
3164   LisT           objlist;
3165   TexT           findthis;
3166   Uint2          itemtype;
3167   Uint2          subtype;
3168   ObjMgrPtr      omp;
3169   ObjMgrTypePtr  omtp;
3170   ValNodePtr     head;
3171   Boolean        stringfound;
3172   Char           findStr [128];
3173   ButtoN         when_string_not_present;
3174   ButtoN         case_insensitive;
3175 } SelectFormData, PNTR SelectFormPtr;
3176 
3177 static void FeatureSelectCallback (SeqFeatPtr sfp, Pointer userdata)
3178 {
3179   Uint1Ptr subtype;
3180   if (sfp == NULL) return;
3181   
3182   if (userdata != NULL)
3183   {
3184         subtype = (Uint1Ptr) userdata;
3185         if (*subtype != sfp->idx.subtype) return;
3186   }
3187   ObjMgrAlsoSelect (sfp->idx.entityID, sfp->idx.itemID, OBJ_SEQFEAT, 0, NULL);
3188 }
3189 
3190 static void DescriptorSelectCallback (SeqDescrPtr sdp, Pointer userdata)
3191 {
3192   ObjValNodePtr ovp;
3193   Uint1Ptr subtype;
3194   
3195   if (sdp == NULL || sdp->extended == 0) return;
3196   
3197   ovp = (ObjValNodePtr) sdp;
3198   if (userdata != NULL)
3199   {
3200         subtype = (Uint1Ptr) userdata;
3201         if (*subtype != ovp->idx.subtype) return;
3202   }
3203     
3204   ObjMgrAlsoSelect (ovp->idx.entityID, ovp->idx.itemID, OBJ_SEQDESC, 0, NULL);
3205 }
3206 
3207 static void BioseqSelectCallback (BioseqPtr bsp, Pointer userdata)
3208 {
3209   Uint1Ptr subtype;
3210   
3211   if (bsp == NULL) return;
3212   
3213   if (userdata != NULL)
3214   {
3215         subtype = (Uint1Ptr) userdata;
3216         if (*subtype != bsp->idx.subtype) return;
3217   }
3218     
3219   ObjMgrAlsoSelect (bsp->idx.entityID, bsp->idx.itemID, bsp->idx.itemtype, 0, NULL);
3220 }
3221 
3222 
3223 static void DoSelectAsnObject (ButtoN b)
3224 
3225 {
3226   SelectFormPtr           selfp;
3227   SeqEntryPtr             sep;
3228   Int2                    val;
3229   ValNodePtr              vnp;
3230   FeaturesWithTextData    fd;
3231   DescriptorsWithTextData dd;
3232   Uint1                   bioseq_choice = Seq_repr_raw;
3233   Uint1                   pub_choice = FEATDEF_PUB;
3234 
3235   selfp = GetObjectExtra (b);
3236   if (selfp == NULL) return;
3237   sep = GetTopSeqEntryForEntityID (selfp->input_entityID);
3238   if (sep == NULL) return;
3239   Hide (selfp->form);
3240   
3241   vnp = NULL;
3242   if (selfp->type == SLCT_FEAT || selfp->type == SLCT_DESC)
3243   {
3244     val = GetValue (selfp->objlist);
3245     if (val > 0) {
3246       vnp = selfp->head;
3247       while (vnp != NULL && val > 1) {
3248         val--;
3249         vnp = vnp->next;
3250       }
3251     }
3252   }
3253 
3254   switch (selfp->type) {
3255     case SLCT_FEAT :
3256       GetTitle (selfp->findthis, selfp->findStr, sizeof (selfp->findStr) - 1);
3257       fd.search_text = selfp->findStr;
3258       fd.no_text = StringHasNoText (selfp->findStr);
3259       fd.seqFeatChoice = 0;
3260       fd.featDefChoice = 0;
3261       fd.case_insensitive = GetStatus (selfp->case_insensitive);
3262       fd.whole_word = FALSE;
3263       fd.act_when_string_not_present = GetStatus (selfp->when_string_not_present);
3264       fd.callback = FeatureSelectCallback;
3265       if (vnp == NULL)
3266       {
3267         fd.userdata = NULL;
3268       }
3269       else
3270       {
3271         fd.userdata = (Pointer) &(vnp->choice);
3272       }
3273       OperateOnSeqEntryFeaturesWithText (sep, &fd);     
3274       break;
3275     case SLCT_DESC :
3276       GetTitle (selfp->findthis, selfp->findStr, sizeof (selfp->findStr) - 1);
3277       dd.search_text = selfp->findStr;
3278       dd.no_text = StringHasNoText (selfp->findStr);
3279       dd.case_insensitive = GetStatus (selfp->case_insensitive);
3280       dd.whole_word = FALSE;
3281       dd.act_when_string_not_present = GetStatus (selfp->when_string_not_present);
3282       dd.callback = DescriptorSelectCallback;
3283       if (vnp == NULL)
3284       {
3285         dd.userdata = NULL;
3286       }
3287       else
3288       {
3289         dd.userdata = (Pointer) &(vnp->choice);
3290       }
3291       OperateOnSeqEntryDescriptorsWithText (sep, &dd);  
3292       break;
3293     case SLCT_BIOSEQ :
3294           VisitBioseqsInSep (sep, (Pointer) &bioseq_choice, BioseqSelectCallback);      
3295       break;
3296         case SLCT_PUB:
3297       GetTitle (selfp->findthis, selfp->findStr, sizeof (selfp->findStr) - 1);
3298       fd.search_text = selfp->findStr;
3299       fd.no_text = StringHasNoText (selfp->findStr);
3300       fd.seqFeatChoice = 0;
3301       fd.featDefChoice = 0;
3302       fd.case_insensitive = GetStatus (selfp->case_insensitive);
3303       fd.whole_word = FALSE;
3304       fd.act_when_string_not_present = GetStatus (selfp->when_string_not_present);
3305       fd.callback = FeatureSelectCallback;
3306       fd.userdata = (Pointer) &pub_choice;
3307       OperateOnSeqEntryFeaturesWithText (sep, &fd); 
3308       dd.search_text = fd.search_text;
3309       dd.no_text = fd.no_text;
3310       dd.case_insensitive = fd.case_insensitive;
3311       dd.whole_word = fd.whole_word;
3312       dd.act_when_string_not_present = fd.act_when_string_not_present;
3313       dd.callback = DescriptorSelectCallback;
3314       dd.userdata = fd.userdata;        
3315       OperateOnSeqEntryDescriptorsWithText (sep, &dd);  
3316       break;    
3317     default :
3318       Remove (selfp->form);
3319       Update ();
3320       return;
3321   }
3322   WatchCursor ();
3323   Update ();
3324 
3325   ArrowCursor ();
3326   Update ();
3327   /* ObjMgrSendMsg (OM_MSG_UPDATE, selfp->input_entityID, 0, 0); */
3328   Remove (selfp->form);
3329 }
3330 
3331 static void SelectMessageProc (ForM f, Int2 mssg)
3332 
3333 {
3334   SelectFormPtr  selfp;
3335 
3336   selfp = (SelectFormPtr) GetObjectExtra (f);
3337   if (selfp != NULL) {
3338     if (selfp->appmessage != NULL) {
3339       selfp->appmessage (f, mssg);
3340     }
3341   }
3342 }
3343 
3344 static void CleanupSelectPage (GraphiC g, VoidPtr data)
3345 
3346 {
3347   SelectFormPtr  selfp;
3348 
3349   selfp = (SelectFormPtr) data;
3350   if (selfp != NULL) {
3351     ValNodeFreeData (selfp->head);
3352   }
3353   StdCleanupFormProc (g, data);
3354 }
3355 
3356 static void SelectAsnObject (IteM i, Int2 type)
3357 
3358 {
3359   BaseFormPtr        bfp;
3360   ButtoN             b;
3361   GrouP              c;
3362   GrouP              g;
3363   GrouP              h;
3364   GrouP              k = NULL, m;
3365   ValNodePtr         head;
3366   Uint1              j;
3367   Int2               listHeight;
3368   SelectFormPtr      selfp;
3369   SeqEntryPtr        sep;
3370   StdEditorProcsPtr  sepp;
3371   CharPtr            title;
3372   ValNodePtr         vnp;
3373   WindoW             w;
3374 
3375 #ifdef WIN_MAC
3376   bfp = currentFormDataPtr;
3377 #else
3378   bfp = GetObjectExtra (i);
3379 #endif
3380   if (bfp == NULL) return;
3381   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3382   if (sep == NULL) return;
3383   selfp = (SelectFormPtr) MemNew (sizeof (SelectFormData));
3384   if (selfp == NULL) return;
3385   switch (type) {
3386     case SLCT_FEAT :
3387       title = "Feature Selection";
3388       break;
3389     case SLCT_DESC :
3390       title = "Descriptor Selection";
3391       break;
3392     case SLCT_BIOSEQ :
3393       title = "Sequence Selection";
3394       break;
3395         case SLCT_PUB:
3396           title = "Publication Selection";
3397           break;
3398     default :
3399       title = "? Selection";
3400       break;
3401   }
3402   w = FixedWindow (-50, -33, -10, -10, title, StdCloseWindowProc);
3403   SetObjectExtra (w, selfp, CleanupSelectPage);
3404   selfp->form = (ForM) w;
3405   selfp->formmessage = SelectMessageProc;
3406 
3407   sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
3408   if (sepp != NULL) {
3409     SetActivate (w, sepp->activateForm);
3410     selfp->appmessage = sepp->handleMessages;
3411   }
3412 
3413   selfp->input_entityID = bfp->input_entityID;
3414   selfp->input_itemID = bfp->input_itemID;
3415   selfp->input_itemtype = bfp->input_itemtype;
3416 
3417   h = HiddenGroup (w, -1, 0, NULL);
3418   SetGroupSpacing (h, 10, 10);
3419 
3420   g = HiddenGroup (h, 0, 2, NULL);
3421   selfp->type = type;
3422   switch (type) {
3423     case SLCT_FEAT :
3424       StaticPrompt (g, "Feature", 0, 0, programFont, 'c');
3425       break;
3426     case SLCT_DESC :
3427       StaticPrompt (g, "Descriptor", 0, 0, programFont, 'c');
3428       break;
3429     case SLCT_BIOSEQ :
3430       StaticPrompt (g, "Sequence", 0, 0, programFont, 'c');
3431       break;
3432         case SLCT_PUB:
3433           StaticPrompt (g, "Publication", 0, 0, programFont, 'c');
3434           break;
3435     default :
3436       break;
3437   }
3438   if (indexerVersion) {
3439     listHeight = 16;
3440   } else {
3441     listHeight = 8;
3442   }
3443   
3444   if (type != SLCT_PUB)
3445   {
3446     selfp->objlist = SingleList (g, 16, listHeight, NULL);
3447   }
3448   head = NULL;
3449   if (type == SLCT_FEAT) {
3450     head = BuildFeatureValNodeList (TRUE, NULL, ALL_FEATURES, TRUE, FALSE);
3451   } else if (type == SLCT_DESC) {
3452     for (j = 1; descNames [j] != NULL; j++) {
3453       if (StringHasNoText (descNames [j])) continue;
3454       vnp = ValNodeNew (head);
3455       if (head == NULL) {
3456         head = vnp;
3457       }
3458       if (vnp != NULL) {
3459         vnp->choice = j;
3460         vnp->data.ptrvalue = StringSave (descNames [j]);
3461       }
3462     }
3463   }
3464   if (head != NULL) {
3465     if (type != SLCT_FEAT) {
3466       head = SortValNode (head, SortByVnpChoice);
3467     }
3468     for (vnp = head; vnp != NULL; vnp = vnp->next) {
3469       ListItem (selfp->objlist, (CharPtr) vnp->data.ptrvalue);
3470     }
3471   }
3472   selfp->head = head;
3473 
3474   if (selfp->type == SLCT_FEAT || selfp->type == SLCT_DESC || selfp->type == SLCT_PUB)
3475   {
3476     k = HiddenGroup (h, 0, 3, NULL);
3477     StaticPrompt (k, "Optional string constraint", 0, dialogTextHeight, programFont, 'c');
3478     selfp->findthis = DialogText (k, "", 14, NULL);
3479     m = HiddenGroup (k, 2, 0, NULL);
3480     selfp->case_insensitive = CheckBox (m, "Case Insensitive", NULL);
3481     selfp->when_string_not_present = CheckBox (m, "When String Not Present", NULL);
3482   }
3483 
3484   c = HiddenGroup (h, 4, 0, NULL);
3485   b = DefaultButton (c, "Accept", DoSelectAsnObject);
3486   SetObjectExtra (b, selfp, NULL);
3487   PushButton (c, "Cancel", StdCancelButtonProc);
3488 
3489   if (selfp->type == SLCT_FEAT || selfp->type == SLCT_DESC)
3490   {
3491     AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, (HANDLE) k, NULL);
3492   }
3493   else
3494   {
3495     AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL);
3496   }
3497   RealizeWindow (w);
3498   if (type == SLCT_BIOSEQ) {
3499     DoSelectAsnObject (b);
3500     Update ();
3501     return;
3502   }
3503   Show (w);
3504   Update ();
3505 }
3506 
3507 extern void SelectDescriptor (IteM i)
3508 
3509 {
3510   SelectAsnObject (i, SLCT_DESC);
3511 }
3512 
3513 extern void SelectBioseq (IteM i)
3514 
3515 {
3516   SelectAsnObject (i, SLCT_BIOSEQ);
3517 }
3518 
3519 extern void SelectPubs (IteM i)
3520 
3521 {
3522   SelectAsnObject (i, SLCT_PUB);
3523 }
3524 
3525 typedef struct fuseformdata {
3526   FEATURE_FORM_BLOCK
3527 
3528   LisT           objlist;
3529   Uint2          subtype;
3530   ValNodePtr     head;
3531 } FuseFormData, PNTR FuseFormPtr;
3532 
3533 static SeqLocPtr FuseTwoLocations (Uint2 entityID, SeqLocPtr slp1, SeqLocPtr slp2)
3534 {
3535   Boolean           slp1_partial5, slp1_partial3;
3536   Boolean           slp2_partial5, slp2_partial3;
3537   Int4              slp1_start_pos, slp1_stop_pos;
3538   Int4              slp2_start_pos, slp2_stop_pos;
3539   SeqLocPtr         slp_result = NULL, slp2_copy, slp1_copy, slp_list;
3540   BioseqPtr         bsp1, bsp2;
3541 
3542   if (slp1 == NULL || slp2 == NULL)
3543   {
3544     return NULL;
3545   }
3546   
3547   bsp1 = GetBioseqGivenSeqLoc (slp1, entityID);
3548   bsp2 = GetBioseqGivenSeqLoc (slp2, entityID);
3549   
3550   /* preserve partialness of ends */
3551   CheckSeqLocForPartial (slp1, &slp1_partial5, &slp1_partial3);
3552   slp1_start_pos = SeqLocStart (slp1);
3553   slp1_stop_pos = SeqLocStop (slp1);
3554   CheckSeqLocForPartial (slp2, &slp2_partial5, &slp2_partial3);
3555   slp2_start_pos = SeqLocStart (slp2);
3556   slp2_stop_pos = SeqLocStop (slp2);
3557   if (slp1_start_pos > slp2_start_pos)
3558   {
3559     slp1_partial5 = slp2_partial5;
3560   }
3561   if (slp1_stop_pos < slp2_stop_pos)
3562   {
3563     slp1_partial3 = slp2_partial3;
3564   }
3565 
3566   if (bsp1 == bsp2)
3567   {
3568     slp_result = SeqLocMerge (bsp1, slp2, slp1, FALSE, TRUE, FALSE);
3569     SetSeqLocPartial (slp_result, slp1_partial5, slp1_partial3);
3570   }
3571   else 
3572   {
3573     /* we are dealing with a segmented set, and both locations are segments */
3574     slp1_copy = (SeqLocPtr) AsnIoMemCopy (slp1, (AsnReadFunc) SeqLocAsnRead,
3575                                           (AsnWriteFunc) SeqLocAsnWrite);
3576     slp2_copy = (SeqLocPtr) AsnIoMemCopy (slp2, (AsnReadFunc) SeqLocAsnRead,
3577                                           (AsnWriteFunc) SeqLocAsnWrite);
3578     if (slp1_copy != NULL && slp2_copy != NULL)
3579     {
3580       /* if the second location is already a mix, don't create a nested
3581        * mixed location.
3582        */
3583       if (slp2_copy->choice == SEQLOC_MIX)
3584       {
3585         slp_list = (SeqLocPtr) slp2_copy->data.ptrvalue;
3586         slp2_copy->data.ptrvalue = NULL;
3587         slp2_copy = SeqLocFree (slp2_copy);
3588         slp2_copy = slp_list;
3589       }
3590     
3591       if (slp1_copy->choice == SEQLOC_MIX)
3592       {
3593         slp_list = slp1_copy->data.ptrvalue;
3594         while (slp_list != NULL && slp_list->next != NULL)
3595         {
3596           slp_list = slp_list->next;
3597         }
3598         
3599         
3600         if (slp_list == NULL)
3601         {
3602           slp1_copy->data.ptrvalue = slp2_copy;
3603         }
3604         else
3605         {
3606           slp_list->next = slp2_copy;
3607         }
3608         slp_result = slp1_copy;
3609       }
3610       else
3611       {
3612         slp_result = ValNodeNew (NULL);
3613         if (slp_result != NULL)
3614         {
3615           slp_result->choice = SEQLOC_MIX;
3616           slp_result->data.ptrvalue = slp1_copy;
3617           slp1_copy->next = slp2_copy;
3618         }
3619       }
3620     }
3621   }
3622   
3623   return slp_result;
3624 }
3625 
3626 static void CombineProductFeatures (BioseqPtr pbsp1, BioseqPtr pbsp2, Int4 old_len)
3627 {
3628   SeqAnnotPtr sap1, sap2, last_sap1 = NULL;
3629   SeqFeatPtr  sfp2, sfp_new, last_sfp1 = NULL, main_prot = NULL;
3630   Boolean     partial5_orig = TRUE, partial3_orig = TRUE;
3631   Boolean     partial5_new, partial3_new;
3632   SeqEntryPtr psep;
3633   ProtRefPtr  prp;
3634   
3635   if (pbsp1 == NULL || pbsp2 == NULL)
3636   {
3637     return;
3638   }
3639   
3640   sap2 = pbsp2->annot;
3641   while (sap2 != NULL && sap2->type != 1)
3642   {
3643     sap2 = sap2->next;
3644   }
3645   if (sap2 == NULL || sap2->data == NULL)
3646   {
3647     /* second sequence has no features */
3648     return;
3649   }
3650   
3651   sap1 = pbsp1->annot;
3652   while (sap1 != NULL && sap1->type != 1)
3653   {
3654     last_sap1 = sap1;
3655     sap1 = sap1->next;
3656   }
3657   if (sap1 == NULL)
3658   {
3659     sap1 = SeqAnnotNew();
3660     if (sap1 == NULL)
3661     {
3662       return;
3663     }
3664     sap1->type = 1;
3665     sap1->data = NULL;
3666     if (last_sap1 == NULL)
3667     {
3668       pbsp1->annot = sap1;
3669     }
3670     else
3671     {
3672       last_sap1->next = sap1;
3673     }
3674   }
3675   
3676   last_sfp1 = sap1->data;
3677   if (last_sfp1 != NULL && last_sfp1->idx.subtype == FEATDEF_PROT)
3678   {
3679     main_prot = last_sfp1;
3680     CheckSeqLocForPartial (main_prot->location, &partial5_orig, &partial3_orig);
3681   }
3682   while (last_sfp1 != NULL && last_sfp1->next != NULL)
3683   {
3684     if (main_prot == NULL && last_sfp1->idx.subtype == FEATDEF_PROT)
3685     {
3686       main_prot = last_sfp1;
3687       CheckSeqLocForPartial (main_prot->location, &partial5_orig, &partial3_orig);
3688     }
3689     last_sfp1 = last_sfp1->next;
3690   }
3691   if (last_sfp1 != NULL && main_prot == NULL && last_sfp1->idx.subtype == FEATDEF_PROT)
3692   {
3693     main_prot = last_sfp1;
3694     CheckSeqLocForPartial (main_prot->location, &partial5_orig, &partial3_orig);
3695   }
3696   
3697   partial3_new = partial3_orig;
3698   
3699   while (sap2 != NULL)
3700   {
3701     if (sap2->type == 1)
3702     {
3703       for (sfp2 = sap2->data; sfp2 != NULL; sfp2 = sfp2->next)
3704       {  
3705         if (sfp2->idx.subtype == FEATDEF_PROT)
3706         {
3707           CheckSeqLocForPartial (sfp2->location, &partial5_new, &partial3_new);
3708           /* do not create additional full-length protein features */
3709           continue;
3710         }
3711         sfp_new = (SeqFeatPtr) AsnIoMemCopy (sfp2, (AsnReadFunc) SeqFeatAsnRead,
3712                                                (AsnWriteFunc) SeqFeatAsnWrite);
3713         if (sfp_new != NULL)
3714         {
3715           OffsetLocation (sfp_new->location, old_len, pbsp1->id);
3716 
3717           if (last_sfp1 == NULL)
3718           {
3719             sap1->data = sfp_new;
3720           }
3721           else
3722           {
3723             last_sfp1->next = sfp_new;
3724           }
3725           last_sfp1 = sfp_new;
3726         }
3727       }
3728     }
3729     sap2 = sap2->next;
3730   }
3731 
3732   /* make sure there is one full-length protein feature */
3733   if (main_prot == NULL)
3734   {
3735     psep = SeqMgrGetSeqEntryForData (pbsp1);
3736     main_prot = CreateNewFeature (psep, NULL, SEQFEAT_PROT, NULL);
3737     if (main_prot != NULL) 
3738     {
3739       prp = ProtRefNew ();
3740       main_prot->data.value.ptrvalue = (Pointer) prp;
3741     }
3742   }
3743   if (main_prot != NULL)
3744   {
3745     if (main_prot->location == NULL || main_prot->location->choice != SEQLOC_INT)
3746     {
3747       main_prot->location = SeqLocFree (main_prot->location);
3748       main_prot->location = SeqLocIntNew (0, pbsp1->length - 1, 
3749                                           Seq_strand_plus,
3750                                           SeqIdDup (pbsp1->id));
3751     }
3752     SetSeqLocPartial (main_prot->location, partial5_orig, partial3_new);
3753     main_prot->partial = (Boolean) (partial5_orig || partial3_new);
3754   }
3755 }
3756 
3757 static void FuseTwoProducts (SeqFeatPtr sfp1, SeqFeatPtr sfp2, Uint2 entityID)
3758 {
3759   BioseqPtr    pbsp1, pbsp2;
3760   CharPtr      pstr1, pstr2;
3761   ByteStorePtr byte_store, bs2 = NULL;
3762   Int4         old_length, added_length;
3763   SeqIdPtr     sip1;
3764   
3765   if (sfp1 == NULL || sfp2 == NULL 
3766       || sfp1->idx.subtype != FEATDEF_CDS
3767       || sfp2->idx.subtype != FEATDEF_CDS)
3768   {
3769     return;
3770   }
3771   pbsp1 = BioseqFindFromSeqLoc (sfp1->product);
3772   pbsp2 = BioseqFindFromSeqLoc (sfp2->product);
3773   
3774   if (pbsp1 == NULL)
3775   {
3776     sip1 = SeqLocId (sfp1->product);
3777     pbsp1 = BioseqFind (sip1);
3778     if (pbsp1 == NULL)
3779     {
3780       RetranslateOneCDS (sfp1, entityID, TRUE, FALSE);
3781       pbsp1 = BioseqFindFromSeqLoc (sfp1->product);
3782       if (pbsp1 == NULL)
3783       {
3784         sip1 = SeqLocId (sfp1->product);
3785         pbsp1 = BioseqFind (sip1);
3786       }
3787     }
3788   }
3789   if (pbsp1 == NULL)
3790   {
3791     return;
3792   }
3793   pstr1 = BSMerge ((ByteStorePtr)(pbsp1->seq_data), NULL);
3794   old_length = pbsp1->length;
3795   
3796   if (pbsp2 == NULL)
3797   {
3798     bs2 = ProteinFromCdRegionEx (sfp2, TRUE, FALSE);
3799     pstr2 = BSMerge (bs2, NULL);
3800     added_length = BSLen (bs2);
3801   }
3802   else
3803   {
3804     pstr2 = BSMerge ((ByteStorePtr)(pbsp2->seq_data), NULL);
3805     added_length = pbsp2->length;
3806   }
3807   
3808   byte_store = BSNew (old_length + added_length);
3809   if (byte_store != NULL)
3810   {
3811     BSWrite (byte_store, pstr1, StringLen (pstr1));
3812     BSWrite (byte_store, pstr2, StringLen (pstr2));
3813     pbsp1->seq_data = SeqDataFree (pbsp1->seq_data, pbsp1->seq_data_type);
3814     pbsp1->seq_data = (SeqDataPtr) byte_store;
3815     pbsp1->length += added_length;
3816       
3817     /* now copy features from the second protein to the first */
3818     CombineProductFeatures (pbsp1, pbsp2, old_length);     
3819       
3820     /* remove unused protein */
3821     if (pbsp2 != NULL)
3822     {
3823       pbsp2->idx.deleteme = TRUE;
3824     }
3825   }
3826   bs2 = BSFree (bs2);
3827 }
3828 
3829 static void FuseFeatureCallback (BioseqPtr bsp, Pointer userdata)
3830 {
3831   FuseFormPtr       ffp;
3832   SeqFeatPtr        first = NULL, sfp = NULL;
3833   SeqMgrFeatContext context;
3834   SeqLocPtr         slp;
3835   
3836   if (bsp == NULL || userdata == NULL)
3837   {
3838     return;
3839   }
3840   
3841   ffp = (FuseFormPtr) userdata;
3842   
3843   sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &context);
3844   while (sfp != NULL)
3845   {
3846     if (sfp->idx.subtype == ffp->subtype ||
3847            (ffp->subtype == FEATDEF_IMP &&
3848             IsRealImpFeat (sfp->idx.subtype))) 
3849     {
3850       if (first == NULL)
3851       {
3852         first = sfp;
3853       }
3854       else
3855       {
3856         slp = FuseTwoLocations (ffp->input_entityID, first->location, sfp->location);
3857         first->location = SeqLocFree (first->location);
3858         first->location = slp;
3859         first->partial = CheckSeqLocForPartial (slp, NULL, NULL);
3860         sfp->idx.deleteme = TRUE;
3861         if (sfp->idx.subtype == FEATDEF_CDS)
3862         {
3863           FuseTwoProducts (first, sfp, ffp->input_entityID);
3864         }
3865       }
3866     }
3867     sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &context);
3868   }  
3869 }
3870 
3871 
3872 static void DoFuseFeature (ButtoN b)
3873 
3874 {
3875   FuseFormPtr  ffp;
3876   SeqEntryPtr  sep;
3877   Int2         val;
3878   ValNodePtr   vnp;
3879 
3880   ffp = (FuseFormPtr) GetObjectExtra (b);
3881   if (ffp == NULL) return;
3882   sep = GetTopSeqEntryForEntityID (ffp->input_entityID);
3883   if (sep == NULL) return;
3884   Hide (ffp->form);
3885   WatchCursor ();
3886   Update ();
3887 
3888   vnp = NULL;
3889   val = GetValue (ffp->objlist);
3890   if (val > 0) {
3891     vnp = ffp->head;
3892     while (vnp != NULL && val > 1) {
3893       val--;
3894       vnp = vnp->next;
3895     }
3896   }
3897   if (vnp != NULL) {
3898     ffp->subtype = vnp->choice;
3899     VisitBioseqsInSep (sep, ffp, FuseFeatureCallback);
3900     DeleteMarkedObjects (ffp->input_entityID, 0, NULL);
3901   }
3902 
3903   ArrowCursor ();
3904   Update ();
3905   ObjMgrSetDirtyFlag (ffp->input_entityID, TRUE);
3906   ObjMgrSendMsg (OM_MSG_UPDATE, ffp->input_entityID, 0, 0);
3907   ObjMgrDeSelect (0, 0, 0, 0, NULL);
3908   Remove (ffp->form);
3909 }
3910 
3911 static void FuseMessageProc (ForM f, Int2 mssg)
3912 
3913 {
3914   FuseFormPtr  ffp;
3915 
3916   ffp = (FuseFormPtr) GetObjectExtra (f);
3917   if (ffp != NULL) {
3918     if (ffp->appmessage != NULL) {
3919       ffp->appmessage (f, mssg);
3920     }
3921   }
3922 }
3923 
3924 static void CleanupFusePage (GraphiC g, VoidPtr data)
3925 
3926 {
3927   FuseFormPtr  ffp;
3928 
3929   ffp = (FuseFormPtr) data;
3930   if (ffp != NULL) {
3931     ValNodeFreeData (ffp->head);
3932   }
3933   StdCleanupFormProc (g, data);
3934 }
3935 
3936 extern void FuseFeature (IteM i)
3937 
3938 {
3939   BaseFormPtr        bfp;
3940   ButtoN             b;
3941   GrouP              c;
3942   FeatDefPtr         curr;
3943   FuseFormPtr        ffp;
3944   GrouP              g;
3945   GrouP              h;
3946   ValNodePtr         head;
3947   Uint1              key;
3948   CharPtr            label = NULL;
3949   Int2               listHeight;
3950   SeqEntryPtr        sep;
3951   StdEditorProcsPtr  sepp;
3952   Uint1              subtype;
3953   ValNodePtr         vnp;
3954   WindoW             w;
3955 
3956 #ifdef WIN_MAC
3957   bfp = currentFormDataPtr;
3958 #else
3959   bfp = GetObjectExtra (i);
3960 #endif
3961   if (bfp == NULL) return;
3962   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
3963   if (sep == NULL) return;
3964   ffp = (FuseFormPtr) MemNew (sizeof (FuseFormData));
3965   if (ffp == NULL) return;
3966   w = FixedWindow (-50, -33, -10, -10, "Fuse Feature", StdCloseWindowProc);
3967   SetObjectExtra (w, ffp, CleanupFusePage);
3968   ffp->form = (ForM) w;
3969   ffp->formmessage = FuseMessageProc;
3970 
3971   sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
3972   if (sepp != NULL) {
3973     SetActivate (w, sepp->activateForm);
3974     ffp->appmessage = sepp->handleMessages;
3975   }
3976 
3977   ffp->input_entityID = bfp->input_entityID;
3978   ffp->input_itemID = bfp->input_itemID;
3979   ffp->input_itemtype = bfp->input_itemtype;
3980 
3981   h = HiddenGroup (w, -1, 0, NULL);
3982   SetGroupSpacing (h, 10, 10);
3983 
3984   g = HiddenGroup (h, 0, 2, NULL);
3985   StaticPrompt (g, "Feature", 0, 0, programFont, 'c');
3986   if (indexerVersion) {
3987     listHeight = 16;
3988   } else {
3989     listHeight = 8;
3990   }
3991   ffp->objlist = SingleList (g, 16, listHeight, NULL);
3992   head = NULL;
3993   curr = FeatDefFindNext (NULL, &key, &label, FEATDEF_ANY, TRUE);
3994   while (curr != NULL) {
3995     if (key != FEATDEF_BAD) {
3996       subtype = curr->featdef_key;
3997       if (subtype != FEATDEF_misc_RNA &&
3998           subtype != FEATDEF_precursor_RNA &&
3999           subtype != FEATDEF_mat_peptide &&
4000           subtype != FEATDEF_sig_peptide &&
4001           subtype != FEATDEF_transit_peptide &&
4002           subtype != FEATDEF_Imp_CDS &&
4003           !IsUnwantedFeatureType(subtype)) {
4004         vnp = ValNodeNew (head);
4005         if (head == NULL) {
4006           head = vnp;
4007         }
4008         if (vnp != NULL) {
4009           vnp->choice = subtype;
4010           vnp->data.ptrvalue = StringSave (curr->typelabel);
4011         }
4012       }
4013     }
4014     curr = FeatDefFindNext (curr, &key, &label, FEATDEF_ANY, TRUE);
4015   }
4016   if (head != NULL) {
4017     head = SortValNode (head, SortByVnpChoice);
4018     for (vnp = head; vnp != NULL; vnp = vnp->next) {
4019       ListItem (ffp->objlist, (CharPtr) vnp->data.ptrvalue);
4020     }
4021   }
4022   ffp->head = head;
4023 
4024   c = HiddenGroup (h, 4, 0, NULL);
4025   b = DefaultButton (c, "Accept", DoFuseFeature);
4026   SetObjectExtra (b, ffp, NULL);
4027   PushButton (c, "Cancel", StdCancelButtonProc);
4028 
4029   AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL);
4030   RealizeWindow (w);
4031   Show (w);
4032   Update ();
4033 }
4034 
4035 
4036 
4037 
4038 
4039 typedef struct genomeprojiduserdialog {
4040   DIALOG_MESSAGE_BLOCK
4041   DialoG        ids;
4042 } GenomeprojidUserDialog, PNTR GenomeprojidUserDialogPtr;
4043 
4044 typedef struct genomeprojiduserform {
4045   FEATURE_FORM_BLOCK
4046   SeqEntryPtr   sep;
4047 } GenomeprojidUserForm, PNTR GenomeprojidUserFormPtr;
4048 
4049 static void UserObjectPtrToGenomeprojidDialog (DialoG d, Pointer data)
4050 
4051 {
4052   Char                       buf [64];
4053   UserFieldPtr               curr;
4054   ValNodePtr                 head = NULL;
4055   ObjectIdPtr                oip;
4056   Int4                       parentID;
4057   Int4                       projectID;
4058   GenomeprojidUserDialogPtr  rdp;
4059   UserObjectPtr              uop;
4060   Int4                       val;
4061 
4062   rdp = (GenomeprojidUserDialogPtr) GetObjectExtra (d);
4063   if (rdp == NULL) return;
4064   uop = (UserObjectPtr) data;
4065   if (uop == NULL || uop->type == NULL || StringICmp (uop->type->str, "GenomeProjectsDB") != 0) {
4066     PointerToDialog (rdp->ids, NULL);
4067     return;
4068   }
4069   projectID = 0;
4070   parentID = 0;
4071   for (curr = uop->data; curr != NULL; curr = curr->next) {
4072     oip = curr->label;
4073     if (oip == NULL) continue;
4074     if (StringICmp (oip->str, "ProjectID") == 0) {
4075       if (curr->choice == 2) {
4076         val = (Int4) curr->data.intvalue;
4077         if (projectID > 0) {
4078           sprintf (buf, "%ld\t%ld", (long) projectID, (long) parentID);
4079           ValNodeCopyStr (&head, 0, buf);
4080           parentID = 0;
4081         }
4082         projectID = val;
4083       }
4084     } else if (StringICmp (oip->str, "ParentID") == 0) {
4085       if (curr->choice == 2) {
4086         val = (Int4) curr->data.intvalue;
4087         parentID = val;
4088       }
4089     }
4090   }
4091   if (projectID > 0) {
4092     sprintf (buf, "%ld\t%ld", (long) projectID, (long) parentID);
4093     ValNodeCopyStr (&head, 0, buf);
4094   }
4095 
4096   PointerToDialog (rdp->ids, (Pointer) head);
4097   ValNodeFreeData (head);
4098 }
4099 
4100 static Pointer GenomeprojidDialogToUserObjectPtr (DialoG d)
4101 
4102 {
4103   Char                       buf [64];
4104   ValNodePtr                 head;
4105   Int4                       parentID;
4106   Int4                       projectID;
4107   CharPtr                    ptr1;
4108   CharPtr                    ptr2;
4109   GenomeprojidUserDialogPtr  rdp;
4110   CharPtr                    str;
4111   UserObjectPtr              uop;
4112   long int                   val;
4113   ValNodePtr                 vnp;
4114 
4115   rdp = (GenomeprojidUserDialogPtr) GetObjectExtra (d);
4116   if (rdp == NULL) return NULL;
4117 
4118   uop = CreateGenomeProjectsDBUserObject ();
4119   if (uop == NULL) return NULL;
4120 
4121   head = (ValNodePtr) DialogToPointer (rdp->ids);
4122   if (head == NULL) return NULL;
4123 
4124   for (vnp = head; vnp != NULL; vnp = vnp->next) {
4125     projectID = 0;
4126     parentID = 0;
4127     str = (CharPtr) vnp->data.ptrvalue;
4128     if (StringHasNoText (str)) continue;
4129     StringNCpy_0 (buf, str, sizeof (buf));
4130     ptr1 = StringChr (buf, '\t');
4131     if (ptr1 != NULL) {
4132       *ptr1 = '\0';
4133       ptr1++;
4134       ptr2 = StringChr (ptr1, '\n');
4135       if (ptr2 == NULL) {
4136         ptr2 = StringChr (ptr1, '\t');
4137       }
4138       if (ptr2 != NULL) {
4139         *ptr2 = '\0';
4140       }
4141       if (sscanf (buf, "%ld", &val) == 1 && val > 0) {
4142         projectID = (Int4) val;
4143         if (sscanf (ptr1, "%ld", &val) == 1 && val > 0) {
4144           parentID = (Int4) val;
4145         }
4146         AddIDsToGenomeProjectsDBUserObject (uop, projectID, parentID);
4147       }
4148     }
4149   }
4150 
4151   ValNodeFreeData (head);
4152 
4153   return uop;
4154 }
4155 
4156 static void ValNodePtrToGenomeprojidDialog (DialoG d, Pointer data)
4157 
4158 {
4159   ValNodePtr   head;
4160   Int2         j;
4161   ValNodePtr   list;
4162   CharPtr      str;
4163   TagListPtr   tlp;
4164   ValNodePtr   vnp;
4165 
4166   tlp = (TagListPtr) GetObjectExtra (d);
4167   list = (ValNodePtr) data;
4168   if (tlp != NULL) {
4169     head = NULL;
4170     while (list != NULL) {
4171       vnp = ValNodeNew (head);
4172       if (head == NULL) {
4173         head = vnp;
4174       }
4175       if (vnp != NULL) {
4176         str = MemNew (StringLen ((CharPtr) list->data.ptrvalue) + 3);
4177         if (str != NULL) {
4178           StringCpy (str, (CharPtr) list->data.ptrvalue);
4179           StringCat (str, "\n");
4180         }
4181         vnp->data.ptrvalue = str;
4182       }
4183       list = list->next;
4184     }
4185     SendMessageToDialog (tlp->dialog, VIB_MSG_RESET);
4186     tlp->vnp = head;
4187     SendMessageToDialog (tlp->dialog, VIB_MSG_REDRAW);
4188     for (j = 0, vnp = tlp->vnp; vnp != NULL; j++, vnp = vnp->next) {
4189     }
4190     tlp->max = MAX ((Int2) 0, (Int2) (j - tlp->rows + 1));
4191     CorrectBarMax (tlp->bar, tlp->max);
4192     CorrectBarPage (tlp->bar, tlp->rows - 1, tlp->rows - 1);
4193   }
4194 }
4195 
4196 static Pointer GenomeprojidDialogToValNodePtr (DialoG d)
4197 
4198 {
4199   Char         ch;
4200   ValNodePtr   head;
4201   Int2         j;
4202   Int2         len;
4203   ValNodePtr   list;
4204   Boolean      okay;
4205   CharPtr      str;
4206   TagListPtr   tlp;
4207   ValNodePtr   vnp;
4208 
4209   head = NULL;
4210   tlp = (TagListPtr) GetObjectExtra (d);
4211   if (tlp != NULL && tlp->vnp != NULL) {
4212     list = NULL;
4213     for (vnp = tlp->vnp; vnp != NULL; vnp = vnp->next) {
4214       str = (CharPtr) vnp->data.ptrvalue;
4215       okay = FALSE;
4216       len = StringLen (str);
4217       for (j = 0; j < len; j++) {
4218         ch = str [j];
4219         if (ch != ' ' && ch != '\t' && ch != '\n') {
4220           okay = TRUE;
4221         }
4222       }
4223       if (okay) {
4224         list = ValNodeNew (list);
4225         if (head == NULL) {
4226           head = list;
4227         }
4228         if (list != NULL) {
4229           list->choice = 0;
4230           list->data.ptrvalue = StringSave (str);
4231         }
4232       }
4233     }
4234   }
4235   return (Pointer) head;
4236 }
4237 
4238 Uint2 genproj_types [] = {
4239   TAGLIST_TEXT, TAGLIST_TEXT
4240 };
4241 
4242 Uint2 genproj_widths [] = {
4243   10, 10, 0
4244 };
4245 
4246 static DialoG CreateGenomeProjectsDBDialog (GrouP g)
4247 
4248 {
4249   GrouP                      p;
4250   GenomeprojidUserDialogPtr  rdp;
4251   GrouP                      x;
4252   GrouP                      y;
4253 
4254   p = HiddenGroup (g, -1, 0, NULL);
4255   SetGroupSpacing (p, 10, 10);
4256 
4257   rdp = (GenomeprojidUserDialogPtr) MemNew (sizeof (GenomeprojidUserDialog));
4258   if (rdp == NULL) return NULL;
4259 
4260   SetObjectExtra (p, rdp, NULL);
4261   rdp->dialog = (DialoG) p;
4262   rdp->todialog = UserObjectPtrToGenomeprojidDialog;
4263   rdp->fromdialog = GenomeprojidDialogToUserObjectPtr;
4264 
4265   x = HiddenGroup (p, 0, 2, NULL);
4266   y = HiddenGroup (x, 3, 0, NULL);
4267   StaticPrompt (y, "Project ID", 10 * stdCharWidth, 0, programFont, 'c');
4268   StaticPrompt (y, "Parent ID", 10 * stdCharWidth, 0, programFont, 'c');
4269 
4270   rdp->ids = CreateTagListDialog (x, 3, 2, -1,
4271                                   genproj_types, genproj_widths, NULL,
4272                                   ValNodePtrToGenomeprojidDialog,
4273                                   GenomeprojidDialogToValNodePtr);
4274 
4275   return (DialoG) p;
4276 }
4277 
4278 static void GenomeProjectsDBUserFormMessage (ForM f, Int2 mssg)
4279 
4280 {
4281   GenomeprojidUserFormPtr  rfp;
4282 
4283   rfp = (GenomeprojidUserFormPtr) GetObjectExtra (f);
4284   if (rfp != NULL) {
4285     switch (mssg) {
4286       case VIB_MSG_CLOSE :
4287         Remove (f);
4288         break;
4289       case VIB_MSG_CUT :
4290         StdCutTextProc (NULL);
4291         break;
4292       case VIB_MSG_COPY :
4293         StdCopyTextProc (NULL);
4294         break;
4295       case VIB_MSG_PASTE :
4296         StdPasteTextProc (NULL);
4297         break;
4298       case VIB_MSG_DELETE :
4299         StdDeleteTextProc (NULL);
4300         break;
4301       default :
4302         if (rfp->appmessage != NULL) {
4303           rfp->appmessage (f, mssg);
4304         }
4305         break;
4306     }
4307   }
4308 }
4309 
4310 static ForM CreateGenomeProjectsDBDescForm (Int2 left, Int2 top, Int2 width,
4311                                            Int2 height, CharPtr title, ValNodePtr sdp,
4312                                            SeqEntryPtr sep, FormActnFunc actproc)
4313 
4314 {
4315   ButtoN                   b;
4316   GrouP                    c;
4317   GrouP                    g;
4318   GenomeprojidUserFormPtr  rfp;
4319   StdEditorProcsPtr        sepp;
4320   WindoW                   w;
4321 
4322   w = NULL;
4323   rfp = (GenomeprojidUserFormPtr) MemNew (sizeof (GenomeprojidUserForm));
4324   if (rfp != NULL) {
4325     w = FixedWindow (left, top, width, height, title, StdCloseWindowProc);
4326     SetObjectExtra (w, rfp, StdDescFormCleanupProc);
4327     rfp->form = (ForM) w;
4328     rfp->actproc = actproc;
4329     rfp->formmessage = GenomeProjectsDBUserFormMessage;
4330 
4331     rfp->sep = sep;
4332 
4333 #ifndef WIN_MAC
4334     CreateStdEditorFormMenus (w);
4335 #endif
4336     sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
4337     if (sepp != NULL) {
4338       SetActivate (w, sepp->activateForm);
4339       rfp->appmessage = sepp->handleMessages;
4340     }
4341 
4342     g = HiddenGroup (w, -1, 0, NULL);
4343     rfp->data = CreateGenomeProjectsDBDialog (g);
4344 
4345     c = HiddenGroup (w, 2, 0, NULL);
4346     b = DefaultButton (c, "Accept", StdAcceptFormButtonProc);
4347     SetObjectExtra (b, rfp, NULL);
4348     PushButton (c, "Cancel", StdCancelButtonProc);
4349     AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL);
4350     RealizeWindow (w);
4351   }
4352   return (ForM) w;
4353 }
4354 
4355 extern Int2 LIBCALLBACK GenomeProjectsDBUserGenFunc (Pointer data);
4356 extern Int2 LIBCALLBACK GenomeProjectsDBUserGenFunc (Pointer data)
4357 
4358 {
4359   ObjectIdPtr              oip;
4360   OMProcControlPtr         ompcp;
4361   OMUserDataPtr            omudp;
4362   ObjMgrProcPtr            proc;
4363   GenomeprojidUserFormPtr  rfp;
4364   ValNodePtr               sdp;
4365   SeqEntryPtr              sep;
4366   UserObjectPtr            uop;
4367   WindoW                   w;
4368 
4369   ompcp = (OMProcControlPtr) data;
4370   w = NULL;
4371   sdp = NULL;
4372   sep = NULL;
4373   uop = NULL;
4374   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
4375   proc = ompcp->proc;
4376   switch (ompcp->input_itemtype) {
4377     case OBJ_SEQDESC :
4378       sdp = (ValNodePtr) ompcp->input_data;
4379       if (sdp != NULL && sdp->choice != Seq_descr_user) {
4380         return OM_MSG_RET_ERROR;
4381       }
4382       uop = (UserObjectPtr) sdp->data.ptrvalue;
4383       break;
4384     case OBJ_BIOSEQ :
4385       break;
4386     case OBJ_BIOSEQSET :
4387       break;
4388     case 0 :
4389       break;
4390     default :
4391       return OM_MSG_RET_ERROR;
4392   }
4393   omudp = ItemAlreadyHasEditor (ompcp->input_entityID, ompcp->input_itemID,
4394                                 ompcp->input_itemtype, ompcp->proc->procid);
4395   if (omudp != NULL) {
4396     if (StringCmp (proc->procname, "Edit GenomeProjectsDB User Desc") == 0) {
4397       rfp = (GenomeprojidUserFormPtr) omudp->userdata.ptrvalue;
4398       if (rfp != NULL) {
4399         Select (rfp->form);
4400       }
4401       return OM_MSG_RET_DONE;
4402     } else {
4403       return OM_MSG_RET_OK; /* not this type, check next registered user object editor */
4404     }
4405   }
4406   if (uop != NULL) {
4407     oip = uop->type;
4408     if (oip == NULL || oip->str == NULL) return OM_MSG_RET_OK;
4409     if (StringCmp (oip->str, "GenomeProjectsDB") != 0) return OM_MSG_RET_OK;
4410   }
4411   sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
4412   w = (WindoW) CreateGenomeProjectsDBDescForm (-50, -33, -10, -10,
4413                                                "Genome Projects DB", sdp, sep,
4414                                                StdDescFormActnProc);
4415   rfp = (GenomeprojidUserFormPtr) GetObjectExtra (w);
4416   if (rfp != NULL) {
4417     rfp->input_entityID = ompcp->input_entityID;
4418     rfp->input_itemID = ompcp->input_itemID;
4419     rfp->input_itemtype = ompcp->input_itemtype;
4420     rfp->this_itemtype = OBJ_SEQDESC;
4421     rfp->this_subtype = Seq_descr_user;
4422     rfp->procid = ompcp->proc->procid;
4423     rfp->proctype = ompcp->proc->proctype;
4424     rfp->userkey = OMGetNextUserKey ();
4425     omudp = ObjMgrAddUserData (ompcp->input_entityID, ompcp->proc->procid,
4426                                    OMPROC_EDIT, rfp->userkey);
4427     if (omudp != NULL) {
4428       omudp->userdata.ptrvalue = (Pointer) rfp;
4429       omudp->messagefunc = StdVibrantEditorMsgFunc;
4430     }
4431     SendMessageToForm (rfp->form, VIB_MSG_INIT);
4432     if (sdp != NULL) {
4433       PointerToDialog (rfp->data, (Pointer) sdp->data.ptrvalue);
4434       SetClosestParentIfDuplicating ((BaseFormPtr) rfp);
4435     }
4436   }
4437   Show (w);
4438   Select (w);
4439   return OM_MSG_RET_DONE;
4440 }
4441 
4442 
4443 typedef struct dblinkdialog {
4444   DIALOG_MESSAGE_BLOCK
4445   DialoG  traceassm;
4446   DialoG  biosample;
4447   DialoG  probedb;
4448 } DblinkDialog, PNTR DblinkDialogPtr;
4449 
4450 typedef struct dblinkform {
4451   FEATURE_FORM_BLOCK
4452   SeqEntryPtr   sep;
4453 } DblinkForm, PNTR DblinkFormPtr;
4454 
4455 static void UserObjectPtrToDblinkDialog (
4456   DialoG d,
4457   Pointer data
4458 )
4459 
4460 {
4461   Char             buf [32];
4462   CharPtr PNTR     cpp;
4463   UserFieldPtr     curr;
4464   DblinkDialogPtr  ddp;
4465   ValNodePtr       head;
4466   Int4             i, val;
4467   Int4Ptr          ip;
4468   Int4             num;
4469   ObjectIdPtr      oip;
4470   CharPtr          str;
4471   UserObjectPtr    uop;
4472  
4473   ddp = (DblinkDialogPtr) GetObjectExtra (d);
4474   if (ddp == NULL) return;
4475 
4476   uop = (UserObjectPtr) data;
4477   if (uop == NULL || uop->type == NULL || StringICmp (uop->type->str, "DBLink") != 0) {
4478     PointerToDialog (ddp->traceassm, NULL);
4479     PointerToDialog (ddp->biosample, NULL);
4480     PointerToDialog (ddp->probedb, NULL);
4481     return;
4482   }
4483 
4484   for (curr = uop->data; curr != NULL; curr = curr->next) {
4485     oip = curr->label;
4486     if (oip == NULL) continue;
4487     if (StringICmp (oip->str, "Trace Assembly Archive") == 0) {
4488       if (curr->choice == 8) {
4489         num = curr->num;
4490         ip = (Int4Ptr) curr->data.ptrvalue;
4491         if (num > 0 && ip != NULL) {
4492           head = NULL;
4493           for (i = 0; i < num; i++) {
4494             val = ip [i];
4495             if (val > 0) {
4496               sprintf (buf, "%ld", (long) val);
4497               ValNodeCopyStr (&head, 0, buf);
4498             }
4499           }
4500           if (head != NULL) {
4501             PointerToDialog (ddp->traceassm, (Pointer) head);
4502           }
4503           head = ValNodeFreeData (head);
4504         }
4505       }
4506     } else if (StringICmp (oip->str, "Bio Sample") == 0) {
4507       if (curr->choice == 7) {
4508         num = curr->num;
4509         cpp = (CharPtr PNTR) curr->data.ptrvalue;
4510         if (num > 0 && cpp != NULL) {
4511           head = NULL;
4512           for (i = 0; i < num; i++) {
4513             str = cpp [i];
4514             if (StringDoesHaveText (str)) {
4515               ValNodeCopyStr (&head, 0, str);
4516             }
4517           }
4518           if (head != NULL) {
4519             PointerToDialog (ddp->biosample, (Pointer) head);
4520           }
4521           head = ValNodeFreeData (head);
4522         }
4523       }
4524     } else if (StringICmp (oip->str, "ProbeDB") == 0) {
4525       if (curr->choice == 7) {
4526         num = curr->num;
4527         cpp = (CharPtr PNTR) curr->data.ptrvalue;
4528         if (num > 0 && cpp != NULL) {
4529           head = NULL;
4530           for (i = 0; i < num; i++) {
4531             str = cpp [i];
4532             if (StringDoesHaveText (str)) {
4533               ValNodeCopyStr (&head, 0, str);
4534             }
4535           }
4536           if (head != NULL) {
4537             PointerToDialog (ddp->probedb, (Pointer) head);
4538           }
4539           head = ValNodeFreeData (head);
4540         }
4541       }
4542     }
4543   }
4544 }
4545 
4546 static Pointer DblinkDialogToUserObjectPtr (
4547   DialoG d
4548 )
4549 
4550 {
4551   CharPtr PNTR     cpp;
4552   DblinkDialogPtr  ddp;
4553   ValNodePtr       head, vnp;
4554   Int4             i, num;
4555   Int4Ptr          ipp;
4556   Boolean          okay = FALSE;
4557   CharPtr          str;
4558   UserObjectPtr    uop;
4559   long int         val;
4560 
4561   ddp = (DblinkDialogPtr) GetObjectExtra (d);
4562   if (ddp == NULL) return NULL;
4563 
4564   uop = CreateDBLinkUserObject ();
4565   if (uop == NULL) return NULL;
4566 
4567   head = (ValNodePtr) DialogToPointer (ddp->traceassm);
4568   if (head != NULL) {
4569     num = 0;
4570     for (vnp = head; vnp != NULL; vnp = vnp->next) {
4571       str = (CharPtr) vnp->data.ptrvalue;
4572       if (StringHasNoText (str)) continue;
4573       num++;
4574     }
4575     if (num > 0) {
4576       ipp = (Int4Ptr) MemNew (sizeof (Int4) * num);
4577       if (ipp != NULL) {
4578         i = 0;
4579         for (vnp = head; vnp != NULL; vnp = vnp->next) {
4580           str = (CharPtr) vnp->data.ptrvalue;
4581           if (StringHasNoText (str)) continue;
4582           if (sscanf (str, "%ld", &val) == 1) {
4583             ipp [i] = (Int4) val;
4584             i++;
4585           }
4586         }
4587         if (i > 0) {
4588           AddTraceAssemblyIDsToDBLinkUserObject (uop, i, ipp);
4589           okay = TRUE;
4590         }
4591       }
4592     }
4593   }
4594   ValNodeFreeData (head);
4595 
4596   head = (ValNodePtr) DialogToPointer (ddp->biosample);
4597   if (head != NULL) {
4598     num = 0;
4599     for (vnp = head; vnp != NULL; vnp = vnp->next) {
4600       str = (CharPtr) vnp->data.ptrvalue;
4601       if (StringHasNoText (str)) continue;
4602       num++;
4603     }
4604     if (num > 0) {
4605       cpp = (CharPtr PNTR) MemNew (sizeof (CharPtr) * num);
4606       if (cpp != NULL) {
4607         i = 0;
4608         for (vnp = head; vnp != NULL; vnp = vnp->next) {
4609           str = (CharPtr) vnp->data.ptrvalue;
4610           if (StringHasNoText (str)) continue;
4611           cpp [i] = str;
4612           i++;
4613         }
4614         if (i > 0) {
4615           AddBioSampleIDsToDBLinkUserObject (uop, i, cpp);
4616           okay = TRUE;
4617         }
4618       }
4619     }
4620   }
4621   ValNodeFreeData (head);
4622 
4623   head = (ValNodePtr) DialogToPointer (ddp->probedb);
4624   if (head != NULL) {
4625     num = 0;
4626     for (vnp = head; vnp != NULL; vnp = vnp->next) {
4627       str = (CharPtr) vnp->data.ptrvalue;
4628       if (StringHasNoText (str)) continue;
4629       num++;
4630     }
4631     if (num > 0) {
4632       cpp = (CharPtr PNTR) MemNew (sizeof (CharPtr) * num);
4633       if (cpp != NULL) {
4634         i = 0;
4635         for (vnp = head; vnp != NULL; vnp = vnp->next) {
4636           str = (CharPtr) vnp->data.ptrvalue;
4637           if (StringHasNoText (str)) continue;
4638           cpp [i] = str;
4639           i++;
4640         }
4641         if (i > 0) {
4642           AddProbeDBIDsToDBLinkUserObject (uop, i, cpp);
4643           okay = TRUE;
4644         }
4645       }
4646     }
4647   }
4648   ValNodeFreeData (head);
4649 
4650   if (! okay) {
4651     uop = UserObjectFree (uop);
4652   }
4653 
4654   return uop;
4655 }
4656 
4657 static DialoG CreateDblinkDialog (
4658   GrouP g
4659 )
4660 
4661 {
4662   DblinkDialogPtr  ddp;
4663   GrouP            p, x;
4664 
4665   p = HiddenGroup (g, -1, 0, NULL);
4666   SetGroupSpacing (p, 10, 10);
4667 
4668   ddp = (DblinkDialogPtr) MemNew (sizeof (DblinkDialog));
4669   if (ddp == NULL) return NULL;
4670 
4671   SetObjectExtra (p, ddp, NULL);
4672   ddp->dialog = (DialoG) p;
4673   ddp->todialog = UserObjectPtrToDblinkDialog;
4674   ddp->fromdialog = DblinkDialogToUserObjectPtr;
4675 
4676   x = HiddenGroup (p, 0, 8, NULL);
4677 
4678   StaticPrompt (x, "Trace Assembly", 10 * stdCharWidth, 0, programFont, 'c');
4679   ddp->traceassm = CreateVisibleStringDialog (x, 3, -1, 15);
4680 
4681   StaticPrompt (x, "Bio Sample", 10 * stdCharWidth, 0, programFont, 'c');
4682   ddp->biosample = CreateVisibleStringDialog (x, 3, -1, 15);
4683 
4684   StaticPrompt (x, "ProbeDB", 10 * stdCharWidth, 0, programFont, 'c');
4685   ddp->probedb = CreateVisibleStringDialog (x, 3, -1, 15);
4686 
4687   return (DialoG) p;
4688 }
4689 
4690 static void DblinkFormMessage (
4691   ForM f,
4692   Int2 mssg
4693 )
4694 
4695 {
4696   DblinkFormPtr  dfp;
4697 
4698   dfp = (DblinkFormPtr) GetObjectExtra (f);
4699   if (dfp != NULL) {
4700     switch (mssg) {
4701       case VIB_MSG_CLOSE :
4702         Remove (f);
4703         break;
4704       case VIB_MSG_CUT :
4705         StdCutTextProc (NULL);
4706         break;
4707       case VIB_MSG_COPY :
4708         StdCopyTextProc (NULL);
4709         break;
4710       case VIB_MSG_PASTE :
4711         StdPasteTextProc (NULL);
4712         break;
4713       case VIB_MSG_DELETE :
4714         StdDeleteTextProc (NULL);
4715         break;
4716       default :
4717         if (dfp->appmessage != NULL) {
4718           dfp->appmessage (f, mssg);
4719         }
4720         break;
4721     }
4722   }
4723 }
4724 
4725 static ForM CreateDblinkDescForm (
4726   Int2 left,
4727   Int2 top,
4728   Int2 width,
4729   Int2 height,
4730   CharPtr title,
4731   ValNodePtr sdp,
4732   SeqEntryPtr sep,
4733   FormActnFunc actproc
4734 )
4735 
4736 {
4737   ButtoN             b;
4738   DblinkFormPtr      dfp;
4739   GrouP              c, g;
4740   StdEditorProcsPtr  sepp;
4741   WindoW             w;
4742 
4743   w = NULL;
4744   dfp = (DblinkFormPtr) MemNew (sizeof (DblinkForm));
4745 
4746   if (dfp != NULL) {
4747     w = FixedWindow (left, top, width, height, title, StdCloseWindowProc);
4748     SetObjectExtra (w, dfp, StdDescFormCleanupProc);
4749     dfp->form = (ForM) w;
4750     dfp->actproc = actproc;
4751     dfp->formmessage = DblinkFormMessage;
4752 
4753     dfp->sep = sep;
4754 
4755 #ifndef WIN_MAC
4756     CreateStdEditorFormMenus (w);
4757 #endif
4758     sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
4759     if (sepp != NULL) {
4760       SetActivate (w, sepp->activateForm);
4761       dfp->appmessage = sepp->handleMessages;
4762     }
4763 
4764     g = HiddenGroup (w, -1, 0, NULL);
4765     dfp->data = CreateDblinkDialog (g);
4766 
4767     c = HiddenGroup (w, 2, 0, NULL);
4768     b = DefaultButton (c, "Accept", StdAcceptFormButtonProc);
4769     SetObjectExtra (b, dfp, NULL);
4770     PushButton (c, "Cancel", StdCancelButtonProc);
4771     AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL);
4772     RealizeWindow (w);
4773   }
4774 
4775   return (ForM) w;
4776 }
4777 
4778 extern Int2 LIBCALLBACK DBlinkUserGenFunc (Pointer data);
4779 extern Int2 LIBCALLBACK DBlinkUserGenFunc (Pointer data)
4780 
4781 {
4782   ObjectIdPtr              oip;
4783   OMProcControlPtr         ompcp;
4784   OMUserDataPtr            omudp;
4785   ObjMgrProcPtr            proc;
4786   DblinkFormPtr            dfp;
4787   ValNodePtr               sdp;
4788   SeqEntryPtr              sep;
4789   UserObjectPtr            uop;
4790   WindoW                   w;
4791 
4792   ompcp = (OMProcControlPtr) data;
4793   w = NULL;
4794   sdp = NULL;
4795   sep = NULL;
4796   uop = NULL;
4797   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
4798   proc = ompcp->proc;
4799   switch (ompcp->input_itemtype) {
4800     case OBJ_SEQDESC :
4801       sdp = (ValNodePtr) ompcp->input_data;
4802       if (sdp != NULL && sdp->choice != Seq_descr_user) {
4803         return OM_MSG_RET_ERROR;
4804       }
4805       uop = (UserObjectPtr) sdp->data.ptrvalue;
4806       break;
4807     case OBJ_BIOSEQ :
4808       break;
4809     case OBJ_BIOSEQSET :
4810       break;
4811     case 0 :
4812       break;
4813     default :
4814       return OM_MSG_RET_ERROR;
4815   }
4816   omudp = ItemAlreadyHasEditor (ompcp->input_entityID, ompcp->input_itemID,
4817                                 ompcp->input_itemtype, ompcp->proc->procid);
4818   if (omudp != NULL) {
4819     if (StringCmp (proc->procname, "Edit DBLink User Desc") == 0) {
4820       dfp = (DblinkFormPtr) omudp->userdata.ptrvalue;
4821       if (dfp != NULL) {
4822         Select (dfp->form);
4823       }
4824       return OM_MSG_RET_DONE;
4825     } else {
4826       return OM_MSG_RET_OK; /* not this type, check next registered user object editor */
4827     }
4828   }
4829   if (uop != NULL) {
4830     oip = uop->type;
4831     if (oip == NULL || oip->str == NULL) return OM_MSG_RET_OK;
4832     if (StringCmp (oip->str, "DBLink") != 0) return OM_MSG_RET_OK;
4833   }
4834   sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
4835   w = (WindoW) CreateDblinkDescForm (-50, -33, -10, -10,
4836                                      "DBLink", sdp, sep,
4837                                      StdDescFormActnProc);
4838   dfp = (DblinkFormPtr) GetObjectExtra (w);
4839   if (dfp != NULL) {
4840     dfp->input_entityID = ompcp->input_entityID;
4841     dfp->input_itemID = ompcp->input_itemID;
4842     dfp->input_itemtype = ompcp->input_itemtype;
4843     dfp->this_itemtype = OBJ_SEQDESC;
4844     dfp->this_subtype = Seq_descr_user;
4845     dfp->procid = ompcp->proc->procid;
4846     dfp->proctype = ompcp->proc->proctype;
4847     dfp->userkey = OMGetNextUserKey ();
4848     omudp = ObjMgrAddUserData (ompcp->input_entityID, ompcp->proc->procid,
4849                                    OMPROC_EDIT, dfp->userkey);
4850     if (omudp != NULL) {
4851       omudp->userdata.ptrvalue = (Pointer) dfp;
4852       omudp->messagefunc = StdVibrantEditorMsgFunc;
4853     }
4854     SendMessageToForm (dfp->form, VIB_MSG_INIT);
4855     if (sdp != NULL) {
4856       PointerToDialog (dfp->data, (Pointer) sdp->data.ptrvalue);
4857       SetClosestParentIfDuplicating ((BaseFormPtr) dfp);
4858     }
4859   }
4860   Show (w);
4861   Select (w);
4862   return OM_MSG_RET_DONE;
4863 }
4864 
4865 
4866 extern Int2 LIBCALLBACK RefGeneUserGenFunc (Pointer data);
4867 
4868 #define REFGENE_ASSEMBLY   1
4869 #define REFGENE_RELATED    2
4870 #define REFGENE_SPLICEVAR  3
4871 #define REFGENE_RELDREK    4
4872 #define REFGENE_REJECT     5
4873 #define REFGENE_IDENTICAL  6
4874 #define REFGENE_UNKNOWN    7
4875 
4876 typedef struct refgeneuserdialog {
4877   DIALOG_MESSAGE_BLOCK
4878   GrouP         status;
4879   ButtoN        generated;
4880   TexT          curator;
4881   TexT          url;
4882   TexT          source;
4883   Int2          indexer;
4884   DialoG        fields;
4885   ButtoN        pipebtn;
4886 } RefgeneUserDialog, PNTR RefgeneUserDialogPtr;
4887 
4888 typedef struct refgeneuserform {
4889   FEATURE_FORM_BLOCK
4890   SeqEntryPtr   sep;
4891 } RefgeneUserForm, PNTR RefgeneUserFormPtr;
4892 
4893 static ENUM_ALIST(refgene_alist)
4894   {" ",          0},
4895   {"Assembly",    REFGENE_ASSEMBLY},
4896   {"Related",     REFGENE_RELATED},
4897   {"SpliceVar",   REFGENE_SPLICEVAR},
4898   {"RelatedDrek", REFGENE_RELDREK},
4899   {"Reject",      REFGENE_REJECT},
4900   {"Identical",   REFGENE_IDENTICAL},
4901   {"Unknown",     REFGENE_UNKNOWN},
4902 END_ENUM_ALIST
4903 
4904 static Uint2 refgene_types [] = {
4905   TAGLIST_TEXT, TAGLIST_TEXT, TAGLIST_TEXT, TAGLIST_TEXT, TAGLIST_TEXT, TAGLIST_POPUP
4906 };
4907 
4908 static Uint2 refgene_widths [] = {
4909   9, 7, 7, 7, 8, 0
4910 };
4911 
4912 static EnumFieldAssocPtr refgene_popups [] = {
4913   NULL, NULL, NULL, NULL, NULL, refgene_alist
4914 };
4915 
4916 static CharPtr refgene_labels [] = {
4917   "", "Assembly", "Related", "SpliceVar", "RelatedDrek", "Reject", "IdenticalTo", "Unknown", NULL
4918 };
4919 
4920 static CharPtr refgene_fields [] = {
4921   "Accession", "GI", "Start", "Stop", "Comment", "Type", NULL
4922 };
4923 
4924 static void AccessionUserFieldPtrToVisStringDialog (DialoG d, Pointer data)
4925 
4926 {
4927   CharPtr       accession;
4928   CharPtr       comment;
4929   UserFieldPtr  curr;
4930   UserFieldPtr  entry;
4931   Int2          field;
4932   Char          fm [16];
4933   Int4          from;
4934   Int4          gi;
4935   ValNodePtr    head;
4936   Int2          i;
4937   Int2          j;
4938   CharPtr       name;
4939   ObjectIdPtr   oip;
4940   CharPtr       str;
4941   TagListPtr    tlp;
4942   Int4          to;
4943   Char          tu [16];
4944   UserFieldPtr  ufp;
4945   ValNodePtr    vnp;
4946 
4947   tlp = (TagListPtr) GetObjectExtra (d);
4948   if (tlp == NULL) return;
4949   str = MemNew (sizeof (Char) * 1024);
4950   head = NULL;
4951   curr = (UserFieldPtr) data;
4952   while (curr != NULL) {
4953     oip = curr->label;
4954     if (oip != NULL) {
4955       field = 0;
4956       for (i = REFGENE_ASSEMBLY; i <= REFGENE_UNKNOWN; i++) {
4957         if (StringICmp (oip->str, refgene_labels [i]) == 0 && curr->choice == 11) {
4958           field = i;
4959         }
4960       }
4961       if (field > 0) {
4962         entry = (UserFieldPtr) curr->data.ptrvalue;
4963         while (entry != NULL && entry->choice == 11) {
4964           accession = NULL;
4965           comment = NULL;
4966           name = NULL;
4967           gi = 0;
4968           from = 0;
4969           to = 0;
4970           ufp = (UserFieldPtr) entry->data.ptrvalue;
4971           while (ufp != NULL) {
4972             oip = ufp->label;
4973             if (oip != NULL && oip->str != NULL) {
4974               if (StringICmp (oip->str, "accession") == 0 && ufp->choice == 1) {
4975                 accession = (CharPtr) ufp->data.ptrvalue;
4976               } else if (StringICmp (oip->str, "gi") == 0 && ufp->choice == 2) {
4977                 gi = ufp->data.intvalue;
4978               } else if (StringICmp (oip->str, "from") == 0 && ufp->choice == 2) {
4979                 from = ufp->data.intvalue;
4980               } else if (StringICmp (oip->str, "to") == 0 && ufp->choice == 2) {
4981                 to = ufp->data.intvalue;
4982               } else if (StringICmp (oip->str, "comment") == 0 && ufp->choice == 1) {
4983                 comment = (CharPtr) ufp->data.ptrvalue;
4984               } else if (StringICmp (oip->str, "name") == 0 && ufp->choice == 1) {
4985                 name = (CharPtr) ufp->data.ptrvalue;
4986               }
4987             }
4988             ufp = ufp->next;
4989           }
4990           if (accession != NULL) {
4991             if (comment == NULL) {
4992               comment = "";
4993             }
4994             fm [0] = '\0';
4995             tu [0] = '\0';
4996             if (from > 0 && to > 0) {
4997               sprintf (fm, "%ld", (long) from);
4998               sprintf (tu, "%ld", (long) to);
4999             }
5000             sprintf (str, "%s\t%ld\t%s\t%s\t%s\t%d\n", accession,
5001                      (long) gi, fm, tu, comment, (int) field);
5002             vnp = ValNodeNew (head);
5003             if (head == NULL) {
5004               head = vnp;
5005             }
5006             if (vnp != NULL) {
5007               vnp->data.ptrvalue = StringSave (str);
5008             }
5009           } else if (name != NULL) {
5010             sprintf (str, "\t\t\t\t%s\t%d\n", name, (int) field);
5011             vnp = ValNodeNew (head);
5012             if (head == NULL) {
5013               head = vnp;
5014             }
5015             if (vnp != NULL) {
5016               vnp->data.ptrvalue = StringSave (str);
5017             }
5018           }
5019           entry = entry->next;
5020         }
5021       }
5022     }
5023     curr = curr->next;
5024   }
5025   MemFree (str);
5026   SendMessageToDialog (tlp->dialog, VIB_MSG_RESET);
5027   tlp->vnp = head;
5028   SendMessageToDialog (tlp->dialog, VIB_MSG_REDRAW);
5029   for (j = 0, vnp = tlp->vnp; vnp != NULL; j++, vnp = vnp->next) {
5030   }
5031   tlp->max = MAX ((Int2) 0, (Int2) (j - tlp->rows + 1));
5032   CorrectBarMax (tlp->bar, tlp->max);
5033   CorrectBarPage (tlp->bar, tlp->rows - 1, tlp->rows - 1);
5034 }
5035 
5036 static Pointer VisStringDialogToUserFieldPtr (DialoG d)
5037 
5038 {
5039   return NULL;
5040 }
5041 
5042 static void UserObjectPtrToRefGeneDialog (DialoG d, Pointer data)
5043 
5044 {
5045   UserFieldPtr          curr;
5046   Boolean               gen;
5047   ObjectIdPtr           oip;
5048   RefgeneUserDialogPtr  rdp;
5049   Int2                  status = 0;
5050   CharPtr               str;
5051   UserObjectPtr         uop;
5052 
5053   rdp = (RefgeneUserDialogPtr) GetObjectExtra (d);
5054   if (rdp == NULL) return;
5055   uop = (UserObjectPtr) data;
5056   if (uop == NULL || uop->type == NULL || StringICmp (uop->type->str, "RefGeneTracking") != 0) {
5057     SetValue (rdp->status, 0);
5058     PointerToDialog (rdp->fields, NULL);
5059     return;
5060   }
5061   PointerToDialog (rdp->fields, uop->data);
5062   for (curr = uop->data; curr != NULL; curr = curr->next) {
5063     oip = curr->label;
5064     if (oip != NULL && StringICmp (oip->str, "Status") == 0) {
5065       break;
5066     }
5067   }
5068   if (curr != NULL && curr->choice == 1) {
5069     str = (CharPtr) curr->data.ptrvalue;
5070     if (StringICmp (str, "Inferred") == 0) {
5071       status = 1;
5072     } else if (StringICmp (str, "Predicted") == 0) {
5073       status = 2;
5074     } else if (StringICmp (str, "Provisional") == 0) {
5075       status = 3;
5076     } else if (StringICmp (str, "Validated") == 0) {
5077       status = 4;
5078     } else if (StringICmp (str, "Reviewed") == 0) {
5079       status = 5;
5080     } else if (StringICmp (str, "Model") == 0) {
5081       status = 6;
5082     } else if (StringICmp (str, "WGS") == 0) {
5083       status = 7;
5084     } else if (StringICmp (str, "Pipeline") == 0) {
5085       status = 8;
5086       SafeEnable (rdp->pipebtn);
5087     }
5088   }
5089   for (curr = uop->data; curr != NULL; curr = curr->next) {
5090     oip = curr->label;
5091     if (oip != NULL && StringICmp (oip->str, "Generated") == 0) {
5092       break;
5093     }
5094   }
5095   if (curr != NULL && curr->choice == 4) {
5096     gen = curr->data.boolvalue;
5097     SetStatus (rdp->generated, gen);
5098   }
5099   for (curr = uop->data; curr != NULL; curr = curr->next) {
5100     oip = curr->label;
5101     if (oip != NULL && StringICmp (oip->str, "Collaborator") == 0) {
5102       break;
5103     }
5104   }
5105   if (curr != NULL && curr->choice == 1) {
5106     str = (CharPtr) curr->data.ptrvalue;
5107     SetTitle (rdp->curator, str);
5108   }
5109 
5110   for (curr = uop->data; curr != NULL; curr = curr->next) {
5111     oip = curr->label;
5112     if (oip != NULL && StringICmp (oip->str, "CollaboratorURL") == 0) {
5113       break;
5114     }
5115   }
5116   if (curr != NULL && curr->choice == 1) {
5117     str = (CharPtr) curr->data.ptrvalue;
5118     SetTitle (rdp->url, str);
5119   }
5120 
5121   for (curr = uop->data; curr != NULL; curr = curr->next) {
5122     oip = curr->label;
5123     if (oip != NULL && StringICmp (oip->str, "GenomicSource") == 0) {
5124       break;
5125     }
5126   }
5127   if (curr != NULL && curr->choice == 1) {
5128     str = (CharPtr) curr->data.ptrvalue;
5129     SetTitle (rdp->source, str);
5130   }
5131   SetValue (rdp->status, status);
5132   for (curr = uop->data; curr != NULL; curr = curr->next) {
5133     oip = curr->label;
5134     if (oip != NULL && StringICmp (oip->str, "Indexer") == 0) {
5135       break;
5136     }
5137   }
5138   if (curr != NULL && curr->choice == 2) {
5139     rdp->indexer = (Int2) curr->data.intvalue;
5140   }
5141 }
5142 
5143 static void AddIndexerToRefGeneTrackUserObject (UserObjectPtr uop, Int2 indexer)
5144 
5145 {
5146   UserFieldPtr  curr;
5147   ObjectIdPtr   oip;
5148 
5149   if (uop == NULL || indexer < 1) return;
5150   oip = uop->type;
5151   if (oip == NULL || StringICmp (oip->str, "RefGeneTracking") != 0) return;
5152 
5153   for (curr = uop->data; curr != NULL; curr = curr->next) {
5154     oip = curr->label;
5155     if (oip != NULL && StringICmp (oip->str, "Indexer") == 0) {
5156       break;
5157     }
5158   }
5159 
5160   if (curr == NULL) {
5161     curr = UserFieldNew ();
5162     oip = ObjectIdNew ();
5163     oip->str = StringSave ("Indexer");
5164     curr->label = oip;
5165     curr->choice = 2; /* integer */
5166 
5167     /* link indexer at beginning of list */
5168 
5169     curr->next = uop->data;
5170     uop->data = curr;
5171   }
5172 
5173   if (curr == NULL || curr->choice != 2) return;
5174 
5175   /* replace any existing indexer indication */
5176 
5177   curr->data.intvalue = (Int4) indexer;
5178 }
5179 
5180 static Pointer RefGeneDialogToUserObjectPtr (DialoG d)
5181 
5182 {
5183   Char                  ch;
5184   Char                  curator [256];
5185   Int2                  i;
5186   Uint2                 j;
5187   size_t                len;
5188   Int4                  num [6];
5189   Boolean               okay;
5190   RefgeneUserDialogPtr  rdp;
5191   Char                  source [64];
5192   Int2                  status;
5193   CharPtr               str;
5194   TagListPtr            tlp;
5195   CharPtr               txt [6];
5196   UserObjectPtr         uop;
5197   Char                  url [512];
5198   long int              val;
5199   ValNodePtr            vnp;
5200 
5201   rdp = (RefgeneUserDialogPtr) GetObjectExtra (d);
5202   if (rdp == NULL) return NULL;
5203 
5204   uop = CreateRefGeneTrackUserObject ();
5205   if (uop == NULL) return NULL;
5206 
5207   status = GetValue (rdp->status);
5208   if (status == 1) {
5209     AddStatusToRefGeneTrackUserObject (uop, "Inferred");
5210   } else if (status == 2) {
5211     AddStatusToRefGeneTrackUserObject (uop, "Predicted");
5212   } else if (status == 3) {
5213     AddStatusToRefGeneTrackUserObject (uop, "Provisional");
5214   } else if (status == 4) {
5215     AddStatusToRefGeneTrackUserObject (uop, "Validated");
5216   } else if (status == 5) {
5217     AddStatusToRefGeneTrackUserObject (uop, "Reviewed");
5218   } else if (status == 6) {
5219     AddStatusToRefGeneTrackUserObject (uop, "Model");
5220   } else if (status == 7) {
5221     AddStatusToRefGeneTrackUserObject (uop, "WGS");
5222   } else if (status == 8) {
5223     AddStatusToRefGeneTrackUserObject (uop, "Pipeline");
5224   }
5225 
5226   GetTitle (rdp->source, source, sizeof (source));
5227   if (! StringHasNoText (source)) {
5228     AddSourceToRefGeneTrackUserObject (uop, source);
5229   }
5230 
5231   if (GetStatus (rdp->generated)) {
5232     AddGeneratedToRefGeneTrackUserObject (uop, TRUE);
5233   }
5234 
5235   GetTitle (rdp->curator, curator, sizeof (curator));
5236   if (! StringHasNoText (curator)) {
5237     AddCuratorToRefGeneTrackUserObject (uop, curator);
5238   }
5239 
5240   GetTitle (rdp->url, url, sizeof (url));
5241   if (! StringHasNoText (url)) {
5242     AddCuratorURLToRefGeneTrackUserObject (uop, url);
5243   }
5244 
5245   if (rdp->indexer > 0) {
5246     AddIndexerToRefGeneTrackUserObject (uop, rdp->indexer);
5247   }
5248 
5249   tlp = (TagListPtr) GetObjectExtra (rdp->fields);
5250   if (tlp != NULL && tlp->vnp != NULL) {
5251     for (vnp = tlp->vnp; vnp != NULL; vnp = vnp->next) {
5252       str = (CharPtr) vnp->data.ptrvalue;
5253       okay = FALSE;
5254       len = StringLen (str);
5255       for (j = 0; j < len; j++) {
5256         ch = str [j];
5257         if (ch != ' ' && ch != '\t' && ch != '\n') {
5258           okay = TRUE;
5259         }
5260       }
5261       if (okay) {
5262         for (j = 0; j < 6; j++) {
5263           txt [j] = ExtractTagListColumn ((CharPtr) vnp->data.ptrvalue, j);
5264           num [j] = 0;
5265         }
5266         for (j = 1; j < 4; j++) {
5267           num [j] = 0;
5268           if (txt [j] != NULL && sscanf (txt [j], "%ld", &val) == 1) {
5269             num [j] = val;
5270           }
5271         }
5272         if (txt [5] != NULL && sscanf (txt [5], "%ld", &val) == 1) {
5273           num [5] = val;
5274         }
5275         i = num [5];
5276         if (i >= REFGENE_ASSEMBLY && i <= REFGENE_UNKNOWN) {
5277           if (! StringHasNoText (txt [0])) {
5278             AddAccessionToRefGeneTrackUserObject (uop, refgene_labels [i],
5279                                                   txt [0], num [1], num [2],
5280                                                   num [3], txt [4]);
5281           } else if (! StringHasNoText (txt [4])) {
5282             /* comment by itself goes into name */
5283             AddAccessionToRefGeneTrackUserObject (uop, refgene_labels [i],
5284                                                   NULL, num [1], num [2],
5285                                                   num [3], txt [4]);
5286           }
5287         }
5288         for (j = 0; j < 6; j++) {
5289           txt [j] = MemFree (txt [j]);
5290         }
5291       }
5292     }
5293   }
5294 
5295   return uop;
5296 }
5297 
5298 static DialoG CreateRefGeneDialog (GrouP g)
5299 
5300 {
5301   Int2                  i;
5302   PrompT                lastppt;
5303   GrouP                 p;
5304   PrompT                ppt;
5305   GrouP                 q;
5306   RefgeneUserDialogPtr  rdp;
5307   TagListPtr            tlp;
5308   GrouP                 x;
5309   GrouP                 y;
5310   GrouP                 z;
5311 
5312   p = HiddenGroup (g, -1, 0, NULL);
5313   SetGroupSpacing (p, 10, 10);
5314 
5315   rdp = (RefgeneUserDialogPtr) MemNew (sizeof (RefgeneUserDialog));
5316   if (rdp == NULL) return NULL;
5317 
5318   SetObjectExtra (p, rdp, NULL);
5319   rdp->dialog = (DialoG) p;
5320   rdp->todialog = UserObjectPtrToRefGeneDialog;
5321   rdp->fromdialog = RefGeneDialogToUserObjectPtr;
5322 
5323   x = HiddenGroup (p, 4, 0, NULL);
5324   /* StaticPrompt (x, "Status", 0, stdLineHeight, programFont, 'l'); */
5325   rdp->status = HiddenGroup (x, 8, 0, NULL);
5326   SetObjectExtra (rdp->status, rdp, NULL);
5327   RadioButton (rdp->status, "Inferred");
5328   RadioButton (rdp->status, "Predicted");
5329   RadioButton (rdp->status, "Provisional");
5330   RadioButton (rdp->status, "Validated");
5331   RadioButton (rdp->status, "Reviewed");
5332   RadioButton (rdp->status, "Model");
5333   RadioButton (rdp->status, "WGS");
5334   rdp->pipebtn = RadioButton (rdp->status, "Pipeline");
5335   Disable (rdp->pipebtn);
5336 
5337   y = HiddenGroup (p, 6, 0, NULL);
5338   rdp->generated = CheckBox (y, "Generated", NULL);
5339   z = HiddenGroup (y, 2, 0, NULL);
5340   StaticPrompt (z, "Curator", 0, dialogTextHeight, programFont, 'l');
5341   rdp->curator = DialogText (z, "", 14, NULL);
5342   StaticPrompt (z, "URL", 0, dialogTextHeight, programFont, 'r');
5343   rdp->url = DialogText (z, "", 14, NULL);
5344   StaticPrompt (y, "Genomic Source", 0, dialogTextHeight, programFont, 'l');
5345   rdp->source = DialogText (y, "", 7, NULL);
5346 
5347   rdp->indexer = 0;
5348 
5349   q = HiddenGroup (p, -7, 0, NULL);
5350   lastppt = NULL;
5351   ppt = NULL;
5352   for (i = 0; i < 6; i++) {
5353     lastppt = ppt;
5354     ppt = StaticPrompt (q, refgene_fields [i], refgene_widths [i] * stdCharWidth, 0, systemFont, 'c');
5355   }
5356   rdp->fields = CreateTagListDialog (p, 6, 6, STD_TAG_SPACING,
5357                                      refgene_types, refgene_widths, refgene_popups,
5358                                      AccessionUserFieldPtrToVisStringDialog,
5359                                      VisStringDialogToUserFieldPtr);
5360 
5361   tlp = (TagListPtr) GetObjectExtra (rdp->fields);
5362   if (tlp != NULL) {
5363     AlignObjects (ALIGN_JUSTIFY, (HANDLE) tlp->control [4], (HANDLE) lastppt, NULL);
5364     AlignObjects (ALIGN_JUSTIFY, (HANDLE) tlp->control [5], (HANDLE) ppt, NULL);
5365   }
5366 
5367   AlignObjects (ALIGN_CENTER, (HANDLE) x, (HANDLE) y, (HANDLE) q, (HANDLE) rdp->fields, NULL);
5368   return (DialoG) p;
5369 }
5370 
5371 static void RefgeneUserFormMessage (ForM f, Int2 mssg)
5372 
5373 {
5374   RefgeneUserFormPtr  rfp;
5375 
5376   rfp = (RefgeneUserFormPtr) GetObjectExtra (f);
5377   if (rfp != NULL) {
5378     switch (mssg) {
5379       case VIB_MSG_CLOSE :
5380         Remove (f);
5381         break;
5382       case VIB_MSG_CUT :
5383         StdCutTextProc (NULL);
5384         break;
5385       case VIB_MSG_COPY :
5386         StdCopyTextProc (NULL);
5387         break;
5388       case VIB_MSG_PASTE :
5389         StdPasteTextProc (NULL);
5390         break;
5391       case VIB_MSG_DELETE :
5392         StdDeleteTextProc (NULL);
5393         break;
5394       default :
5395         if (rfp->appmessage != NULL) {
5396           rfp->appmessage (f, mssg);
5397         }
5398         break;
5399     }
5400   }
5401 }
5402 
5403 static ForM CreateRefGeneDescForm (Int2 left, Int2 top, Int2 width,
5404                                    Int2 height, CharPtr title, ValNodePtr sdp,
5405                                    SeqEntryPtr sep, FormActnFunc actproc)
5406 
5407 {
5408   ButtoN              b;
5409   GrouP               c;
5410   GrouP               g;
5411   RefgeneUserFormPtr  rfp;
5412   StdEditorProcsPtr   sepp;
5413   WindoW              w;
5414 
5415   w = NULL;
5416   rfp = (RefgeneUserFormPtr) MemNew (sizeof (RefgeneUserForm));
5417   if (rfp != NULL) {
5418     w = FixedWindow (left, top, width, height, title, StdCloseWindowProc);
5419     SetObjectExtra (w, rfp, StdDescFormCleanupProc);
5420     rfp->form = (ForM) w;
5421     rfp->actproc = actproc;
5422     rfp->formmessage = RefgeneUserFormMessage;
5423 
5424     rfp->sep = sep;
5425 
5426 #ifndef WIN_MAC
5427     CreateStdEditorFormMenus (w);
5428 #endif
5429     sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
5430     if (sepp != NULL) {
5431       SetActivate (w, sepp->activateForm);
5432       rfp->appmessage = sepp->handleMessages;
5433     }
5434 
5435     g = HiddenGroup (w, -1, 0, NULL);
5436     rfp->data = CreateRefGeneDialog (g);
5437 
5438     c = HiddenGroup (w, 2, 0, NULL);
5439     b = DefaultButton (c, "Accept", StdAcceptFormButtonProc);
5440     SetObjectExtra (b, rfp, NULL);
5441     PushButton (c, "Cancel", StdCancelButtonProc);
5442     AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL);
5443     RealizeWindow (w);
5444   }
5445   return (ForM) w;
5446 }
5447 
5448 extern Int2 LIBCALLBACK RefGeneUserGenFunc (Pointer data)
5449 
5450 {
5451   ObjectIdPtr         oip;
5452   OMProcControlPtr    ompcp;
5453   OMUserDataPtr       omudp;
5454   ObjMgrProcPtr       proc;
5455   RefgeneUserFormPtr  rfp;
5456   ValNodePtr          sdp;
5457   SeqEntryPtr         sep;
5458   UserObjectPtr       uop;
5459   WindoW              w;
5460 
5461   ompcp = (OMProcControlPtr) data;
5462   w = NULL;
5463   sdp = NULL;
5464   sep = NULL;
5465   uop = NULL;
5466   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
5467   proc = ompcp->proc;
5468   switch (ompcp->input_itemtype) {
5469     case OBJ_SEQDESC :
5470       sdp = (ValNodePtr) ompcp->input_data;
5471       if (sdp != NULL && sdp->choice != Seq_descr_user) {
5472         return OM_MSG_RET_ERROR;
5473       }
5474       uop = (UserObjectPtr) sdp->data.ptrvalue;
5475       break;
5476     case OBJ_BIOSEQ :
5477       break;
5478     case OBJ_BIOSEQSET :
5479       break;
5480     case 0 :
5481       break;
5482     default :
5483       return OM_MSG_RET_ERROR;
5484   }
5485   omudp = ItemAlreadyHasEditor (ompcp->input_entityID, ompcp->input_itemID,
5486                                 ompcp->input_itemtype, ompcp->proc->procid);
5487   if (omudp != NULL) {
5488     if (StringCmp (proc->procname, "Edit RefGene UserTrack Desc") == 0) {
5489       rfp = (RefgeneUserFormPtr) omudp->userdata.ptrvalue;
5490       if (rfp != NULL) {
5491         Select (rfp->form);
5492       }
5493       return OM_MSG_RET_DONE;
5494     } else {
5495       return OM_MSG_RET_OK; /* not this type, check next registered user object editor */
5496     }
5497   }
5498   if (uop != NULL) {
5499     oip = uop->type;
5500     if (oip == NULL || oip->str == NULL) return OM_MSG_RET_OK;
5501     if (StringCmp (oip->str, "RefGeneTracking") != 0) return OM_MSG_RET_OK;
5502   }
5503   sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
5504   w = (WindoW) CreateRefGeneDescForm (-50, -33, -10, -10,
5505                                       "Reference Gene Tracking", sdp, sep,
5506                                       StdDescFormActnProc);
5507   rfp = (RefgeneUserFormPtr) GetObjectExtra (w);
5508   if (rfp != NULL) {
5509     rfp->input_entityID = ompcp->input_entityID;
5510     rfp->input_itemID = ompcp->input_itemID;
5511     rfp->input_itemtype = ompcp->input_itemtype;
5512     rfp->this_itemtype = OBJ_SEQDESC;
5513     rfp->this_subtype = Seq_descr_user;
5514     rfp->procid = ompcp->proc->procid;
5515     rfp->proctype = ompcp->proc->proctype;
5516     rfp->userkey = OMGetNextUserKey ();
5517     omudp = ObjMgrAddUserData (ompcp->input_entityID, ompcp->proc->procid,
5518                                    OMPROC_EDIT, rfp->userkey);
5519     if (omudp != NULL) {
5520       omudp->userdata.ptrvalue = (Pointer) rfp;
5521       omudp->messagefunc = StdVibrantEditorMsgFunc;
5522     }
5523     SendMessageToForm (rfp->form, VIB_MSG_INIT);
5524     if (sdp != NULL) {
5525       PointerToDialog (rfp->data, (Pointer) sdp->data.ptrvalue);
5526       SetClosestParentIfDuplicating ((BaseFormPtr) rfp);
5527     }
5528   }
5529   Show (w);
5530   Select (w);
5531   return OM_MSG_RET_DONE;
5532 }
5533 
5534 extern Int2 LIBCALLBACK StruCommUserGenFunc (Pointer data);
5535 
5536 typedef struct strucommuserdialog {
5537   DIALOG_MESSAGE_BLOCK
5538   DialoG        fields;
5539 } StruCommUserDialog, PNTR StruCommUserDialogPtr;
5540 
5541 typedef struct strucommuserform {
5542   FEATURE_FORM_BLOCK
5543   SeqEntryPtr   sep;
5544 } StruCommUserForm, PNTR StruCommUserFormPtr;
5545 
5546 static void UserObjectPtrToStruCommDialog (DialoG d, Pointer data)
5547 
5548 {
5549   UserFieldPtr           curr;
5550   CharPtr                field;
5551   ValNodePtr             head = NULL;
5552   ObjectIdPtr            oip;
5553   StruCommUserDialogPtr  sdp;
5554   CharPtr                str;
5555   CharPtr                tmp;
5556   UserObjectPtr          uop;
5557 
5558   sdp = (StruCommUserDialogPtr) GetObjectExtra (d);
5559   if (sdp == NULL) return;
5560 
5561   uop = (UserObjectPtr) data;
5562   if (uop == NULL || uop->type == NULL || StringICmp (uop->type->str, "StructuredComment") != 0) {
5563     PointerToDialog (sdp->fields, NULL);
5564     return;
5565   }
5566 
5567   for (curr = uop->data; curr != NULL; curr = curr->next) {
5568    if (curr->choice != 1) continue;
5569     oip = curr->label;
5570     if (oip == NULL) continue;
5571     field = oip->str;
5572     if (StringHasNoText (field)) continue;
5573     str = (CharPtr) curr->data.ptrvalue;
5574     if (StringHasNoText (str)) continue;
5575     tmp = MemNew (StringLen (field) + StringLen (str) + 5);
5576     if (tmp == NULL) continue;
5577     sprintf (tmp, "%s\t%s", field, str);
5578     ValNodeAddStr (&head, 0, (Pointer) tmp);
5579   }
5580 
5581   PointerToDialog (sdp->fields, (Pointer) head);
5582   ValNodeFreeData (head);
5583 }
5584 
5585 static void FixSpecialCharactersInStructuredCommentUserObject (UserObjectPtr uop, BoolPtr changed)
5586 {
5587   UserFieldPtr           curr;
5588   CharPtr                field;
5589   ValNodePtr             find_list = NULL;
5590   ObjectIdPtr            oip;
5591   CharPtr                str;
5592  
5593 
5594   if (changed != NULL) {
5595     *changed = FALSE;
5596   }
5597   if (uop == NULL || uop->type == NULL || StringICmp (uop->type->str, "StructuredComment") != 0) {
5598     return;
5599   }
5600 
5601   for (curr = uop->data; curr != NULL; curr = curr->next) {
5602    if (curr->choice != 1) continue;
5603     oip = curr->label;
5604     if (oip == NULL) continue;
5605     field = oip->str;
5606     if (StringHasNoText (field)) continue;
5607     str = (CharPtr) curr->data.ptrvalue;
5608     if (StringHasNoText (str)) continue;
5609 
5610     SpecialCharFindWithContext ((CharPtr PNTR) (&(oip->str)), &find_list, NULL, NULL);
5611     SpecialCharFindWithContext ((CharPtr PNTR) (&(curr->data.ptrvalue)), &find_list, NULL, NULL);
5612   }
5613   FixSpecialCharactersForStringsInList (find_list, "Special characters are not permitted.", TRUE);  
5614   if (find_list != NULL)
5615   {
5616     if (changed != NULL) {
5617       *changed = TRUE;
5618     }
5619     find_list = FreeContextList (find_list);
5620   }
5621 }
5622 
5623 
5624 static Pointer StruCommDialogToUserObjectPtr (DialoG d)
5625 
5626 {
5627   CharPtr                field;
5628   ValNodePtr             head;
5629   CharPtr                item;
5630   UserObjectPtr          uop;
5631   StruCommUserDialogPtr  sdp;
5632   CharPtr                str;
5633   ValNodePtr             vnp;
5634   Boolean                fixed_special = FALSE;
5635 
5636   sdp = (StruCommUserDialogPtr) GetObjectExtra (d);
5637   if (sdp == NULL) return NULL;
5638 
5639   uop = CreateStructuredCommentUserObject (NULL, NULL);
5640   if (uop == NULL) return NULL;
5641 
5642   head = (ValNodePtr) DialogToPointer (sdp->fields);
5643   if (head == NULL) return NULL;
5644 
5645   for (vnp = head; vnp != NULL; vnp = vnp->next) {
5646     str = (CharPtr) vnp->data.ptrvalue;
5647     if (StringHasNoText (str)) continue;
5648     field = ExtractTagListColumn (str, 0);
5649     item = ExtractTagListColumn (str, 1);
5650     if (StringDoesHaveText (field) && StringDoesHaveText (item)) {
5651       AddItemStructuredCommentUserObject (uop, field, item);
5652     }
5653     MemFree (field);
5654     MemFree (item);
5655   }
5656 
5657   ValNodeFreeData (head);
5658 
5659   FixSpecialCharactersInStructuredCommentUserObject (uop, &fixed_special);
5660   if (fixed_special) {
5661     PointerToDialog (d, uop);
5662   }
5663 
5664   return uop;
5665 }
5666 
5667 static void ValNodePtrToStruCommDialog (DialoG d, Pointer data)
5668 
5669 {
5670   ValNodePtr   head;
5671   Int2         j;
5672   ValNodePtr   list;
5673   CharPtr      str;
5674   TagListPtr   tlp;
5675   ValNodePtr   vnp;
5676 
5677   tlp = (TagListPtr) GetObjectExtra (d);
5678   list = (ValNodePtr) data;
5679   if (tlp != NULL) {
5680     head = NULL;
5681     while (list != NULL) {
5682       vnp = ValNodeNew (head);
5683       if (head == NULL) {
5684         head = vnp;
5685       }
5686       if (vnp != NULL) {
5687         str = MemNew (StringLen ((CharPtr) list->data.ptrvalue) + 3);
5688         if (str != NULL) {
5689           StringCpy (str, (CharPtr) list->data.ptrvalue);
5690           StringCat (str, "\n");
5691         }
5692         vnp->data.ptrvalue = str;
5693       }
5694       list = list->next;
5695     }
5696     SendMessageToDialog (tlp->dialog, VIB_MSG_RESET);
5697     tlp->vnp = head;
5698     SendMessageToDialog (tlp->dialog, VIB_MSG_REDRAW);
5699     for (j = 0, vnp = tlp->vnp; vnp != NULL; j++, vnp = vnp->next) {
5700     }
5701     tlp->max = MAX ((Int2) 0, (Int2) (j - tlp->rows + 1));
5702     CorrectBarMax (tlp->bar, tlp->max);
5703     CorrectBarPage (tlp->bar, tlp->rows - 1, tlp->rows - 1);
5704   }
5705 }
5706 
5707 static Pointer StruCommDialogToValNodePtr (DialoG d)
5708 
5709 {
5710   Char         ch;
5711   ValNodePtr   head;
5712   Int2         j;
5713   Int2         len;
5714   ValNodePtr   list;
5715   Boolean      okay;
5716   CharPtr      str;
5717   TagListPtr   tlp;
5718   ValNodePtr   vnp;
5719 
5720   head = NULL;
5721   tlp = (TagListPtr) GetObjectExtra (d);
5722   if (tlp != NULL && tlp->vnp != NULL) {
5723     list = NULL;
5724     for (vnp = tlp->vnp; vnp != NULL; vnp = vnp->next) {
5725       str = (CharPtr) vnp->data.ptrvalue;
5726       okay = FALSE;
5727       len = StringLen (str);
5728       for (j = 0; j < len; j++) {
5729         ch = str [j];
5730         if (ch != ' ' && ch != '\t' && ch != '\n') {
5731           okay = TRUE;
5732         }
5733       }
5734       if (okay) {
5735         list = ValNodeNew (list);
5736         if (head == NULL) {
5737           head = list;
5738         }
5739         if (list != NULL) {
5740           list->choice = 0;
5741           list->data.ptrvalue = StringSave ((CharPtr) vnp->data.ptrvalue);
5742         }
5743       }
5744     }
5745   }
5746   return (Pointer) head;
5747 }
5748 
5749 Uint2 strccmm_types [] = {
5750   TAGLIST_TEXT, TAGLIST_TEXT
5751 };
5752 
5753 Uint2 strccmm_widths [] = {
5754   16, 16, 0
5755 };
5756 
5757 static DialoG CreateStruCommDialog (GrouP g)
5758 
5759 {
5760   StruCommUserDialogPtr  sdp;
5761   GrouP                  p;
5762   GrouP                  x;
5763   GrouP                  y;
5764 
5765   p = HiddenGroup (g, -1, 0, NULL);
5766   SetGroupSpacing (p, 10, 10);
5767 
5768   sdp = (StruCommUserDialogPtr) MemNew (sizeof (StruCommUserDialog));
5769   if (sdp == NULL) return NULL;
5770 
5771   SetObjectExtra (p, sdp, NULL);
5772   sdp->dialog = (DialoG) p;
5773   sdp->todialog = UserObjectPtrToStruCommDialog;
5774   sdp->fromdialog = StruCommDialogToUserObjectPtr;
5775 
5776   x = HiddenGroup (p, 0, 2, NULL);
5777   y = HiddenGroup (x, 3, 0, NULL);
5778   StaticPrompt (y, "Field", 16 * stdCharWidth, 0, programFont, 'c');
5779   StaticPrompt (y, "Text", 16 * stdCharWidth, 0, programFont, 'c');
5780   sdp->fields = CreateTagListDialog (x, 8, 2, -1,
5781                                      strccmm_types, strccmm_widths, NULL,
5782                                      ValNodePtrToStruCommDialog,
5783                                      StruCommDialogToValNodePtr);
5784 
5785   return (DialoG) p;
5786 }
5787 
5788 
5789 static Boolean ExportStructuredCommentForm (ForM f, CharPtr filename)
5790 {
5791   StruCommUserFormPtr  sfp;
5792   Char            path [PATH_MAX];
5793   UserObjectPtr   uop;
5794   AsnIoPtr        aip;
5795   Boolean         rval = FALSE;
5796 #ifdef WIN_MAC
5797   FILE            *fp;
5798 #endif
5799 
5800   sfp = (StruCommUserFormPtr) GetObjectExtra (f);
5801   if (sfp == NULL) {
5802     return FALSE;
5803   }
5804 
5805   uop = DialogToPointer (sfp->data);
5806   if (uop == NULL) {
5807     Message (MSG_ERROR, "Don't have a valid structured comment yet!");
5808     return FALSE;
5809   }
5810 
5811   path [0] = '\0';
5812   StringNCpy_0 (path, filename, sizeof (path));
5813   if (path [0] != '\0' || GetOutputFileName (path, sizeof (path), NULL)) {
5814 #ifdef WIN_MAC
5815     fp = FileOpen (path, "r");
5816     if (fp != NULL) {
5817       FileClose (fp);
5818     } else {
5819       FileCreate (path, "TEXT", "ttxt");
5820     }
5821 #endif
5822   }
5823   aip = AsnIoOpen (path, "w");
5824   if (aip == NULL) {
5825     Message (MSG_ERROR, "Unable to create file %s", path);
5826   } else {
5827     UserObjectAsnWrite (uop, aip, NULL);
5828     AsnIoClose (aip);
5829     rval = TRUE;
5830   }
5831   uop = UserObjectFree (uop);
5832   return rval;
5833 }
5834 
5835 
5836 static UserObjectPtr StructuredCommentFromTabFile (CharPtr path)
5837 {
5838   FILE *fp;
5839   ValNodePtr table, tmp, header, line;
5840   UserObjectPtr uop = NULL;
5841 
5842   fp = FileOpen (path, "r");
5843   if (fp == NULL) {
5844     return NULL;
5845   }
5846 
5847   table = ReadTabTableFromFile (fp);
5848   FileClose (fp);
5849   if (table == NULL || table->next == NULL 
5850       || table->data.ptrvalue == NULL
5851       || table->next->data.ptrvalue == NULL) {
5852     table = FreeTabTable (table);
5853     return NULL;
5854   }
5855   tmp = FlipTabTableAxes (table);
5856   table = FreeTabTable (table);
5857   table = tmp;
5858 
5859   header = table->data.ptrvalue;
5860   if (header == NULL || header->data.ptrvalue == NULL || header->next == NULL) {
5861     table = FreeTabTable (table);
5862     return NULL;
5863   }
5864   line = table->next;
5865 
5866   tmp = CreateStructuredCommentsFromRow (header, line->data.ptrvalue, NULL, NULL);
5867   table = FreeTabTable (table);
5868   if (tmp != NULL) {
5869     uop = (UserObjectPtr) tmp->data.ptrvalue;
5870     tmp->data.ptrvalue = NULL;
5871     for (line = tmp->next; line != NULL; line = line->next) {
5872       line->data.ptrvalue = UserObjectFree (line->data.ptrvalue);
5873     }
5874     tmp = ValNodeFree (tmp);
5875   }
5876   return uop;
5877 }
5878 
5879 
5880 static Boolean ImportStructuredCommentForm  (ForM f, CharPtr filename)
5881 {
5882   StruCommUserFormPtr  sfp;
5883   Char            path [PATH_MAX];
5884   UserObjectPtr   uop = NULL;
5885   AsnIoPtr        aip = NULL;
5886   Boolean         rval = FALSE;
5887 
5888   sfp = (StruCommUserFormPtr) GetObjectExtra (f);
5889   if (sfp == NULL) {
5890     return FALSE;
5891   }
5892 
5893   path [0] = '\0';
5894   StringNCpy_0 (path, filename, sizeof (path));
5895   if (path [0] == '\0') {
5896     if (!GetInputFileName (path, sizeof (path), "", "TEXT")) {
5897       return FALSE;
5898     }
5899   }
5900 
5901   aip = AsnIoOpen (path, "r");
5902   if (aip == NULL) {
5903     Message (MSG_ERROR, "Unable to read file %s", path);
5904   } else {
5905     uop = UserObjectAsnRead (aip, NULL);
5906     AsnIoClose (aip);
5907     if (uop == NULL) {
5908       /* try reading as though it were a table */
5909       uop = StructuredCommentFromTabFile(path);
5910     }
5911     if (uop == NULL) {
5912       Message (MSG_ERROR, "Unable to read structured comment ASN.1 from file");
5913     }
5914   }
5915   if (uop != NULL) {
5916     PointerToDialog (sfp->data, uop);
5917     uop = UserObjectFree (uop);
5918     rval = TRUE;
5919   }
5920   return rval;
5921 }
5922 
5923 
5924 static void StruCommUserFormMessage (ForM f, Int2 mssg)
5925 
5926 {
5927   StruCommUserFormPtr  sfp;
5928 
5929   sfp = (StruCommUserFormPtr) GetObjectExtra (f);
5930   if (sfp != NULL) {
5931     switch (mssg) {
5932       case VIB_MSG_CLOSE :
5933         Remove (f);
5934         break;
5935       case VIB_MSG_CUT :
5936         StdCutTextProc (NULL);
5937         break;
5938       case VIB_MSG_COPY :
5939         StdCopyTextProc (NULL);
5940         break;
5941       case VIB_MSG_PASTE :
5942         StdPasteTextProc (NULL);
5943         break;
5944       case VIB_MSG_DELETE :
5945         StdDeleteTextProc (NULL);
5946         break;
5947       case VIB_MSG_EXPORT :
5948         ExportStructuredCommentForm (f, NULL);
5949         break;
5950       case VIB_MSG_IMPORT :
5951         ImportStructuredCommentForm (f, NULL);
5952         break;
5953       default :
5954         if (sfp->appmessage != NULL) {
5955           sfp->appmessage (f, mssg);
5956         }
5957         break;
5958     }
5959   }
5960 }
5961 
5962 
5963 typedef struct replacestruccmt {
5964   UserObjectPtr   deleteThis;
5965   UserObjectPtr   replaceWith;
5966 } ReplaceStrucCmtData, PNTR ReplaceStrucCmtPtr;
5967 
5968 
5969 static void ReplaceAllStructuredCommentsCallback (SeqDescrPtr sdp, Pointer data)
5970 
5971 {
5972   ReplaceStrucCmtPtr   rp;
5973 
5974   if ((rp = (ReplaceStrucCmtPtr) data) == NULL || sdp == NULL || sdp->choice != Seq_descr_user) {
5975     return;
5976   }
5977 
5978   if (AsnIoMemComp (sdp->data.ptrvalue, rp->deleteThis, (AsnWriteFunc) UserObjectAsnWrite)) {
5979     sdp->data.ptrvalue = UserObjectFree (sdp->data.ptrvalue);
5980     sdp->data.ptrvalue = AsnIoMemCopy (rp->replaceWith, (AsnReadFunc) UserObjectAsnRead, (AsnWriteFunc) UserObjectAsnWrite);
5981   }
5982 }
5983 
5984 
5985 static void ReplaceAllStructuredCommentsButtonProc (ButtoN b)
5986 {
5987   StruCommUserFormPtr sfp;
5988   SeqEntryPtr   sep;
5989   ReplaceStrucCmtData rd; 
5990   SeqDescrPtr       sdp_orig;
5991   SeqMgrDescContext context;
5992 
5993   sfp = (StruCommUserFormPtr) GetObjectExtra (b);
5994   if (sfp == NULL) {
5995     return;
5996   }
5997 
5998   rd.replaceWith = DialogToPointer (sfp->data);
5999   if (rd.replaceWith == NULL) {
6000     Message (MSG_ERROR, "Must supply text!");
6001     rd.replaceWith = UserObjectFree (rd.replaceWith);
6002     return;
6003   }
6004 
6005   sdp_orig = SeqMgrGetDesiredDescriptor (sfp->input_entityID, NULL, sfp->input_itemID, 0, NULL, &context);
6006   if (sdp_orig == NULL || sdp_orig->choice != Seq_descr_user) {
6007     Message (MSG_ERROR, "Unable to find original descriptor!");
6008     Remove (sfp->form);
6009     rd.replaceWith = UserObjectFree (rd.replaceWith);
6010     return;
6011   }
6012   rd.deleteThis = AsnIoMemCopy (sdp_orig->data.ptrvalue, (AsnReadFunc)UserObjectAsnRead, (AsnWriteFunc) UserObjectAsnWrite);
6013 
6014   sep = GetTopSeqEntryForEntityID (sfp->input_entityID);
6015   VisitDescriptorsInSep (sep, &rd, ReplaceAllStructuredCommentsCallback);
6016 
6017   rd.deleteThis = UserObjectFree (rd.deleteThis);
6018   rd.replaceWith = UserObjectFree (rd.replaceWith);
6019   
6020   ObjMgrSetDirtyFlag (sfp->input_entityID, TRUE);
6021   ObjMgrSendMsg (OM_MSG_UPDATE, sfp->input_entityID,
6022                   sfp->input_itemID, sfp->input_itemtype);
6023   Remove (sfp->form);
6024 }
6025 
6026 
6027 static ForM CreateStruCommDescForm (Int2 left, Int2 top, Int2 width,
6028                                      Int2 height, CharPtr title, ValNodePtr sdp,
6029                                      SeqEntryPtr sep, FormActnFunc actproc)
6030 
6031 {
6032   ButtoN               b;
6033   GrouP                c;
6034   GrouP                g;
6035   StdEditorProcsPtr    sepp;
6036   StruCommUserFormPtr  sfp;
6037   WindoW               w;
6038 
6039   w = NULL;
6040   sfp = (StruCommUserFormPtr) MemNew (sizeof (StruCommUserForm));
6041   if (sfp != NULL) {
6042     w = FixedWindow (left, top, width, height, title, StdCloseWindowProc);
6043     SetObjectExtra (w, sfp, StdDescFormCleanupProc);
6044     sfp->form = (ForM) w;
6045     sfp->actproc = actproc;
6046     sfp->formmessage = StruCommUserFormMessage;
6047     sfp->exportform = ExportStructuredCommentForm;
6048     sfp->importform = ImportStructuredCommentForm;
6049     sfp->sep = sep;
6050 
6051 #ifndef WIN_MAC
6052     CreateStdEditorFormMenus (w);
6053 #endif
6054     sepp = (StdEditorProcsPtr) GetAppProperty ("StdEditorForm");
6055     if (sepp != NULL) {
6056       SetActivate (w, sepp->activateForm);
6057       sfp->appmessage = sepp->handleMessages;
6058     }
6059 
6060     g = HiddenGroup (w, -1, 0, NULL);
6061     sfp->data = CreateStruCommDialog (g);
6062 
6063     c = HiddenGroup (w, 3, 0, NULL);
6064     if (sdp == NULL) {
6065       b = DefaultButton (c, "Accept", StdAcceptFormButtonProc);
6066       SetObjectExtra (b, sfp, NULL);
6067     } else {
6068       b = DefaultButton (c, "Replace This", StdAcceptFormButtonProc);
6069       SetObjectExtra (b, sfp, NULL);
6070       b = PushButton (c, "Replace All", ReplaceAllStructuredCommentsButtonProc);
6071       SetObjectExtra (b, sfp, NULL);
6072     }
6073 
6074     PushButton (c, "Cancel", StdCancelButtonProc);
6075 
6076     AlignObjects (ALIGN_CENTER, (HANDLE) g, (HANDLE) c, NULL);
6077     RealizeWindow (w);
6078   }
6079   return (ForM) w;
6080 }
6081 
6082 extern Int2 LIBCALLBACK StruCommUserGenFunc (Pointer data)
6083 
6084 {
6085   ObjectIdPtr          oip;
6086   OMProcControlPtr     ompcp;
6087   OMUserDataPtr        omudp;
6088   ObjMgrProcPtr        proc;
6089   ValNodePtr           sdp;
6090   SeqEntryPtr          sep;
6091   StruCommUserFormPtr  sfp;
6092   UserObjectPtr        uop;
6093   WindoW               w;
6094 
6095   ompcp = (OMProcControlPtr) data;
6096   w = NULL;
6097   sdp = NULL;
6098   sep = NULL;
6099   uop = NULL;
6100   if (ompcp == NULL || ompcp->proc == NULL) return OM_MSG_RET_ERROR;
6101   proc = ompcp->proc;
6102   switch (ompcp->input_itemtype) {
6103     case OBJ_SEQDESC :
6104       sdp = (ValNodePtr) ompcp->input_data;
6105       if (sdp != NULL && sdp->choice != Seq_descr_user) {
6106         return OM_MSG_RET_ERROR;
6107       }
6108       uop = (UserObjectPtr) sdp->data.ptrvalue;
6109       break;
6110     case OBJ_BIOSEQ :
6111       break;
6112     case OBJ_BIOSEQSET :
6113       break;
6114     case 0 :
6115       break;
6116     default :
6117       return OM_MSG_RET_ERROR;
6118   }
6119   omudp = ItemAlreadyHasEditor (ompcp->input_entityID, ompcp->input_itemID,
6120                                 ompcp->input_itemtype, ompcp->proc->procid);
6121   if (omudp != NULL) {
6122     if (StringCmp (proc->procname, "Edit StructuredComment User Desc") == 0) {
6123       sfp = (StruCommUserFormPtr) omudp->userdata.ptrvalue;
6124       if (sfp != NULL) {
6125         Select (sfp->form);
6126       }
6127       return OM_MSG_RET_DONE;
6128     } else {
6129       return OM_MSG_RET_OK; /* not this type, check next registered user object editor */
6130     }
6131   }
6132   if (uop != NULL) {
6133     oip = uop->type;
6134     if (oip == NULL || oip->str == NULL) return OM_MSG_RET_OK;
6135     if (StringCmp (oip->str, "StructuredComment") != 0) return OM_MSG_RET_OK;
6136   }
6137   sep = GetTopSeqEntryForEntityID (ompcp->input_entityID);
6138   w = (WindoW) CreateStruCommDescForm (-50, -33, -10, -10,
6139                                        "Structured Comment", sdp, sep,
6140                                        StdDescFormActnProc);
6141   sfp = (StruCommUserFormPtr) GetObjectExtra (w);
6142   if (sfp != NULL) {
6143     sfp->input_entityID = ompcp->input_entityID;
6144     sfp->input_itemID = ompcp->input_itemID;
6145     sfp->input_itemtype = ompcp->input_itemtype;
6146     sfp->this_itemtype = OBJ_SEQDESC;
6147     sfp->this_subtype = Seq_descr_user;
6148     sfp->procid = ompcp->proc->procid;
6149     sfp->proctype = ompcp->proc->proctype;
6150     sfp->userkey = OMGetNextUserKey ();
6151     omudp = ObjMgrAddUserData (ompcp->input_entityID, ompcp->proc->procid,
6152                                    OMPROC_EDIT, sfp->userkey);
6153     if (omudp != NULL) {
6154       omudp->userdata.ptrvalue = (Pointer) sfp;
6155       omudp->messagefunc = StdVibrantEditorMsgFunc;
6156     }
6157     SendMessageToForm (sfp->form, VIB_MSG_INIT);
6158     if (sdp != NULL) {
6159       PointerToDialog (sfp->data, (Pointer) sdp->data.ptrvalue);
6160       SetClosestParentIfDuplicating ((BaseFormPtr) sfp);
6161     }
6162   }
6163   Show (w);
6164   Select (w);
6165   return OM_MSG_RET_DONE;
6166 }
6167 
6168 
6169 /*
6170 static void TestGeneRefStuff (void)
6171 
6172 {
6173   UserObjectPtr uop;
6174   ValNodePtr    sdp;
6175 
6176   uop = CreateRefGeneTrackUserObject ();
6177   AddAccessionToRefGeneTrackUserObject (uop, "Assembly", "U12345", 57, 29, 1995);
6178   AddAccessionToRefGeneTrackUserObject (uop, "Assembly", "L97531", 142, 66, 963);
6179   AddAccessionToRefGeneTrackUserObject (uop, "Assembly", "M66778", 823, 7677, 343);
6180   AddAccessionToRefGeneTrackUserObject (uop, "Related", "P34345", 445, 0, 0);
6181   AddAccessionToRefGeneTrackUserObject (uop, "Reject", "S19635", 1765, 0, 0);
6182   AddAccessionToRefGeneTrackUserObject (uop, "Related", "Q14884", 664, 35, 97);
6183   sdp = ValNodeNew (NULL);
6184   sdp->choice = Seq_descr_user;
6185   sdp->data.ptrvalue = (Pointer) uop;
6186   if (! ObjMgrRegister (OBJ_SEQDESC, (Pointer) sdp)) {
6187      ErrPostEx (SEV_ERROR, 0, 0, "ObjMgrRegister failed.");
6188   }
6189 }
6190 */
6191 
6192 #define CKA_GAPLEN  50 /* max allowed unaligned gap size */
6193 
6194 typedef struct cka_acc {
6195    CharPtr      accession;
6196    SeqIdPtr     sip_whole;
6197    SeqAlignPtr  sap;
6198    Int4         start_acc;
6199    Int4         stop_acc;
6200    Int4         start_seq;
6201    Int4         stop_seq;
6202    Uint1        strand;
6203    Int4         num;
6204    struct cka_acc PNTR next;
6205 } CKA_Acc, PNTR CKA_AccPtr;
6206 
6207 static Int4     CKA_blast_wordsize;
6208 static FloatHi  CKA_blast_expect_value;
6209 static Boolean  CKA_blast_allow_repeats;
6210 static Int4     CKA_blast_detailed_wordsize;
6211 static FloatHi  CKA_blast_detailed_expect_value;
6212 static Boolean  CKA_blast_detailed_allow_repeats;
6213 
6214 static SeqAlignPtr CKA_MakeAlign(BioseqPtr bsp, CKA_AccPtr acc_head, LogInfoPtr lip);
6215 
6216 static Boolean SPI_GetAccessionFromSeqId(SeqIdPtr sip, Int4Ptr gi, CharPtr PNTR id)
6217 {
6218    Boolean numeric_id_type = FALSE;
6219    Int2 id_len;
6220    GiimPtr gip;
6221    ObjectIdPtr oip;
6222    TextSeqIdPtr textsip;
6223    DbtagPtr dbtag;
6224    PatentSeqIdPtr psip;
6225    PDBSeqIdPtr pdbsip;
6226 
6227    *id = NULL;
6228    *gi = 0;
6229 
6230    switch (sip->choice) {
6231    case SEQID_GI: case SEQID_GIBBSQ: case SEQID_GIBBMT:
6232       *gi = sip->data.intvalue;
6233       numeric_id_type = TRUE;
6234       break;
6235    case SEQID_GIIM:
6236       gip = (GiimPtr) sip->data.ptrvalue;
6237       *gi = gip->id;
6238       numeric_id_type = TRUE;
6239       break;
6240    case SEQID_LOCAL:
6241       oip = (ObjectIdPtr) sip->data.ptrvalue;
6242 
6243       if (oip->str) {
6244          id_len = StringLen(oip->str);
6245          *id = (CharPtr) MemNew(id_len+1);
6246          sprintf(*id, "%s", oip->str);
6247       } else {
6248          *id = (CharPtr) MemNew(6);
6249          sprintf(*id, "%d", oip->id);
6250       }
6251       break;
6252    case SEQID_GENBANK: case SEQID_EMBL: case SEQID_PIR: case SEQID_TPG: case SEQID_TPE: case SEQID_TPD:
6253    case SEQID_SWISSPROT: case SEQID_DDBJ: case SEQID_PRF:
6254    case SEQID_OTHER: case SEQID_GPIPE:
6255       textsip = (TextSeqIdPtr)sip->data.ptrvalue;
6256       id_len = StringLen(textsip->accession);
6257       *id = (CharPtr) MemNew(id_len+1);
6258       if (textsip->version > 0)
6259          sprintf(*id, "%s.%d", textsip->accession, textsip->version);
6260       else
6261          sprintf(*id, "%s", textsip->accession);
6262       break;
6263    case SEQID_GENERAL:
6264       dbtag = (DbtagPtr) sip->data.ptrvalue;
6265       if (dbtag->tag->str == NULL) {
6266          numeric_id_type = TRUE;
6267          *gi = dbtag->tag->id;
6268       } else {
6269          id_len = StringLen(dbtag->tag->str);
6270          *id = (CharPtr) MemNew(id_len+1);
6271          sprintf(*id, "%s", dbtag->tag->str);
6272       }
6273       break;
6274    case SEQID_PATENT:
6275       psip = (PatentSeqIdPtr) sip->data.ptrvalue;
6276       *gi = (Int4) psip->seqid;
6277       numeric_id_type = TRUE;
6278       break;
6279    case SEQID_PDB:
6280       pdbsip = (PDBSeqIdPtr) sip->data.ptrvalue;
6281       id_len = StringLen(pdbsip->mol);
6282       *id = (CharPtr) MemNew(id_len+4);
6283       sprintf(*id, "%s%d", pdbsip->mol, pdbsip->chain);
6284       break;
6285    default: break;
6286    }
6287 
6288    return numeric_id_type;
6289 }
6290 
6291 static void CKA_FindAllTpaDescr(SeqEntryPtr sep, Pointer data, Int4 index, Int2 indent)
6292 {
6293    CKA_AccPtr         acc;
6294    CKA_AccPtr         PNTR acc_head;
6295    CKA_AccPtr         acc_prev;
6296    BioseqPtr          bsp;
6297    SeqMgrDescContext  context;
6298    UserFieldPtr       curr;
6299    ObjectIdPtr        oip;
6300    SeqDescrPtr        sdp;
6301    UserFieldPtr       ufp;
6302    UserObjectPtr      uop;
6303 
6304    acc_head = (CKA_AccPtr PNTR)data;
6305    acc_prev = *acc_head;
6306    while (acc_prev != NULL && acc_prev->next != NULL)
6307    {
6308       acc_prev = acc_prev->next;
6309    }
6310    sdp = NULL;
6311    if (IS_Bioseq(sep))
6312    {
6313       bsp = (BioseqPtr)sep->data.ptrvalue;
6314       if (ISA_na(bsp->mol))
6315       {
6316          while ((sdp = SeqMgrGetNextDescriptor(bsp, sdp, Seq_descr_user, &context)) != NULL)
6317          {
6318             uop = (UserObjectPtr)sdp->data.ptrvalue;
6319             if (!StringICmp(uop->type->str, "TpaAssembly"))
6320             {
6321                for (curr = uop->data; curr != NULL; curr = curr->next)
6322                {
6323                   if (curr->choice != 11) continue;
6324                   
6325                   acc = (CKA_AccPtr)MemNew(sizeof(CKA_Acc));
6326                   acc->sip_whole = SeqIdSetDup(bsp->id);
6327                   /* will use these to mark the span for blast2seq */
6328                   acc->start_acc = acc->stop_acc = -1;
6329                   if (acc_prev == NULL)
6330                     *acc_head = acc_prev = acc;
6331                   else {
6332                     acc_prev->next = acc;
6333                     acc_prev = acc;
6334                   }
6335                   
6336                   for (ufp = curr->data.ptrvalue; ufp != NULL; ufp = ufp->next) {
6337                     oip = ufp->label;
6338                     if (oip == NULL) continue;
6339                     if (StringICmp (oip->str, "accession") == 0 && ufp->choice == 1) {
6340                       acc->accession = StringSave((CharPtr)ufp->data.ptrvalue);
6341                     } else if (StringICmp (oip->str, "from") == 0 && ufp->choice == 2) {
6342                       acc->start_acc = (Int4) ufp->data.intvalue;
6343                     } else if (StringICmp (oip->str, "to") == 0 && ufp->choice == 2) {
6344                       acc->stop_acc = (Int4) ufp->data.intvalue;
6345                     }
6346                   }
6347                }
6348             }
6349          }
6350       }
6351    }
6352 }
6353 
6354 static int LIBCALLBACK CKA_SortAccs(VoidPtr ptr1, VoidPtr ptr2)
6355 {
6356    CKA_AccPtr  acc1;
6357    CKA_AccPtr  acc2;
6358 
6359    acc1 = *((CKA_AccPtr PNTR)ptr1);
6360    acc2 = *((CKA_AccPtr PNTR)ptr2);
6361    if (acc1->start_seq < acc2->start_seq)
6362       return -1;
6363    else if (acc1->start_seq > acc2->start_seq)
6364       return 1;
6365    else if (acc1->stop_seq < acc2->stop_seq)
6366       return -1;
6367    else if (acc1->stop_seq > acc2->stop_seq)
6368       return 1;
6369    else
6370       return 0; /* no alignment */
6371 }
6372 
6373 static SeqIdPtr SqnSeqIdFindBestAccession (SeqIdPtr sip)
6374 {
6375         Uint1 order[NUM_SEQID];
6376 
6377         if (sip == NULL)
6378                 return NULL;
6379         SeqIdBestRank(order, NUM_SEQID);
6380         order[SEQID_GI]=order[SEQID_LOCAL]+2;
6381         order[SEQID_PATENT]=order[SEQID_LOCAL]+1;
6382         return SeqIdSelect (sip, order, NUM_SEQID);
6383 }
6384 
6385 
6386 static Boolean ValidateTPAHistAlign (BioseqPtr bsp, ValNodePtr PNTR errors)
6387 {
6388   ValNodePtr new_errors;
6389   Boolean    retval = TRUE;
6390   SeqAlignPtr salp;
6391 
6392   if (bsp == NULL || bsp->hist == NULL || bsp->hist->assembly == NULL) {
6393     return FALSE;
6394   }
6395 
6396   for (salp = bsp->hist->assembly; salp != NULL; salp = salp->next) {
6397     AlnMgr2IndexSingleChildSeqAlign(salp);
6398   }
6399 
6400   new_errors = ReportCoverageForBioseqSeqHist (bsp);
6401   if (new_errors != NULL) {
6402     ValNodeLink (errors, new_errors);
6403     retval = FALSE;
6404   }
6405   return retval;
6406 }
6407 
6408  
6409 static Boolean CKA_ValidateSeqAlign(SeqAlignPtr sap, CKA_AccPtr acc_head, Int4 bioseqlen, ValNodePtr PNTR errors)
6410 {
6411    CKA_AccPtr        acc;
6412    CKA_AccPtr        PNTR accarray;
6413    AMAlignIndex2Ptr  amaip;
6414    Int4              first, first_align;
6415    Boolean           found;
6416    Int4              gi;
6417    Int4              i;
6418    Int4              j;
6419    Int4              k;
6420    Int4              last;
6421    Int4              longest;
6422    Int4              max;
6423    Int4              n;
6424    Int4              prev;
6425    Boolean           retval = TRUE;
6426    CharPtr           textid;
6427    Char              textid2[42];
6428    CharPtr           err_msg;
6429    CharPtr           no_cover_fmt = "Primary accessions do not completely cover the bioseq %s:\n %s aligns to %d-%d but next aln is %s to %d-%d\n"; 
6430    CharPtr           no_cover_ok_gap_fmt = "Primary accessions do not completely cover the bioseq %s:\n %s aligns to %d-%d but the next aln is %s to %d-%d;\n the gap is less than %d and is acceptable.\n";
6431    CharPtr           bad_start_fmt = "Primary accessions do not completely cover the bioseq %s:\n %s (the first aln) starts at position %d\n";
6432    CharPtr           bad_start_ok_gap_fmt = "Primary accessions do not completely cover the bioseq %s:\n %s (the first alignment) starts at position %d, but the gap is less than %d and is acceptable.\n";
6433    CharPtr           bad_end_fmt = "Primary accessions do not completely cover the bioseq %s:\n %s (the last aln) goes to %d, bioseq length is %d\n";
6434    CharPtr           bad_end_ok_gap_fmt = "Primary accessions do not completely cover the bioseq %s:\n %s (the last alignment) goes to %d, bioseq length is %d, but the gap is less than %d and is acceptable.\n";
6435 
6436    if (sap == NULL || sap->saip == NULL || sap->saip->indextype != INDEX_PARENT || errors == NULL)
6437       return FALSE;
6438 
6439    amaip = (AMAlignIndex2Ptr)(sap->saip);
6440    for (i=0; i<amaip->numsaps; i++)
6441    {
6442       acc = acc_head;
6443       found = FALSE;
6444       while (acc != NULL && !found)
6445       {
6446          if (amaip->saps[i] == acc->sap)
6447             found = TRUE;
6448          if (!found)
6449             acc = acc->next;
6450       }
6451       if (!found) /* big error */
6452          return FALSE;
6453       acc->num = i+1;
6454       AlnMgr2GetNthSeqRangeInSA(amaip->saps[i], 1, &acc->start_seq, &acc->stop_seq);
6455       AlnMgr2GetNthSeqRangeInSA(amaip->saps[i], 2, &acc->start_acc, &acc->stop_acc);
6456       acc->strand = AlnMgr2GetNthStrand(amaip->saps[i], 2);
6457       acc->start_seq++;
6458       acc->stop_seq++;
6459       acc->start_acc++;
6460       acc->stop_acc++;
6461    }
6462    acc = acc_head;
6463    i = 0;
6464    while (acc != NULL)
6465    {
6466       if (acc->start_seq == 0 && acc->stop_seq == 0)
6467       {
6468          AlnMgr2GetNthSeqRangeInSA(acc->sap, 1, &acc->start_seq, &acc->stop_seq);
6469          AlnMgr2GetNthSeqRangeInSA(acc->sap, 2, &acc->start_acc, &acc->stop_acc);
6470          acc->strand = AlnMgr2GetNthStrand(acc->sap, 2);
6471          acc->start_seq++;
6472          acc->stop_seq++;
6473          acc->start_acc++;
6474          acc->stop_acc++;
6475       }
6476       if (acc->num == 0)
6477          acc->num = amaip->numsaps; /* sort these guys all to the end */
6478       i++;
6479       acc = acc->next;
6480    }
6481    accarray = (CKA_AccPtr PNTR)MemNew(i*sizeof(CKA_AccPtr));
6482    i = 0;
6483    acc = acc_head;
6484    while (acc != NULL)
6485    {
6486       accarray[i] = acc;
6487       i++;
6488       acc = acc->next;
6489    }
6490    HeapSort(accarray, i, sizeof(CKA_AccPtr), CKA_SortAccs);
6491    n=0;
6492    while (accarray[n]->sap == NULL && n < i)
6493    {
6494       n++;
6495    }
6496    SPI_GetAccessionFromSeqId(SqnSeqIdFindBestAccession(accarray[0]->sip_whole), &gi, &textid);
6497    if (textid == NULL)
6498    {
6499       sprintf(textid2, "%d", gi);
6500       textid = textid2;
6501    }
6502    first = last = -1;
6503    prev = -1;
6504    retval = TRUE;
6505    for (j=0; j<i /*&& first <=0*/ ; j++)
6506    {
6507       acc = accarray[j];
6508       if (acc->sap != NULL)
6509       {
6510         if (first == -1) {
6511           first = acc->start_seq;
6512           first_align = j;
6513         }
6514         last = MAX(last, acc->stop_seq);
6515       } else {
6516         continue;
6517       }
6518       if (prev != -1)
6519       {
6520          if (acc->start_seq > prev + CKA_GAPLEN)
6521          {
6522             err_msg = (CharPtr) MemNew (sizeof (Char) * (StringLen (no_cover_fmt) + StringLen (textid) + StringLen (accarray[j-1]->accession)
6523                                                          + StringLen (acc->accession) + 60));
6524             sprintf (err_msg, no_cover_fmt, 
6525                      textid, accarray[j-1]->accession, accarray[j-1]->start_seq, accarray[j-1]->stop_seq, acc->accession, acc->start_seq, acc->stop_seq);
6526             ValNodeAddPointer (errors, 0, err_msg);
6527             retval = FALSE;
6528          } 
6529          else if (acc->start_seq > prev)
6530          {
6531             err_msg = (CharPtr) MemNew (sizeof (Char) * (StringLen (no_cover_ok_gap_fmt) + StringLen (textid)
6532                                                          + StringLen (accarray[j-1]->accession)
6533                                                          + StringLen (acc->accession)
6534                                                          + 75));
6535             sprintf (err_msg, no_cover_ok_gap_fmt,
6536                      textid, accarray[j-1]->accession, accarray[j-1]->start_seq, accarray[j-1]->stop_seq, acc->accession, acc->start_seq, acc->stop_seq, CKA_GAPLEN);
6537             ValNodeAddPointer (errors, 0, err_msg);
6538             retval = FALSE;
6539          }
6540       }
6541       prev = acc->stop_seq+1;
6542    }
6543    if (first != 1 || last != bioseqlen)
6544    {
6545       if (first > CKA_GAPLEN)
6546       {
6547          err_msg = (CharPtr) MemNew (sizeof (Char) * (StringLen (bad_start_fmt) + StringLen (textid)
6548                                                       + StringLen (accarray[first_align]->accession)
6549                                                      + 15));
6550          sprintf (err_msg, bad_start_fmt,
6551                           textid, accarray[first_align]->accession, accarray[first_align]->start_seq);
6552          ValNodeAddPointer (errors, 0, err_msg);
6553          retval = FALSE;
6554       } 
6555       else if (first != 1)
6556       {
6557          err_msg = (CharPtr) MemNew (sizeof (Char) * (StringLen (bad_start_ok_gap_fmt) 
6558                                                       + StringLen (textid)
6559                                                       + StringLen (accarray[first_align]->accession)
6560                                                       + 30));
6561          sprintf (err_msg, bad_start_ok_gap_fmt, 
6562                   textid, accarray[first_align]->accession, accarray[first_align]->start_seq, CKA_GAPLEN);
6563          ValNodeAddPointer (errors, 0, err_msg);
6564       }
6565       max = 0;
6566       for (k=0; k<i; k++)
6567       {
6568          if (accarray[k]->stop_seq > max)
6569          {
6570             max = accarray[k]->stop_seq;
6571             longest = k;
6572          }
6573       }
6574       if (accarray[longest]->stop_seq < bioseqlen-CKA_GAPLEN)
6575       {
6576          err_msg = (CharPtr) MemNew (sizeof (Char) * (StringLen (bad_end_fmt) 
6577                                                       + StringLen (textid)
6578                                                       + StringLen (accarray[longest]->accession)
6579                                                       + 30));
6580          sprintf (err_msg, bad_end_fmt,
6581                           textid, accarray[longest]->accession, accarray[longest]->stop_seq, bioseqlen);
6582          ValNodeAddPointer (errors, 0, err_msg);
6583          retval = FALSE;
6584       } 
6585       else if (accarray[longest]->stop_seq < bioseqlen)
6586       {
6587          err_msg = (CharPtr) MemNew (sizeof (Char) * (StringLen (bad_end_ok_gap_fmt)
6588                                                       + StringLen (textid)
6589                                                       + StringLen (accarray[longest]->accession)
6590                                                       + 45));
6591          sprintf (err_msg, bad_end_ok_gap_fmt,
6592                            textid, accarray[longest]->accession, accarray[longest]->stop_seq, bioseqlen, CKA_GAPLEN);
6593          ValNodeAddPointer (errors, 0, err_msg);
6594       }
6595       MemFree(accarray);
6596       accarray = NULL;
6597    }
6598    MemFree(accarray);
6599    return retval;
6600 }
6601 
6602 static void FrameVwr (
6603   VieweR vwr,
6604   SegmenT pict
6605 )
6606 
6607 {
6608   RecT  r;
6609 
6610   ResetClip ();
6611   ObjectRect (vwr, &r);
6612   FrameRect (&r);
6613 }
6614 
6615 static void CKA_ShowAln(SeqAlignPtr sap, CKA_AccPtr acc_head)
6616 {
6617    CKA_AccPtr   acc;
6618    BioseqPtr    bsp;
6619    DenseSegPtr  dsp;
6620    Boolean      found;
6621    GrouP        g;
6622    Int4         gi;
6623    Int4         i;
6624    Int4         len;
6625    Int4         numsaps;
6626    SegmenT      picture;
6627    SeqAlignPtr  salp;
6628    SeqIdPtr     sip;
6629    Int4         start;
6630    Int4         start_r;
6631    Int4         stop;
6632    Int4         stop_r;
6633    Char         tmp[42];
6634    CharPtr      textid;
6635    Char         textid2[42];
6636    VieweR       v;
6637    WindoW       w;
6638 
6639    w = FixedWindow(-1, -1, -1, -1, "TPA display", StdCloseWindowProc);
6640    g = HiddenGroup(w, 1, 0, NULL);
6641    v = CreateViewer(g, 750, 300, TRUE, TRUE);
6642    picture = CreatePicture();
6643    salp = (SeqAlignPtr)(sap->segs);
6644    numsaps = 0;
6645    while (salp != NULL)
6646    {
6647       numsaps++;
6648       salp = salp->next;
6649    }
6650    salp = (SeqAlignPtr)(sap->segs);
6651    numsaps++;
6652    dsp = (DenseSegPtr)(salp->segs);
6653    sip = dsp->ids;
6654    SPI_GetAccessionFromSeqId(SqnSeqIdFindBestAccession(sip), &gi, &textid);
6655    if (textid == NULL)
6656    {
6657       sprintf(textid2, "%d", gi);
6658       textid = textid2;
6659    }
6660    bsp = BioseqLockById(sip);
6661    len = bsp->length;
6662    AddRectangle(picture, 0, numsaps*10, (bsp->length*680)/len, numsaps*10-7, 0, TRUE, 0);
6663    sprintf(tmp, "1");
6664    AddLabel(picture, 0-10, numsaps*10-3, tmp, 0, 0, MIDDLE_LEFT, 0);
6665    sprintf(tmp, "%d  %s", bsp->length, textid);
6666    AddLabel(picture, ((bsp->length+10)*680)/len, numsaps*10-3, tmp, 0, 0, MIDDLE_RIGHT, 0);
6667    BioseqUnlock(bsp);
6668    i = numsaps-1;
6669    while (salp != NULL)
6670    {
6671       acc = acc_head;
6672       found = FALSE;
6673       while (acc != NULL && !found)
6674       {
6675          if (acc->sap == salp)
6676             found = TRUE;
6677          else
6678             acc = acc->next;
6679       }
6680       AlnMgr2GetNthSeqRangeInSA(salp, 1, &start, &stop);
6681       start_r = (start*680)/len;
6682       stop_r = (stop*680)/len;
6683       AddRectangle(picture, start_r, i*10, stop_r, i*10-7, 0, TRUE, 0);
6684       dsp = (DenseSegPtr)(salp->segs);
6685       sprintf(tmp, "%d", start+1);
6686       AddLabel(picture, start_r-10, i*10-3, tmp, 0, 0, MIDDLE_LEFT, 0);
6687       sprintf(tmp, "%d  %s", stop+1, acc->accession);
6688       AddLabel(picture, stop_r+10, i*10-3, tmp, 0, 0, MIDDLE_RIGHT, 0);
6689       salp = salp->next;
6690       i--;
6691    }
6692    AttachPicture(v, picture, 0, 0, UPPER_LEFT, 1, 1, FrameVwr);
6693    Show(w);
6694 }
6695 
6696 
6697 static void PrintTPAHistErrors (LogInfoPtr lip, ValNodePtr errors)
6698 {
6699   ValNodePtr vnp;
6700 
6701   if (lip == NULL || lip->fp == NULL || errors == NULL) return;
6702 
6703   for (vnp = errors; vnp != NULL; vnp = vnp->next)
6704   {
6705     fprintf (lip->fp, "%s\n", vnp->data.ptrvalue);
6706     lip->data_in_log = TRUE;
6707   }
6708   fprintf (lip->fp, "\n\n");
6709 }
6710 
6711 
6712 static void CKA_RunChecker(SeqEntryPtr sep)
6713 {
6714    CKA_AccPtr   acc;
6715    CKA_AccPtr   acc_head;
6716    CKA_AccPtr   acc_head_next;
6717    CKA_AccPtr   acc_head_prev;
6718    CKA_AccPtr   acc_head_real;
6719    CKA_AccPtr   acc_head_tmp;
6720    BioseqPtr    bsp;
6721    Boolean      found;
6722    Int4         gi;
6723    SeqIdPtr     lastid;
6724    SeqAlignPtr  sap;
6725    SeqHistPtr   shp;
6726    CharPtr      textid;
6727    Char         textid2[42];
6728    LogInfoPtr   lip;
6729    ValNodePtr   err_list;
6730    CharPtr      err_msg;
6731    CharPtr      no_align_fmt = "Accession %s does not align to the bioseq %s.\n";
6732 
6733    if (sep == NULL)
6734    {
6735       Message(MSG_ERROR, "Null SeqEntry passed to CKA_RunChecker");
6736       return;
6737    }
6738    acc_head = NULL;
6739    SeqEntryExplore(sep, &acc_head, CKA_FindAllTpaDescr);
6740    lastid = NULL;
6741    if (acc_head == NULL)
6742    {
6743       Message(MSG_ERROR, "No Tpa features found in SeqEntry.");
6744       return;
6745    }
6746 
6747    lip = OpenLog ("TPA Alignment Assembly Problems");
6748 
6749    acc_head_real = acc_head;
6750    while (acc_head != NULL)
6751    {
6752       lastid = acc_head->sip_whole;
6753       acc_head_prev = acc_head;
6754       acc_head_tmp = acc_head->next;
6755       found = FALSE;
6756       while (!found && acc_head_tmp != NULL)
6757       {
6758          if (SeqIdComp(lastid, acc_head_tmp->sip_whole) != SIC_YES)
6759             found = TRUE;
6760          else
6761          {
6762             acc_head_prev = acc_head_tmp;
6763             acc_head_tmp = acc_head_tmp->next;
6764          }
6765       }
6766       acc_head_next = acc_head_prev->next;
6767       acc_head_prev->next = NULL;
6768       bsp = BioseqLockById(acc_head->sip_whole);
6769       if (ISA_na(bsp->mol))
6770       {
6771          sap = CKA_MakeAlign(bsp, acc_head, lip);
6772          acc = acc_head;
6773          while (acc != NULL && acc->sap == NULL)
6774          {
6775             acc = acc->next;
6776          }
6777          SPI_GetAccessionFromSeqId(SqnSeqIdFindBestAccession(acc_head->sip_whole), &gi, &textid);
6778          if (textid == NULL)
6779          {
6780             sprintf(textid2, "%d", gi);
6781             textid = textid2;
6782          }
6783 
6784          err_list = NULL;
6785 
6786          /* report each accession that does not align to the bioseq */
6787          acc = acc_head;
6788          while (acc != NULL) 
6789          {
6790            if (acc->sap == NULL) 
6791            {
6792              err_msg = (CharPtr) MemNew (sizeof(Char) * (StringLen (no_align_fmt) + StringLen (acc->accession) + StringLen (textid)));
6793              sprintf (err_msg, no_align_fmt, acc->accession, textid);
6794              ValNodeAddPointer (&err_list, 0, err_msg);
6795            }
6796            acc = acc->next;
6797          }
6798 
6799          if (sap != NULL) {
6800             AlnMgr2IndexLite(sap);
6801             AlnMgr2SortAlnSetByNthRowPos(sap, 1);
6802                   /* make seq-hist and add it to record */
6803                   if (bsp->hist != NULL)
6804                   {
6805                       shp = bsp->hist;
6806                       if (shp->assembly != NULL)
6807                         SeqAlignSetFree(shp->assembly);
6808                       shp->assembly = (SeqAlignPtr)(sap->segs);
6809                   }
6810             else
6811                   {
6812                       shp = SeqHistNew();
6813                       shp->assembly = (SeqAlignPtr)(sap->segs);
6814                       bsp->hist = shp;
6815                   }
6816          }
6817       
6818          if (ValidateTPAHistAlign(bsp, &err_list)) 
6819          {
6820             fprintf (lip->fp, "Alignments were successfully created and are being added to %s.\n", textid);
6821             lip->data_in_log = TRUE;
6822             PrintTPAHistErrors (lip, err_list);
6823             err_list = ValNodeFreeData (err_list);
6824          }
6825                else if (sap != NULL)
6826          {
6827             fprintf (lip->fp, "Alignments were created but are not valid. They are being added to %s for review.\n", textid);
6828             lip->data_in_log = TRUE;
6829             PrintTPAHistErrors (lip, err_list);
6830             err_list = ValNodeFreeData (err_list);
6831          }
6832          else if (sap == NULL) 
6833          {
6834             fprintf (lip->fp, "No alignments could be created for %s.\n", textid);
6835             lip->data_in_log = TRUE;
6836             PrintTPAHistErrors (lip, err_list);
6837             err_list = ValNodeFreeData (err_list);
6838             acc_head = acc_head_next;
6839             BioseqUnlock (bsp);
6840             continue;
6841          } else {
6842             PrintTPAHistErrors (lip, err_list);
6843             err_list = ValNodeFreeData (err_list);
6844          }
6845 
6846          if (sap != NULL) {
6847             sap->segs = NULL;
6848             SeqAlignFree(sap);
6849          }
6850              } 
6851      else
6852      {
6853         fprintf (lip->fp, "%s is annotated on a non-nucleotide bioseq.\n", acc_head->accession);
6854         lip->data_in_log = TRUE;
6855      }
6856      BioseqUnlock (bsp);
6857      acc_head = acc_head_next;
6858   }
6859   /*CKA_ShowAln(sap, acc_head_real);*/
6860   while (acc_head_real != NULL)
6861   {
6862      acc_head_tmp = acc_head_real->next;
6863      MemFree(acc_head_real->accession);
6864      SeqIdFree(acc_head_real->sip_whole);
6865      MemFree(acc_head_real);
6866      acc_head_real = acc_head_tmp;
6867   }
6868   CloseLog (lip);
6869   lip = FreeLog (lip);
6870 }
6871 
6872 
6873 typedef struct seqalignrow {
6874   Int4 start;
6875   Int4 stop;
6876   Uint1 strand;
6877 } SeqAlignRowData, PNTR SeqAlignRowPtr;
6878 
6879 static SeqAlignRowPtr SeqAlignRowNew (Int4 start, Int4 stop, Uint1 strand)
6880 {
6881   SeqAlignRowPtr r;
6882   Int4 tmp;
6883 
6884   r = (SeqAlignRowPtr) MemNew (sizeof (SeqAlignRowData));
6885   r->start = start;
6886   r->stop = stop;
6887 
6888   if (r->start > r->stop) {
6889     tmp = r->start;
6890     r->start = r->stop;
6891     r->stop = tmp;
6892   }
6893   r->strand = strand;
6894   return r;
6895 }
6896 
6897 
6898 static SeqAlignRowPtr SeqAlignRowCopy (SeqAlignRowPtr orig)
6899 {
6900   SeqAlignRowPtr r = NULL;
6901 
6902   if (orig != NULL) {
6903     r = SeqAlignRowNew (orig->start, orig->stop, orig->strand);
6904   }
6905   return r;
6906 }
6907 
6908 
6909 static SeqAlignRowPtr SeqAlignRowFree (SeqAlignRowPtr r)
6910 {
6911   r = MemFree (r);
6912   return r;
6913 }
6914 
6915 
6916 static Int4 RowDiff (SeqAlignRowPtr r1, SeqAlignRowPtr r2)
6917 {
6918   Int4 diff = 0;
6919 
6920   if (r1 == NULL || r2 == NULL) {
6921     return -1;
6922   }
6923 
6924   diff = ABS(r1->start - r2->start) + ABS (r1->stop - r2->stop);
6925   return diff;
6926 }
6927 
6928 
6929 static Boolean SeqAlignRowConflict (SeqAlignRowPtr r1, SeqAlignRowPtr r2)
6930 {
6931   if (r1 == NULL || r2 == NULL) {
6932     return FALSE;
6933   }
6934   if (r1->start <= r2->start && r1->stop >= r2->start) {
6935     return TRUE;
6936   } else if (r1->start <= r2->stop && r1->stop >= r2->stop) {
6937     return TRUE;
6938   } else if (r2->start <= r1->start && r2->start >= r2->start) {
6939     return TRUE;
6940   } else if (r2->start <= r1->stop && r2->stop >= r2->stop) {
6941     return TRUE;
6942   } else {
6943     return FALSE;
6944   }
6945 }
6946 
6947 
6948 static Int4 SeqAlignRowLen (SeqAlignRowPtr r) 
6949 {
6950   Int4 len = 0;
6951 
6952   if (r != NULL) {
6953     len = r->stop - r->start + 1;
6954   }
6955   return len;
6956 }
6957 
6958 
6959 typedef struct seqalignsort {
6960   SeqAlignRowPtr row1;
6961   SeqAlignRowPtr row2;
6962   SeqAlignPtr salp;
6963 } SeqAlignSortData, PNTR SeqAlignSortPtr;
6964 
6965 
6966 static SeqAlignSortPtr SeqAlignSortNew (SeqAlignPtr salp)
6967 {
6968   SeqAlignSortPtr s;
6969 
6970   if (salp == NULL) {
6971     return NULL;
6972   }
6973 
6974   s = (SeqAlignSortPtr) MemNew (sizeof (SeqAlignSortData));
6975   s->salp = SeqAlignDup (salp);
6976 
6977   AlnMgr2IndexSingleChildSeqAlign(s->salp);
6978 
6979   s->row1 = SeqAlignRowNew (SeqAlignStart (s->salp, 0), SeqAlignStop (s->salp, 0), SeqAlignStrand (s->salp, 0));
6980   s->row2 = SeqAlignRowNew (SeqAlignStart (s->salp, 1), SeqAlignStop (s->salp, 1), SeqAlignStrand (s->salp, 1));
6981 
6982   return s;
6983 }
6984 
6985 
6986 static SeqAlignSortPtr SeqAlignSortFree (SeqAlignSortPtr s)
6987 {
6988   if (s != NULL) {
6989     s->row1 = SeqAlignRowFree (s->row1);
6990     s->row2 = SeqAlignRowFree (s->row2);
6991     s->salp = SeqAlignFree (s->salp);
6992     s = MemFree (s);
6993   }
6994   return s;
6995 }
6996 
6997 
6998 static SeqAlignSortPtr SeqAlignSortCopy (SeqAlignSortPtr s)
6999 {
7000   SeqAlignSortPtr copy = NULL;
7001 
7002   if (s != NULL) {
7003     copy = (SeqAlignSortPtr) MemNew (sizeof (SeqAlignSortData));
7004     copy->salp = SeqAlignDup (s->salp);
7005     AlnMgr2IndexSingleChildSeqAlign(copy->salp);
7006     copy->row1 = SeqAlignRowCopy (s->row1);
7007     copy->row2 = SeqAlignRowCopy (s->row2);
7008   }
7009   return copy;
7010 }
7011 
7012 
7013 static ValNodePtr SeqAlignSortListNew (SeqAlignPtr salp)
7014 {
7015   ValNodePtr list = NULL;
7016   SeqAlignPtr salp_next;
7017 
7018   while (salp != NULL) {
7019     salp_next = salp->next;
7020     salp->next = NULL;
7021     ValNodeAddPointer (&list, 0, SeqAlignSortNew (salp));
7022     salp = salp_next;
7023   }
7024   return list;
7025 }
7026 
7027 
7028 static ValNodePtr SeqAlignSortListFree (ValNodePtr vnp)
7029 {
7030   ValNodePtr vnp_next;
7031 
7032   while (vnp != NULL) {
7033     vnp_next = vnp->next;
7034     vnp->next = NULL;
7035     vnp->data.ptrvalue = SeqAlignSortFree (vnp->data.ptrvalue);
7036     vnp = ValNodeFree (vnp);
7037     vnp = vnp_next;
7038   }
7039   return vnp;
7040 }
7041 
7042 
7043 static Boolean SeqAlignSortConflict (SeqAlignSortPtr s1, SeqAlignSortPtr s2)
7044 {
7045   if (s1 == NULL || s2 == NULL) {
7046     return FALSE;
7047   } else if (SeqAlignRowConflict (s1->row1, s2->row1)) {
7048     return TRUE;
7049   } else if (SeqAlignRowConflict (s1->row2, s2->row2)) {
7050     return TRUE;
7051   } else {
7052     return FALSE;
7053   }
7054 }
7055 
7056 
7057 static Int4 SeqAlignSortListLongestInterval (ValNodePtr list)
7058 {
7059   Int4 len, max = 0;
7060   ValNodePtr vnp;
7061   SeqAlignSortPtr s;
7062 
7063   for (vnp = list; vnp != NULL; vnp = vnp->next) {
7064     s = vnp->data.ptrvalue;
7065     if (s != NULL && s->row1 != NULL) {
7066       len = SeqAlignRowLen (s->row1);
7067       if (len > max) {
7068         max = len;
7069       }
7070     }
7071   }
7072   return max;
7073 }
7074 
7075 
7076 static SeqAlignRowPtr SeqAlignRowFromSeqAlignSort (SeqAlignSortPtr s, Int4 row)
7077 {
7078   if (s == NULL) {
7079     return NULL;
7080   } else if (row == 1) {
7081     return s->row1;
7082   } else {
7083     return s->row2;
7084   }
7085 }
7086 
7087 
7088 static Uint1 SeqAlignSortRowStrand (SeqAlignSortPtr s, Int4 row)
7089 {
7090   Uint1 strand = Seq_strand_plus;
7091   SeqAlignRowPtr r;
7092 
7093   r = SeqAlignRowFromSeqAlignSort (s, row);
7094   if (r != NULL) {
7095     strand = r->strand;
7096   }
7097   return strand;
7098 }
7099 
7100 
7101 static Uint1 SeqAlignSortListFindBestStrand (ValNodePtr vnp, Int4 row)
7102 {
7103   Int4 num_plus = 0, num_minus = 0, num_align, num = 0;
7104   SeqAlignSortPtr s;
7105 
7106   /* count the alignments */
7107   num_align = ValNodeLen (vnp);
7108 
7109   /* only look at strands from the first half of the alignments */
7110   num_align = num_align / 2;
7111 
7112   while (vnp != NULL && num < num_align) {
7113     s = (SeqAlignSortPtr) vnp->data.ptrvalue;
7114     if (s != NULL) {
7115       if (SeqAlignSortRowStrand(s, row) == Seq_strand_minus) {
7116         num_minus++;
7117       } else {
7118         num_plus++;
7119       }
7120     }
7121     vnp = vnp->next;
7122     num++;
7123   }
7124 
7125   if (num_minus > num_plus) {
7126     return Seq_strand_minus;
7127   } else {
7128     return Seq_strand_plus;
7129   }
7130 }
7131 
7132 
7133 static void SeqAlignSortListMarkStrand (ValNodePtr vnp, Int4 row, Uint1 strand)
7134 {
7135   while (vnp != NULL) {
7136     if (SeqAlignSortRowStrand (vnp->data.ptrvalue, row) == strand) {
7137       vnp->choice = 1;
7138     }
7139     vnp = vnp->next;
7140   }
7141 }
7142 
7143 
7144 static void SeqAlignSortListRemoveMarked (ValNodePtr PNTR list)
7145 {
7146   ValNodePtr remove_list;
7147 
7148   if (list == NULL) {
7149     return;
7150   }
7151 
7152   remove_list = ValNodeExtractList (list, 1);
7153   remove_list = SeqAlignSortListFree (remove_list);
7154 }
7155 
7156 
7157 static Uint1 SeqAlignSortListRemoveConflictingStrands (ValNodePtr PNTR list, Int4 row)
7158 {
7159   Uint1 strand;
7160 
7161   if (list == NULL) {
7162     return Seq_strand_plus;
7163   }
7164 
7165   strand = SeqAlignSortListFindBestStrand (*list, row);
7166   if (strand == Seq_strand_plus) {
7167     SeqAlignSortListMarkStrand (*list, row, Seq_strand_minus);
7168   } else {
7169     SeqAlignSortListMarkStrand (*list, row, Seq_strand_plus);
7170   }
7171 
7172   SeqAlignSortListRemoveMarked (list);
7173   return strand;
7174 }
7175 
7176 
7177 static SeqAlignPtr SeqAlignFromSeqAlignSortList (ValNodePtr vnp)
7178 {
7179   SeqAlignPtr salp_list = NULL, salp_prev = NULL;
7180   SeqAlignSortPtr s;
7181 
7182   while (vnp != NULL) {
7183     s = (SeqAlignSortPtr) vnp->data.ptrvalue;
7184     if (s != NULL && s->salp != NULL) {
7185       s->salp->next = NULL;
7186       if (salp_prev == NULL) {
7187         salp_list = s->salp;
7188       } else {
7189         salp_prev->next = s->salp;
7190       }
7191       salp_prev = s->salp;
7192       s->salp->next = NULL;
7193       /* NULL out entry in SeqAlignSort so that it will not be freed later */
7194       s->salp = NULL;
7195     }
7196     vnp = vnp->next;
7197   }
7198   return salp_list;
7199 }
7200 
7201 
7202 static int CompareSeqAlignRow (SeqAlignRowPtr r1, SeqAlignRowPtr r2)
7203 {
7204   int rval = 0;
7205 
7206   if (r1 == NULL && r2 == NULL) {
7207     rval = 0;
7208   } else if (r1 == NULL) {
7209     rval = -1;
7210   } else if (r2 == NULL) {
7211     rval = 1;
7212   } else if (r1->start < r2->start) {
7213     rval = -1;
7214   } else if (r1->start > r2->start) {
7215     rval = 1;
7216   } else if (r1->stop < r2->stop) {
7217     rval = -1;
7218   } else if (r1->stop > r2->stop) {
7219     rval = 1;
7220   } else if (r1->strand < r2->strand) {
7221     rval = -1;
7222   } else if (r1->strand > r2->strand) {
7223     rval = 1;
7224   }
7225   return rval;
7226 }
7227 
7228 
7229 static int CompareSeqAlignSortPreferRow1 (SeqAlignSortPtr s1, SeqAlignSortPtr s2)
7230 {
7231   int rval = 0;
7232   if (s1 == NULL && s2 == NULL) {
7233     rval = 0;
7234   } else if (s1 == NULL) {
7235     rval = -1;
7236   } else if (s2 == NULL) {
7237     rval = 1;
7238   } else if ((rval = CompareSeqAlignRow (s1->row1,s2->row1)) == 0) {
7239     rval = CompareSeqAlignRow (s1->row2, s2->row2);
7240   }
7241   return rval;
7242 }
7243 
7244 
7245 static int CompareSeqAlignSortPreferRow2 (SeqAlignSortPtr s1, SeqAlignSortPtr s2)
7246 {
7247   int rval = 0;
7248   if (s1 == NULL && s2 == NULL) {
7249     rval = 0;
7250   } else if (s1 == NULL) {
7251     rval = -1;
7252   } else if (s2 == NULL) {
7253     rval = 1;
7254   } else if ((rval = CompareSeqAlignRow (s1->row2,s2->row2)) == 0) {
7255     rval = CompareSeqAlignRow (s1->row1, s2->row1);
7256   }
7257   return rval;
7258 }
7259 
7260 
7261 
7262 static int LIBCALLBACK SortVnpBySeqAlignSortRow1 (VoidPtr ptr1, VoidPtr ptr2)
7263 
7264 {
7265   ValNodePtr  vnp1;
7266   ValNodePtr  vnp2;
7267 
7268   if (ptr1 != NULL && ptr2 != NULL) {
7269     vnp1 = *((ValNodePtr PNTR) ptr1);
7270     vnp2 = *((ValNodePtr PNTR) ptr2);
7271     if (vnp1 != NULL && vnp2 != NULL) {
7272       return CompareSeqAlignSortPreferRow1 (vnp1->data.ptrvalue, vnp2->data.ptrvalue);
7273     }
7274   }
7275   return 0;
7276 }
7277 
7278 
7279 static int LIBCALLBACK SortVnpBySeqAlignSortRow2 (VoidPtr ptr1, VoidPtr ptr2)
7280 
7281 {
7282   ValNodePtr  vnp1;
7283   ValNodePtr  vnp2;
7284 
7285   if (ptr1 != NULL && ptr2 != NULL) {
7286     vnp1 = *((ValNodePtr PNTR) ptr1);
7287     vnp2 = *((ValNodePtr PNTR) ptr2);
7288     if (vnp1 != NULL && vnp2 != NULL) {
7289       return CompareSeqAlignSortPreferRow2 (vnp1->data.ptrvalue, vnp2->data.ptrvalue);
7290     }
7291   }
7292   return 0;
7293 }
7294 
7295 
7296 static ValNodePtr SeqAlignSortListMarkRepeats (ValNodePtr PNTR list, Int4 row, Int4 fuzz)
7297 {
7298   ValNodePtr repeat_start, vnp, vnp_mark;
7299   ValNodePtr repeat_list = NULL, tmp_list;
7300   SeqAlignSortPtr s1, s2;
7301   SeqAlignRowPtr  interval, r2;
7302   Int4            diff;
7303   Boolean         is_repeat;
7304 
7305   if (list == NULL || *list == NULL || (*list)->next == NULL) {
7306     return NULL;
7307   }
7308 
7309   if (row == 1) {
7310     *list = ValNodeSort (*list, SortVnpBySeqAlignSortRow1);
7311   } else {
7312     *list = ValNodeSort (*list, SortVnpBySeqAlignSortRow2);
7313   }
7314 
7315   repeat_start = *list;
7316   s1 = repeat_start->data.ptrvalue;
7317   interval = SeqAlignRowCopy (SeqAlignRowFromSeqAlignSort(s1, row));
7318   for (vnp = (*list)->next; vnp != NULL; vnp = vnp->next) {
7319     s2 = vnp->data.ptrvalue;
7320     is_repeat = FALSE;
7321     r2 = SeqAlignRowFromSeqAlignSort (s2, row);
7322 
7323     if (interval->start <= r2->start && interval->stop >= r2->stop) {
7324       /* contained */
7325       is_repeat = TRUE;
7326     } else if (r2->start <= interval->start && r2->stop >= interval->stop) {
7327       /* contained */
7328       is_repeat = TRUE;
7329     } else if ((diff = RowDiff (interval, r2)) > -1 && diff < fuzz) {
7330       is_repeat = TRUE;
7331     }
7332     if (is_repeat) {
7333       if (interval->start > r2->start) {
7334         interval->start = r2->start;
7335       }
7336       if (interval->stop < r2->stop) {
7337         interval->stop = r2->stop;
7338       }
7339     } else {
7340       if (repeat_start->next != vnp) {
7341         tmp_list = NULL;
7342         for (vnp_mark = repeat_start; vnp_mark != vnp; vnp_mark = vnp_mark->next) {
7343           /* add copy to list of repeats */
7344           ValNodeAddPointer (&tmp_list, 0, SeqAlignSortCopy (vnp_mark->data.ptrvalue));
7345           /* mark as repeat for this row */
7346           vnp_mark->choice = row;
7347         }
7348         ValNodeAddPointer (&repeat_list, 0, tmp_list);
7349       }
7350       repeat_start = vnp;
7351       s1 = vnp->data.ptrvalue;
7352       interval = SeqAlignRowFree (interval);
7353       interval = SeqAlignRowCopy (SeqAlignRowFromSeqAlignSort(s1, row));
7354     }
7355   }
7356 
7357   if (repeat_start->next != NULL) {
7358     tmp_list = NULL;
7359     for (vnp_mark = repeat_start; vnp_mark != vnp; vnp_mark = vnp_mark->next) {
7360       /* add copy to list of repeats */
7361       ValNodeAddPointer (&tmp_list, 0, SeqAlignSortCopy (vnp_mark->data.ptrvalue));
7362       /* mark as repeat for this row */
7363       vnp_mark->choice = row;
7364     }
7365     ValNodeAddPointer (&repeat_list, 0, tmp_list);
7366   }
7367 
7368   interval = SeqAlignRowFree (interval);
7369   return repeat_list;
7370 }
7371 
7372 
7373 static int SeqAlignRowFuzzyCompare (SeqAlignRowPtr r1, SeqAlignRowPtr r2, Int4 fuzz)
7374 {
7375   if (r1 == NULL && r2 == NULL) {
7376     return 0;
7377   } else if (r1 == NULL) {
7378     return -1;
7379   } else if (r2 == NULL) {
7380     return 1;
7381   }
7382 
7383   if (r1->stop < r2->start || r1->stop - r2->start < fuzz) {
7384     return -1;
7385   } else if (r2->stop < r1->start || r2->stop - r1->start < fuzz) {
7386     return 1;
7387   } else {
7388     return 0;
7389   }
7390 }
7391 
7392 
7393 static int SeqAlignSortFuzzyCompare (SeqAlignSortPtr s1, SeqAlignSortPtr s2, Int4 row, Int4 fuzz)
7394 {
7395   if (s1 == NULL && s2 == NULL) {
7396     return 0;
7397   } else if (s1 == NULL) {
7398     return -1;
7399   } else if (s2 == NULL) {
7400     return 1;
7401   } else if (row == 1) {
7402     return SeqAlignRowFuzzyCompare (s1->row1, s2->row1, fuzz);
7403   } else {
7404     return SeqAlignRowFuzzyCompare (s1->row2, s2->row2, fuzz);
7405   }
7406 }
7407 
7408 
7409 static void SeqAlignSortListRemoveIntervalsOutOfOrder (ValNodePtr PNTR list, Int4 row, Int4 fuzz)
7410 {
7411   ValNodePtr vnp, vnp_prev = NULL;
7412 
7413   if (list == NULL) {
7414     return;
7415   }
7416 
7417   for (vnp = *list; vnp != NULL; vnp = vnp->next) {
7418     if (vnp_prev != NULL && SeqAlignSortFuzzyCompare (vnp_prev->data.ptrvalue, vnp->data.ptrvalue, row, fuzz) != -1) {
7419       vnp->choice = 1;
7420     } else if (vnp->next != NULL && SeqAlignSortFuzzyCompare (vnp->data.ptrvalue, vnp->next->data.ptrvalue, row, fuzz) != -1) {
7421       if (vnp->next->next != NULL 
7422           && SeqAlignSortFuzzyCompare (vnp->data.ptrvalue, vnp->next->next->data.ptrvalue, row, fuzz) == -1
7423           && SeqAlignSortFuzzyCompare (vnp->next->data.ptrvalue, vnp->next->next->data.ptrvalue, row, fuzz) != -1) {
7424         /* ok to keep this one, we'll toss the next one */
7425       } else {
7426         vnp->choice = 1;
7427       }
7428     }
7429     if (vnp->choice == 0) {
7430       vnp_prev = vnp;
7431     }
7432   }
7433 
7434   SeqAlignSortListRemoveMarked (list);
7435 }
7436 
7437 
7438 static Int4 GetRepeatIntervalFuzz (SeqAlignSortPtr s_repeat, SeqAlignSortPtr s_before, SeqAlignSortPtr s_after, Int4 row)
7439 {
7440   Int4 start_fuzz = 0, end_fuzz = 0;
7441 
7442   if (s_repeat == NULL) {
7443     return -1;
7444   }
7445 
7446   if (s_before != NULL) {
7447     if (row == 1) {
7448       start_fuzz = ABS (s_repeat->row1->start - s_before->row1->stop);
7449     } else {
7450       start_fuzz = ABS (s_repeat->row2->start - s_before->row2->stop);
7451     }
7452   }
7453   if (s_after != NULL) {
7454     if (row == 1) {
7455       end_fuzz = ABS (s_after->row1->start - s_repeat->row1->stop);
7456     } else {
7457       end_fuzz = ABS (s_after->row2->start - s_repeat->row2->stop);
7458     }
7459   }
7460 
7461   return start_fuzz + end_fuzz;
7462 }
7463 
7464 
7465 static int StrandedSeqAlignSortRowCompare (SeqAlignSortPtr s1, SeqAlignSortPtr s2, Int4 row, Int4 fuzz)
7466 {
7467   SeqAlignRowPtr r1 = NULL, r2 = NULL;
7468   int rval = 0;
7469   Uint1 strand = Seq_strand_plus;
7470 
7471   if (s1 == NULL || s2 == NULL) {
7472     return 0;
7473   } 
7474 
7475   r1 = SeqAlignRowFromSeqAlignSort (s1, row);
7476   r2 = SeqAlignRowFromSeqAlignSort (s2, row);
7477   strand = r1->strand;
7478 
7479   if (strand == Seq_strand_minus) {
7480     if (r1->start < r2->start - fuzz) {
7481       rval = 1;
7482     } else if (r1->start >r2->start + fuzz) {
7483       rval = -1;
7484     }
7485   } else {
7486     if (r1->start > r2->start + fuzz) {
7487       rval = 1;
7488     } else if (r1->stop < r2->stop - fuzz) {
7489       rval = -1;
7490     } 
7491   }
7492 
7493   return rval;
7494 }
7495 
7496 
7497 static Boolean FindSeqAlignSortWithPoint (ValNodePtr list, Int4 point, Int4 row)
7498 {
7499   ValNodePtr vnp;
7500   SeqAlignRowPtr r;
7501   SeqAlignSortPtr s;
7502   Boolean found = FALSE;
7503 
7504   for (vnp = list; vnp != NULL; vnp = vnp->next) {
7505     s = vnp->data.ptrvalue;
7506     r = SeqAlignRowFromSeqAlignSort (s, row);
7507     if (point >= r->start && point <= r->stop) {
7508       found = TRUE;
7509     }
7510   }
7511   return found;
7512 }
7513 
7514 
7515 static ValNodePtr FindBestRepeat (ValNodePtr PNTR repeat_list, SeqAlignSortPtr s_before, SeqAlignSortPtr s_after, Int4 row, Int4 fuzz)
7516 {
7517   Int4       best_diff = -1, diff;
7518   ValNodePtr vnp, vnp_best = NULL, vnp_best_prev = NULL, vnp_prev = NULL;
7519   SeqAlignSortPtr s_this;
7520 
7521   if (repeat_list == NULL || *repeat_list == NULL) {
7522     return NULL;
7523   }
7524 
7525   for (vnp = *repeat_list; vnp != NULL; vnp = vnp->next) {
7526     s_this = vnp->data.ptrvalue;
7527 
7528     if (StrandedSeqAlignSortRowCompare (s_this, s_before, row, fuzz) < 0
7529       || StrandedSeqAlignSortRowCompare (s_this, s_after, row, fuzz) > 0) {
7530       /* skip - already out of order */
7531     } else {
7532       diff = GetRepeatIntervalFuzz (vnp->data.ptrvalue, s_before, s_after, row);
7533       if (diff > -1 && (best_diff < 0 || best_diff > diff)) {
7534         vnp_best = vnp;
7535         vnp_best_prev = vnp_prev;
7536         best_diff = diff;
7537       }
7538     }
7539     vnp_prev = vnp;
7540   }
7541 
7542   if (vnp_best != NULL) {
7543     if (vnp_best_prev == NULL) {
7544       *repeat_list = vnp_best->next;
7545     } else {
7546       vnp_best_prev->next = vnp_best->next;
7547     }
7548     vnp_best->next = NULL;
7549   }
7550 
7551   return vnp_best;
7552 }
7553 
7554 
7555 static void RemoveRepeatsCoincidingWithBest (ValNodePtr PNTR repeat_list, ValNodePtr best, Int4 row, Int4 fuzz)
7556 {
7557   ValNodePtr vnp;
7558   SeqAlignSortPtr s_best, s;
7559   SeqAlignRowPtr r_best, r2;
7560   Boolean        is_repeat;
7561   Int4           diff;
7562 
7563   if (repeat_list == NULL || *repeat_list == NULL || best == NULL) {
7564     return;
7565   }
7566 
7567   s_best = best->data.ptrvalue;
7568   r_best = SeqAlignRowFromSeqAlignSort (s_best, row);
7569 
7570   for (vnp = *repeat_list; vnp != NULL; vnp = vnp->next) {
7571     s = vnp->data.ptrvalue;
7572     r2 = SeqAlignRowFromSeqAlignSort (s, row);
7573 
7574     is_repeat = FALSE;
7575     if (r_best->start <= r2->start && r_best->stop >= r2->stop) {
7576       /* contained */
7577       is_repeat = TRUE;
7578     } else if (r2->start <= r_best->start && r2->stop >= r_best->stop) {
7579       /* contained */
7580       is_repeat = TRUE;
7581     } else if (r2->stop < r_best->stop || r2->stop - r_best->stop < fuzz) {
7582       is_repeat = TRUE;
7583     } else if ((diff = RowDiff (r_best, r2)) > -1 && diff < fuzz) {
7584       is_repeat = TRUE;
7585     }
7586 
7587     if (is_repeat) {
7588       vnp->choice = 1;
7589     }
7590   }
7591   SeqAlignSortListRemoveMarked (repeat_list);
7592 }
7593 
7594 
7595 static ValNodePtr ExtractLongestSeqAlignRow (ValNodePtr PNTR list, Int4 row)
7596 {
7597   ValNodePtr vnp, vnp_prev = NULL, rval = NULL;
7598   Int4       longest = 0, len;
7599   Boolean    found = FALSE;
7600 
7601   if (list == NULL || *list == NULL) {
7602     return NULL;
7603   }
7604 
7605   for (vnp = *list; vnp != NULL; vnp = vnp->next) {
7606     len = SeqAlignRowLen (SeqAlignRowFromSeqAlignSort (vnp->data.ptrvalue, row));
7607     if (longest < len) {
7608       longest = len;
7609     }
7610   }
7611 
7612   for (vnp = *list; vnp != NULL && !found; vnp = vnp->next) {
7613     len = SeqAlignRowLen (SeqAlignRowFromSeqAlignSort (vnp->data.ptrvalue, row));
7614     if (len == longest) {
7615       if (vnp_prev == NULL) {
7616         *list = vnp->next;
7617       } else {
7618         vnp_prev->next = vnp->next;
7619       }
7620       vnp->next = NULL;
7621       rval = vnp;
7622       found = TRUE;
7623     }
7624     vnp_prev = vnp;
7625   }
7626   return rval;
7627 }
7628 
7629 
7630 static void InsertBestRepeat (ValNodePtr repeat_list, ValNodePtr PNTR sorted_list, Int4 row, Int4 fuzz)
7631 {
7632   ValNodePtr vnp, vnp_prev = NULL, vnp_new;
7633   SeqAlignSortPtr s_repeat, s, s_before = NULL;
7634   Boolean         found = TRUE;
7635   SeqAlignRowPtr  r1, r2;
7636   Int4 other_row;
7637 
7638   if (repeat_list == NULL || sorted_list == NULL) {
7639     return;
7640   }
7641 
7642   if (row == 1) {
7643     other_row = 2;
7644   } else {
7645     other_row = 1;
7646   }
7647   if (sorted_list == NULL || *sorted_list == NULL) {
7648     /* keep longest, mark others for removal */
7649     vnp = ExtractLongestSeqAlignRow (&repeat_list, row);
7650     ValNodeLink (sorted_list,vnp);
7651     repeat_list = SeqAlignSortListFree (repeat_list);
7652   } else {
7653     s_repeat = repeat_list->data.ptrvalue;
7654     found = FALSE;
7655     vnp = *sorted_list;
7656 
7657     /* find first entry that is after this repeat, and insert before that */
7658     while (vnp != NULL && !found) {
7659       if (SeqAlignSortConflict (s_repeat, vnp->data.ptrvalue)) {
7660         found = TRUE;
7661         break;
7662       }
7663 
7664       s = vnp->data.ptrvalue;
7665       r1 = SeqAlignRowFromSeqAlignSort (s, row);
7666       r2 = SeqAlignRowFromSeqAlignSort (s_repeat, row);
7667 
7668       if (r1->start == r2->start && r1->stop == r2->stop) {
7669         /* this is a duplicate.  throw it away. */
7670         found = TRUE;
7671         break;
7672       }
7673 
7674       if (r1->start > r2->start || r2->start - r1->start < fuzz) {
7675         while (repeat_list != NULL) {
7676           /* extract best repeat */
7677           vnp_new = FindBestRepeat (&repeat_list, s_before, vnp->data.ptrvalue, other_row, fuzz);
7678           if (vnp_new == NULL) {
7679             repeat_list = SeqAlignSortListFree (repeat_list);
7680           } else {
7681             RemoveRepeatsCoincidingWithBest (&repeat_list, vnp_new, row, fuzz);
7682             vnp_new->next = vnp;
7683             if (vnp_prev == NULL) {
7684               *sorted_list = vnp_new;
7685             } else {
7686               vnp_prev->next = vnp_new;
7687             }
7688             vnp_prev = vnp_new;
7689             s_before = vnp_new->data.ptrvalue;
7690           }
7691         }
7692         found = TRUE;
7693       }
7694       if (!found) {
7695         s_before = vnp->data.ptrvalue;
7696         vnp_prev = vnp;
7697         vnp = vnp->next;
7698       }
7699     }
7700     if (!found) {
7701       while (repeat_list != NULL) {
7702         /* extract best repeat */
7703         vnp_new = FindBestRepeat (&repeat_list, s_before, NULL, other_row, fuzz);
7704         if (vnp_new == NULL) {
7705           repeat_list = SeqAlignSortListFree (repeat_list);
7706         } else {
7707           RemoveRepeatsCoincidingWithBest (&repeat_list, vnp_new, row, fuzz);
7708           vnp_new->next = NULL;
7709           if (vnp_prev == NULL) {
7710             *sorted_list = vnp_new;
7711           } else {
7712             vnp_prev->next = vnp_new;
7713           }
7714           vnp_prev = vnp_new;
7715           s_before = vnp_new->data.ptrvalue;
7716         }
7717       }
7718     }
7719   }
7720 
7721   SeqAlignSortListRemoveMarked (&repeat_list);
7722   repeat_list = ValNodeFree (repeat_list);
7723 }
7724 
7725 
7726 static Int4 FindLongestRepeatInterval (ValNodePtr repeat_list)
7727 {
7728   Int4 len, max = 0;
7729   ValNodePtr vnp_r, vnp;
7730   SeqAlignSortPtr s;
7731 
7732   for (vnp_r = repeat_list; vnp_r != NULL; vnp_r = vnp_r->next) {
7733     for (vnp = vnp_r->data.ptrvalue; vnp != NULL; vnp = vnp->next) {
7734       s = vnp->data.ptrvalue;
7735       if (s != NULL && s->row1 != NULL) {
7736         len = SeqAlignRowLen (s->row1);
7737         if (len > max) {
7738           max = len;
7739         }
7740       }
7741     }
7742   }
7743   return max;
7744 }
7745 
7746 
7747 /* note - we want to sort from highest to lowest */
7748 static int LIBCALLBACK SortVnpByRepeatList (VoidPtr ptr1, VoidPtr ptr2)
7749 
7750 {
7751   ValNodePtr  vnp1;
7752   ValNodePtr  vnp2;
7753   Int4        len1, len2;
7754   int         rval = 0;
7755 
7756   if (ptr1 != NULL && ptr2 != NULL) {
7757     vnp1 = *((ValNodePtr PNTR) ptr1);
7758     vnp2 = *((ValNodePtr PNTR) ptr2);
7759     if (vnp1 != NULL && vnp2 != NULL) {
7760       len1 = SeqAlignSortListLongestInterval (vnp1->data.ptrvalue);
7761       len2 = SeqAlignSortListLongestInterval (vnp2->data.ptrvalue);
7762       if (len1 < len2) {
7763         rval = 1;
7764       } else if (len2 < len1) {
7765         rval = -1;
7766       }
7767     }
7768   }
7769   return rval;
7770 }
7771 
7772 
7773 
7774 
7775 static void SelectBestRepeatsFromList (SeqAlignPtr PNTR salp)
7776 {
7777   ValNodePtr list, vnp;
7778   ValNodePtr row1_repeats, row2_repeats;
7779   Uint1 strand1, strand2;
7780   SeqAlignPtr    tmp_salp;
7781   Int4           fuzz = 15;
7782   Int4           missing = 600;
7783   Int4           len1, len2;
7784 
7785   if (salp == NULL || *salp == NULL || (*salp)->next == NULL) {
7786     return;
7787   }
7788 
7789   list = SeqAlignSortListNew (*salp);
7790 
7791   FindSeqAlignSortWithPoint (list, missing, 1);
7792 
7793   /* remove conflicting strands for row 1 */
7794   strand1 = SeqAlignSortListRemoveConflictingStrands (&list, 1);
7795 
7796   /* remove conflicting strands for row 1 */
7797   strand2 = SeqAlignSortListRemoveConflictingStrands (&list, 2);
7798 
7799   FindSeqAlignSortWithPoint (list, missing, 1);
7800 
7801   if (list != NULL && list->next != NULL) {
7802     row1_repeats = SeqAlignSortListMarkRepeats (&list, 1, fuzz);
7803     row1_repeats = ValNodeSort (row1_repeats, SortVnpByRepeatList);
7804     row2_repeats = SeqAlignSortListMarkRepeats (&list, 2, fuzz);
7805     row2_repeats = ValNodeSort (row2_repeats, SortVnpByRepeatList);
7806     vnp = ValNodeExtractList (&list, 1);
7807     vnp = SeqAlignSortListFree (vnp);
7808     vnp = ValNodeExtractList (&list, 2);
7809     vnp = SeqAlignSortListFree (vnp);
7810 
7811     FindSeqAlignSortWithPoint (list, missing, 1);
7812 
7813     /* remove scaffold intervals that are out of order */
7814     list = ValNodeSort (list, SortVnpBySeqAlignSortRow1);
7815     SeqAlignSortListRemoveIntervalsOutOfOrder (&list, 1, fuzz);
7816     list = ValNodeSort (list, SortVnpBySeqAlignSortRow2);
7817     SeqAlignSortListRemoveIntervalsOutOfOrder (&list, 2, fuzz);
7818 
7819     FindSeqAlignSortWithPoint (list, missing, 1);
7820 
7821     /* Remove overlaps.*/
7822     list = ValNodeSort (list, SortVnpBySeqAlignSortRow1);
7823     tmp_salp = SeqAlignFromSeqAlignSortList (list);
7824     list = SeqAlignSortListFree (list);
7825     ACT_RemoveInconsistentAlnsFromSet (tmp_salp, 1, 1);
7826     list = SeqAlignSortListNew (tmp_salp);
7827 
7828     FindSeqAlignSortWithPoint (list, missing, 1);
7829 
7830     len1 = FindLongestRepeatInterval (row1_repeats);
7831     len2 = FindLongestRepeatInterval (row2_repeats);
7832 
7833     if (len1 >= len2) {
7834       /* for each repeat on row 1, we want to pick the most consistent interval for row 2 */
7835       list = ValNodeSort (list, SortVnpBySeqAlignSortRow1);
7836       for (vnp = row1_repeats; vnp != NULL; vnp = vnp->next) {   
7837         InsertBestRepeat (vnp->data.ptrvalue, &list, 1, fuzz);
7838       }
7839       row1_repeats = ValNodeFree (row1_repeats);
7840 
7841       /* for each repeat on row 2, we want to pick the most consistent interval for row 1 */
7842       list = ValNodeSort (list, SortVnpBySeqAlignSortRow2);
7843       for (vnp = row2_repeats; vnp != NULL; vnp = vnp->next) {   
7844         InsertBestRepeat (vnp->data.ptrvalue, &list, 2, fuzz);
7845       }
7846       row2_repeats = ValNodeFree (row2_repeats);
7847     } else {
7848       /* for each repeat on row 2, we want to pick the most consistent interval for row 1 */
7849       list = ValNodeSort (list, SortVnpBySeqAlignSortRow2);
7850       for (vnp = row2_repeats; vnp != NULL; vnp = vnp->next) {   
7851         InsertBestRepeat (vnp->data.ptrvalue, &list, 2, fuzz);
7852       }
7853       row2_repeats = ValNodeFree (row2_repeats);
7854 
7855       /* for each repeat on row 1, we want to pick the most consistent interval for row 2 */
7856       list = ValNodeSort (list, SortVnpBySeqAlignSortRow1);
7857       for (vnp = row1_repeats; vnp != NULL; vnp = vnp->next) {   
7858         InsertBestRepeat (vnp->data.ptrvalue, &list, 1, fuzz);
7859       }
7860       row1_repeats = ValNodeFree (row1_repeats);
7861     }
7862   }
7863 
7864   list = ValNodeSort (list, SortVnpBySeqAlignSortRow1);
7865   *salp = SeqAlignFromSeqAlignSortList (list);
7866 
7867   list = SeqAlignSortListFree (list);
7868 }
7869 
7870 
7871 static void amconssetfree(AMConsSetPtr acp)
7872 {
7873    AMConsSetPtr  acp_next;
7874 
7875    while (acp != NULL)
7876    {
7877       acp_next = acp->next;
7878       MemFree(acp->starts);
7879       MemFree(acp->stops);
7880       MemFree(acp->strands);
7881       MemFree(acp);
7882       acp = acp_next;
7883    }
7884 }
7885 
7886 static int LIBCALLBACK CKA_SortForConsistent(VoidPtr ptr1, VoidPtr ptr2)
7887 {
7888    AMConsSetPtr  acp1;
7889    AMConsSetPtr  acp2;
7890    FloatHi       bitscore;
7891    FloatHi       evalue;
7892    Int4          number;
7893    SAIndex2Ptr   saip1;
7894    SAIndex2Ptr   saip2;
7895 
7896    acp1 = *((AMConsSetPtr PNTR)ptr1);
7897    acp2 = *((AMConsSetPtr PNTR)ptr2);
7898    saip1 = (SAIndex2Ptr)(acp1->sap->saip);
7899    saip2 = (SAIndex2Ptr)(acp2->sap->saip);
7900    if (saip1->score == 0)
7901       GetScoreAndEvalue(acp1->sap, &saip1->score, &bitscore, &evalue, &number);
7902    if (saip2->score == 0)
7903       GetScoreAndEvalue(acp2->sap, &saip2->score, &bitscore, &evalue, &number);
7904    if (saip1->score > saip2->score)
7905       return -1;
7906    else if (saip1->score < saip2->score)
7907       return 1;
7908    else
7909       return 0;
7910 }
7911 
7912 
7913 static void CKA_RemoveInconsistentAlnsFromSet(SeqAlignPtr sap_head, Int4 fuzz)
7914 {
7915    AMConsSetPtr  acp;
7916    AMConsSetPtr  acp_head;
7917    AMConsSetPtr  acp_prev;
7918    AMConsSetPtr  PNTR acparray;
7919    DenseSegPtr   dsp;
7920    Int4          i;
7921    Int4          j;
7922    Int4          k;
7923    Int4          lfuzz;
7924    SeqAlignPtr   newsap;
7925    Int4          numrows;
7926    Int4          numsaps;
7927    Int4          orientation;
7928    Int4          row;
7929    SAIndex2Ptr   saip;
7930    SeqAlignPtr   salp_head;
7931    SeqAlignPtr   salp_prev;
7932    SeqAlignPtr   sap;
7933    SeqAlignPtr   sapnext;
7934    Int4          score;
7935    SeqIdPtr      sip;
7936    SeqIdPtr      sip_head;
7937    Uint1         strand;
7938 
7939    lfuzz = fuzz;
7940    if (fuzz < 0)
7941       fuzz = 1;
7942    sap = (SeqAlignPtr)(sap_head->segs);
7943    if (sap->next == NULL)
7944       return;
7945    dsp = (DenseSegPtr)(sap->segs);
7946    sip_head = dsp->ids;
7947    numrows = AlnMgr2GetNumRows(sap);
7948    acp_head = NULL;
7949    strand = AlnMgr2GetNthStrand(sap, 1);
7950    numsaps = 0;
7951    while (sap != NULL)
7952    {
7953       if (AlnMgr2GetNumRows(sap) != numrows)
7954       {
7955          amconssetfree(acp_head);
7956          return;
7957       }
7958       numsaps++;
7959       acp = (AMConsSetPtr)MemNew(sizeof(AMConsSet));
7960       acp->starts = (Int4Ptr)MemNew(numrows*sizeof(Int4));
7961       acp->stops = (Int4Ptr)MemNew(numrows*sizeof(Int4));
7962       acp->strands = (Uint1Ptr)MemNew(numrows*sizeof(Uint1));
7963       acp->which = (Int4Ptr)MemNew(numrows*sizeof(Int4));
7964       acp->sap = sap;
7965       if (acp_head != NULL)
7966       {
7967          acp_prev->next = acp;
7968          acp_prev = acp;
7969       } else
7970          acp_head = acp_prev = acp;
7971       sip = sip_head;
7972       row = AlnMgr2GetFirstNForSip(sap, sip);
7973       if (row <= 0)
7974       {
7975          amconssetfree(acp_head);
7976          return;
7977       }
7978       if (acp->strands[row] != strand)
7979       {
7980          sapnext = acp->sap->next;
7981          acp->sap->next = NULL;
7982          score = ((SAIndex2Ptr)(acp->sap->saip))->score;
7983          SeqAlignListReverseStrand(acp->sap);
7984          AMAlignIndexFreeEitherIndex(acp->sap);
7985          AlnMgr2IndexSingleChildSeqAlign(acp->sap);
7986          saip = (SAIndex2Ptr)(acp->sap->saip);
7987          saip->score = score;
7988          acp->strands[row] = strand;
7989          acp->sap->next = sapnext;
7990       }
7991       for (i=0; i<numrows; i++)
7992       {
7993          acp->which[i] = row;
7994          AlnMgr2GetNthSeqRangeInSA(sap, i+1, &acp->starts[i], &acp->stops[i]);
7995          acp->strands[i] = AlnMgr2GetNthStrand(sap, i+1);
7996       }
7997       sap = sap->next;
7998    }
7999    acparray = (AMConsSetPtr PNTR)MemNew(numsaps*sizeof(AMConsSetPtr));
8000    acp = acp_head;
8001    i = 0;
8002    while (acp != NULL)
8003    {
8004       acparray[i] = acp;
8005       acp = acp->next;
8006       i++;
8007    }
8008    HeapSort(acparray, numsaps, sizeof(AMConsSetPtr), CKA_SortForConsistent);
8009    /* orientation -1 means that ith is before jth in ALL rows, 1 means ith is after jth in ALL rows */
8010    for (i=0; i<numsaps; i++)
8011    {
8012       if (acparray[i]->used != -1)
8013       {
8014          for (j=i+1; j<numsaps; j++)
8015          {
8016             orientation = 0;
8017             for (k=0; acparray[j]->used != -1 && k<numrows; k++)
8018             {
8019                if (acparray[i]->starts[k] - fuzz < acparray[j]->starts[k])
8020                {
8021                   if (acparray[i]->stops[k] - fuzz < acparray[j]->starts[k])
8022                   {
8023                      if (orientation == 0)
8024                      {
8025                         if (acparray[i]->strands[k] == Seq_strand_minus)
8026                            orientation = 1;
8027                         else
8028                            orientation = -1;
8029                      }
8030                   } else
8031                   {
8032                      if (lfuzz >= 0) /* just mark it for deletion */
8033                         acparray[j]->used = -1;
8034                      else /* truncate it */
8035                      {
8036                         if (acparray[j]->stops[k] >
8037                             acparray[i]->stops[k] + CKA_blast_wordsize)
8038                         {
8039                            newsap = AlnMgr2GetSubAlign(acparray[j]->sap, acparray[i]->stops[k]+1,
8040  acparray[j]->stops[k], k+1, TRUE);
8041                            AlnMgr2IndexSingleChildSeqAlign(newsap);
8042                            SeqAlignFree(acparray[j]->sap);
8043                            acparray[j]->sap = newsap;
8044                            acparray[j]->starts[k] = acparray[i]->stops[k]+1;
8045                         } else
8046                            acparray[j]->used = -1;
8047                      }
8048                   }
8049                } else if (acparray[i]->starts[k] - fuzz > acparray[j]->starts[k])
8050                {
8051                  if (acparray[i]->starts[k] + fuzz > acparray[j]->stops[k])
8052                   {
8053                      if (orientation == 0)
8054                      {
8055                         if (acparray[i]->strands[k] == Seq_strand_minus)
8056                            orientation = -1;
8057                         else
8058                            orientation = 1;
8059                      }
8060                   } else
8061                   {
8062                      if (lfuzz >= 0) /* mark for deletion */
8063                         acparray[j]->used = -1;
8064                      else /* truncate */
8065                      {
8066                         if (acparray[j]->starts[k] <
8067                             acparray[i]->starts[k] - CKA_blast_wordsize)
8068                         {
8069                            newsap = AlnMgr2GetSubAlign(acparray[j]->sap, acparray[j]->starts[k], acparray[i]->starts[k]-1, k+1, TRUE);
8070                            AlnMgr2IndexSingleChildSeqAlign(newsap);
8071                            SeqAlignFree(acparray[j]->sap);
8072                            acparray[j]->sap = newsap;
8073                            acparray[j]->stops[k] = acparray[i]->starts[k]-1;
8074                         } else
8075                            acparray[j]->used = -1;
8076                      }
8077                   }
8078                } else
8079                   acparray[j]->used = -1;
8080             }
8081          }
8082       }
8083    }
8084    /* now free all the unused ones, stick the rest back together, reindex, and return */
8085    salp_head = salp_prev = NULL;
8086    for (i=0; i<numsaps; i++)
8087    {
8088       if (acparray[i]->used == -1)
8089       {
8090          SeqAlignFree(acparray[i]->sap);
8091          acparray[i]->sap = NULL;
8092       } else
8093       {
8094          if (salp_head != NULL)
8095          {
8096             salp_prev->next = acparray[i]->sap;
8097             salp_prev = acparray[i]->sap;
8098             salp_prev->next = NULL;
8099          } else
8100          {
8101             salp_head = salp_prev = acparray[i]->sap;
8102             salp_prev->next = NULL;
8103          }
8104       }
8105    }
8106    amconssetfree(acp_head);
8107    MemFree(acparray);
8108    sap_head->segs = (Pointer)(salp_head);
8109    AMAlignIndex2Free2(sap_head->saip);
8110    AlnMgr2IndexLite(sap_head);
8111 }
8112 
8113 
8114 static BioseqPtr ReadFromTraceDb (CharPtr number)
8115 
8116 {
8117   BioseqPtr    bsp = NULL;
8118   CONN         conn;
8119   time_t       currtime, starttime;
8120   FILE         *fp;
8121   time_t       max = 0;
8122   size_t       n_written;
8123   Char         path [PATH_MAX];
8124   Char         query [64];
8125   SeqEntryPtr  sep = NULL;
8126   EIO_Status   status;
8127   STimeout     timeout;
8128   long int     val;
8129 
8130   if (StringHasNoText (number)) return NULL;
8131   if (sscanf (number, "%ld", &val) != 1) return NULL;
8132   sprintf (query, "cmd=raw&query=retrieve+fasta+%ld", (long) val);
8133   conn = QUERY_OpenUrlQuery ("www.ncbi.nlm.nih.gov", 80, "/Traces/trace.cgi",
8134                              query, "Sequin", 30, eMIME_T_NcbiData,
8135                              eMIME_Fasta, eENCOD_None, 0);
8136   if (conn == NULL) return NULL;
8137   status = CONN_Write (conn, (const void *) query, StringLen (query),
8138                        &n_written, eIO_WritePersist);
8139   if (status != eIO_Success) return NULL;
8140   QUERY_SendQuery (conn);
8141 
8142 #ifdef OS_MAC 
8143   timeout.sec = 0;
8144   timeout.usec = 0;
8145 #else
8146   timeout.sec = 100;
8147   timeout.usec = 0;
8148 #endif
8149 
8150   starttime = GetSecs ();
8151   while ((status = CONN_Wait (conn, eIO_Read, &timeout)) != eIO_Success && max < 300) {
8152     currtime = GetSecs ();
8153     max = currtime - starttime;
8154   }
8155 
8156   if (status == eIO_Success) {
8157     TmpNam (path);
8158     fp = FileOpen (path, "w");
8159     QUERY_CopyResultsToFile (conn, fp);
8160     FileClose (fp);
8161     /*
8162     LaunchGeneralTextViewer (path, "QueueFastaQueryToURL results");
8163     */
8164     fp = FileOpen (path, "r");
8165     sep = FastaToSeqEntry (fp, TRUE);
8166     FileClose (fp);
8167     FileRemove (path);
8168     if (sep != NULL) {
8169       bsp = FindNucBioseq (sep);
8170     }
8171   }
8172   CONN_Close (conn);
8173 
8174   return bsp;
8175 }
8176 
8177 static SeqAlignPtr GetNewBlastTPAHistAlignPiece (BioseqPtr bsp1, BioseqPtr bsp2)
8178 {
8179    BLAST_SummaryOptions *options = NULL;
8180    SeqAlignPtr          salp = NULL;
8181 
8182    BLAST_SummaryOptionsInit(&options);
8183    options->program = eBlastn;
8184    options->use_megablast = TRUE;
8185    options->word_size = CKA_blast_wordsize;
8186    options->cutoff_evalue = CKA_blast_expect_value;
8187    options->hint = eNone;
8188    options->gap_x_dropoff = 30;
8189    options->gap_open = -1;
8190    options->gap_extend = -1;
8191    options->filter_string = StringSave ("F");
8192 
8193    BLAST_TwoSequencesSearch(options, bsp1, bsp2, &salp);
8194    BLAST_SummaryOptionsFree(options);
8195 
8196    return salp;
8197 }
8198 
8199 
8200 static SeqAlignPtr GetOldBlastTPAHistAlignPiece (BioseqPtr bsp1, BioseqPtr bsp2)
8201 {
8202   BLAST_OptionsBlkPtr  options;
8203   SeqAlignPtr          salp;
8204 
8205   options = BLASTOptionNew("blastn", TRUE);
8206   options->is_megablast_search = TRUE;
8207   options->gap_open = options->gap_extend = 0;
8208   options->wordsize = CKA_blast_wordsize;
8209   options->expect_value = CKA_blast_expect_value;
8210 
8211   salp = BlastTwoSequences(bsp1, bsp2, "blastn", options);
8212   BLASTOptionDelete(options);
8213 
8214   return salp;
8215 }
8216 
8217 
8218 static Boolean IsHUPIDAccession (BioseqPtr bsp)
8219 {
8220   Int4 j, num;
8221   ObjMgrDataPtr omdp;
8222   OMUserDataPtr omudp;
8223   ObjMgrProcPtr ompp = NULL;
8224   ObjMgrPtr omp;
8225   ObjMgrDataPtr PNTR omdpp;
8226   Boolean           rval = FALSE;
8227 
8228   ompp = NULL;
8229   omp = ObjMgrReadLock();
8230 
8231   omdpp = omp->datalist;
8232   if (omdpp != NULL) {
8233     num = omp->currobj;
8234     for (j = 0; j < num && ompp == NULL; j++) {
8235       if (omdpp[j] != NULL && omdpp[j]->datatype == OBJ_BIOSEQ 
8236           && omdpp[j]->dataptr == bsp) {
8237 
8238         omdp = ObjMgrFindTop (omp, omdpp[j]);
8239         if (omdp != NULL) {
8240           for (omudp = omdp->userdata; omudp != NULL && ompp == NULL; omudp = omudp->next)
8241           {
8242             if (omudp->proctype == OMPROC_FETCH)  /* caching function */
8243             {
8244               ompp = ObjMgrProcFind(omp, omudp->procid, NULL, 0);
8245             }
8246           }
8247         }
8248       }
8249     }
8250   }
8251 
8252   if (ompp != NULL && StringCmp (ompp->procname, "HUPBioseqFetch") == 0) 
8253   {
8254     rval = TRUE;
8255   }
8256 
8257   ObjMgrUnlock();
8258   return rval;
8259 }
8260 
8261 
8262 static SeqAlignPtr CKA_MakeAlign(BioseqPtr bsp, CKA_AccPtr acc_head, LogInfoPtr lip)
8263 {
8264    CKA_AccPtr           acc;
8265    CKA_AccPtr           acc_new;
8266    CKA_AccPtr           acc_new_head_head;
8267    CKA_AccPtr           acc_new_head;
8268    CKA_AccPtr           acc_new_prev;
8269    SeqAlignPtr          allsap;
8270    SeqAlignPtr          allsap_prev;
8271    AMAlignIndex2Ptr     amaip;
8272    BioseqPtr            bsp_tmp = NULL;
8273    Int4                 i;
8274    BLAST_SummaryOptions *options = NULL;
8275    SBlastSeqalignArray * seqalign_arr=NULL;
8276    SeqAlignPtr          sap_new;
8277    SeqAlignPtr          sap_tmp;
8278    SeqAlignPtr          sap_tmp_next;
8279    SeqIdPtr             sip;
8280    Uint1                strand;
8281    Boolean              need_to_unlock = FALSE;
8282 
8283    if (bsp == NULL || acc_head == NULL)
8284       return NULL;
8285    acc = acc_head;
8286    allsap = NULL;
8287    allsap_prev = NULL;
8288    acc_new_head_head = acc_new_prev = NULL;
8289    BLAST_SummaryOptionsInit(&options);
8290    options->program = eBlastn;
8291    options->use_megablast = TRUE;
8292    options->word_size = CKA_blast_wordsize;
8293    options->cutoff_evalue = CKA_blast_expect_value;
8294    options->hint = eNone;
8295    options->gap_open = -1;
8296    options->gap_extend = -1;
8297    options->filter_string = StringSave ("F");
8298    while (acc != NULL)
8299    {
8300 
8301       if (need_to_unlock)
8302       {
8303         BioseqUnlock (bsp_tmp);
8304         need_to_unlock = FALSE;
8305       }
8306 
8307       bsp_tmp = NULL;
8308       if (StringNICmp (acc->accession, "ti", 2) == 0) {
8309         bsp_tmp = ReadFromTraceDb (acc->accession + 2);
8310       } else {
8311         sip = SeqIdFromAccessionDotVersion(acc->accession);
8312         bsp_tmp = BioseqLockById(sip);
8313         if (bsp_tmp != NULL) {
8314           need_to_unlock = TRUE;
8315           if (lip != NULL && lip->fp != NULL && IsHUPIDAccession (bsp_tmp)) {
8316             fprintf (lip->fp, "%s is unreleased accession in TPA Seq-Hist.\n", acc->accession);
8317             lip->data_in_log = TRUE;
8318           }
8319         }
8320       }
8321       if (bsp_tmp == NULL) {
8322         fprintf (lip->fp, "Unable to load %s", acc->accession);
8323         lip->data_in_log = TRUE;
8324         break;
8325       }
8326       if (bsp_tmp->id->next) {
8327         /* find the best accession */
8328         SeqIdPtr sip = SeqIdDup(SqnSeqIdFindBestAccession(bsp_tmp->id));
8329         bsp_tmp->id = SeqIdSetFree(bsp_tmp->id);
8330         bsp_tmp->id = sip;
8331       }
8332       if (!ISA_na(bsp_tmp->mol))
8333       {
8334          if (need_to_unlock)
8335          {
8336            BioseqUnlock(bsp_tmp);
8337            need_to_unlock = FALSE;
8338          }
8339          Message(MSG_ERROR, "%s is not a nucleotide bioseq.", acc->accession);
8340          break;
8341       }
8342       WatchCursor();
8343       if (acc->start_acc >=0 && acc->stop_acc >=0 &&
8344           acc->start_acc < bsp_tmp->length &&
8345           acc->start_acc < bsp_tmp->length) {
8346         SeqLocPtr slp1, slp2;
8347         if (acc->start_acc <= acc->stop_acc) {
8348           slp1 = SeqLocIntNew
8349             (acc->start_acc, acc->stop_acc, Seq_strand_plus, bsp_tmp->id);
8350         } else {
8351           slp1 = SeqLocIntNew
8352             (acc->stop_acc, acc->start_acc, Seq_strand_minus, bsp_tmp->id);
8353         }
8354         slp2 = SeqLocIntNew(0, bsp->length-1, Seq_strand_plus, bsp->id);
8355         acc->sap = NULL;
8356         seqalign_arr = NULL;
8357         BLAST_TwoSeqLocSets (options, slp1, slp2, NULL, &seqalign_arr, NULL, NULL, NULL);
8358         if (seqalign_arr != NULL)
8359         {
8360           acc->sap = seqalign_arr->array[0];
8361           seqalign_arr->array[0] = NULL;
8362           seqalign_arr = SBlastSeqalignArrayFree(seqalign_arr);
8363         }
8364         SeqLocFree(slp1);
8365         SeqLocFree(slp2);
8366       } else {
8367         acc->sap = NULL;
8368         BLAST_TwoSequencesSearch(options, bsp_tmp, bsp, &(acc->sap));
8369       }
8370       ArrowCursor();
8371       acc->start_acc = acc->stop_acc = 0; /* reset, for later usage */
8372       if (acc->sap != NULL)
8373          SPI_flip_sa_list(acc->sap);
8374       acc_new_head = NULL;
8375       if (acc->sap != NULL && acc->sap->next != NULL)
8376       {
8377          if (!CKA_blast_allow_repeats) {
8378            SelectBestRepeatsFromList (&(acc->sap));
8379          }
8380          AlnMgr2IndexLite(acc->sap);
8381          if (!CKA_blast_allow_repeats) {
8382            CKA_RemoveInconsistentAlnsFromSet(acc->sap, -1);
8383          }
8384          sap_tmp = acc->sap;
8385          acc->sap = (SeqAlignPtr)(acc->sap->segs);
8386          sap_tmp->segs = NULL;
8387          SeqAlignFree(sap_tmp);
8388          sap_tmp = acc->sap->next;
8389          acc->sap->next = NULL;
8390          while (sap_tmp != NULL)
8391          {
8392             AlnMgr2IndexSingleChildSeqAlign(sap_tmp);
8393             sap_tmp_next = sap_tmp->next;
8394             sap_tmp->next = NULL;
8395             acc_new = (CKA_AccPtr)MemNew(sizeof(CKA_Acc));
8396             acc_new->accession = StringSave(acc->accession);
8397             acc_new->sip_whole = SeqIdDup(acc->sip_whole);
8398             acc_new->sap = sap_tmp;
8399             sap_tmp = sap_tmp_next;
8400             if (!acc_new_head) {
8401               acc_new_head = acc_new;
8402             }
8403             if (acc_new_prev) {
8404               acc_new_prev->next = acc_new;
8405             }
8406             acc_new_prev = acc_new;
8407          }
8408       } else if (acc->sap != NULL)
8409          AlnMgr2IndexSingleChildSeqAlign(acc->sap);
8410       if (acc->sap != NULL)
8411       {
8412          strand = AlnMgr2GetNthStrand(acc->sap, 1);
8413          if (strand == Seq_strand_minus)
8414          {
8415             SeqAlignListReverseStrand(acc->sap);
8416             SAIndex2Free2(acc->sap->saip);
8417             acc->sap->saip = NULL;
8418          }
8419       }
8420       if (allsap != NULL && acc->sap != NULL)
8421       {
8422          allsap_prev->next = acc->sap;
8423          allsap_prev = allsap_prev->next;;
8424       } else if (acc->sap != NULL)
8425          allsap_prev = allsap = (acc->sap);
8426       acc_new = acc_new_head;
8427       while (acc_new != NULL)
8428       {
8429          strand = AlnMgr2GetNthStrand(acc_new->sap, 1);
8430          if (strand == Seq_strand_minus)
8431          {
8432             SeqAlignListReverseStrand(acc_new->sap);
8433             SAIndex2Free2(acc_new->sap->saip);
8434             acc_new->sap->saip = NULL;
8435          }
8436          if (allsap != NULL)
8437          {
8438             allsap_prev->next = acc_new->sap;
8439             allsap_prev = allsap_prev->next;;
8440          } else
8441             allsap_prev = allsap = acc_new->sap;
8442          acc_new = acc_new->next;
8443       }
8444       if (allsap_prev != NULL)
8445       {
8446          while (allsap_prev->next != NULL)
8447          {
8448             allsap_prev = allsap_prev->next;
8449          }
8450       }  
8451       if (need_to_unlock) 
8452       {
8453          BioseqUnlock(bsp_tmp);
8454          need_to_unlock = FALSE;
8455       }
8456       acc = acc->next;
8457       if (!acc_new_head_head) {
8458         acc_new_head_head = acc_new_head;
8459       }
8460    }
8461 
8462    BLAST_SummaryOptionsFree(options);
8463    if (need_to_unlock)
8464    {
8465       BioseqUnlock (bsp_tmp);
8466       need_to_unlock = FALSE;
8467    }
8468 
8469    acc = acc_head;
8470    while (acc->next != NULL)
8471    {
8472       acc = acc->next;
8473    }
8474    acc->next = acc_new_head_head;
8475    if (allsap == NULL)
8476       return NULL;
8477    sap_new = SeqAlignNew();
8478    sap_new->segtype = SAS_DISC;
8479    sap_new->segs = (Pointer)(allsap);
8480    allsap = sap_new;
8481    AlnMgr2IndexLite(allsap);
8482    AlnMgr2SortAlnSetByNthRowPos(allsap, 1);
8483    amaip = (AMAlignIndex2Ptr)(allsap->saip);
8484    for (i=0; i<amaip->numsaps-1; i++)
8485    {
8486       amaip->saps[i]->next = amaip->saps[i+1];
8487    }
8488    amaip->saps[amaip->numsaps-1]->next = NULL;
8489    allsap->segs = (Pointer)(amaip->saps[0]);
8490    return allsap;
8491 }
8492 
8493 static void DoCreateSeqHistTPA (IteM i)
8494 {
8495   BaseFormPtr        bfp;
8496   SeqEntryPtr        sep;
8497 
8498 #ifdef WIN_MAC
8499   bfp = currentFormDataPtr;
8500 #else
8501   bfp = GetObjectExtra (i);
8502 #endif
8503   if (bfp == NULL) return;
8504   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
8505   if (sep == NULL) return;
8506 
8507   CKA_RunChecker(sep);
8508 
8509   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
8510   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
8511 }
8512 
8513 extern void CreateSeqHistTPA (IteM i);
8514 extern void CreateSeqHistTPA (IteM i)
8515 {
8516   CKA_blast_wordsize = 28;
8517   CKA_blast_expect_value = 0.000001;
8518   CKA_blast_allow_repeats = FALSE;
8519   DoCreateSeqHistTPA(i);
8520 }
8521 
8522 static SeqAlignPtr DeltaSeq2SeqAlign(BioseqPtr bsp)
8523 {
8524   DeltaSeqPtr  deltasp;
8525   SeqLocPtr    slp;
8526   SeqAlignPtr  sap, sap_head = NULL;
8527   DenseSegPtr  dsp;
8528   SeqIntPtr    intp;
8529   SeqLitPtr    litp;
8530   int          curr_start = 0;
8531 
8532   if (bsp == NULL || bsp->repr != Seq_repr_delta || bsp->seq_ext_type != 4) {
8533     return NULL;
8534   }
8535   if (!(deltasp = (DeltaSeqPtr) bsp->seq_ext)) {
8536     return NULL;
8537   }
8538 
8539   while (deltasp) {
8540     if (deltasp->choice == 1) { 
8541       slp = (SeqLocPtr) deltasp->data.ptrvalue;
8542       if (sap_head) {
8543         sap = sap->next = SeqAlignNew();
8544       } else {
8545         sap_head = sap = SeqAlignNew();
8546       }
8547       dsp = DenseSegNew();
8548       
8549       sap->type = SAT_PARTIAL;
8550       sap->segtype = SAS_DENSEG;
8551       sap->dim = 2;
8552       sap->segs = (Pointer)(dsp);
8553       dsp->dim = 2;
8554       dsp->numseg = 1;
8555       dsp->lens = (Int4Ptr)MemNew((dsp->numseg)*sizeof(Int4));
8556       dsp->starts = (Int4Ptr)MemNew((dsp->numseg)*(dsp->dim)*sizeof(Int4));
8557       dsp->strands = (Uint1Ptr)MemNew((dsp->numseg)*(dsp->dim)*sizeof(Int4));
8558       
8559       dsp->ids = SeqIdDup(bsp->id);
8560       if (dsp->ids->next) {
8561         /* Dense-seg ids do not support lists, only 1 id per sequence */
8562         SeqIdFree(dsp->ids->next);
8563         dsp->ids->next = NULL;
8564       }
8565       switch (slp->choice) {
8566       case SEQLOC_INT:
8567         intp = (SeqIntPtr) slp->data.ptrvalue;
8568         dsp->starts[0] = curr_start;
8569         dsp->starts[1] = intp->from;
8570         curr_start += dsp->lens[0] = intp->to - intp->from + 1;
8571         dsp->strands[0] = Seq_strand_plus;
8572         dsp->strands[1] = intp->strand;
8573         dsp->ids->next = SeqIdDup(intp->id);
8574         break;
8575       default:
8576         /* exception */
8577         break;
8578       }
8579     } else if (deltasp->choice == 2) { 
8580       litp = (SeqLitPtr) deltasp->data.ptrvalue;
8581       if (litp != NULL) {
8582         curr_start += litp->length;
8583       }
8584     }
8585     deltasp = deltasp->next;
8586   }
8587   return sap_head;
8588 }
8589 
8590 static void DoDeltaHist (BioseqPtr bsp, Pointer userdata)
8591 
8592 {
8593   SeqAlignPtr  salp;
8594   SeqHistPtr   shp;
8595 
8596   if (bsp == NULL || bsp->repr != Seq_repr_delta || bsp->seq_ext_type != 4) return;
8597   shp = bsp->hist;
8598   if (shp != NULL && shp->assembly != NULL) return;
8599   salp = DeltaSeq2SeqAlign (bsp);
8600   if (salp == NULL) return;
8601   if (shp == NULL) {
8602     shp = SeqHistNew ();
8603     bsp->hist = shp;
8604   }
8605   if (shp == NULL) return;
8606   shp->assembly = salp;
8607 }
8608 
8609 extern void CreateSeqHistDelta (IteM i);
8610 extern void CreateSeqHistDelta (IteM i)
8611 {
8612   BaseFormPtr  bfp;
8613   SeqEntryPtr  sep;
8614 
8615 #ifdef WIN_MAC
8616   bfp = currentFormDataPtr;
8617 #else
8618   bfp = GetObjectExtra (i);
8619 #endif
8620   if (bfp == NULL) return;
8621   sep = GetTopSeqEntryForEntityID (bfp->input_entityID);
8622   if (sep == NULL) return;
8623 
8624   VisitBioseqsInSep (sep, NULL, DoDeltaHist);
8625 
8626   ObjMgrSetDirtyFlag (bfp->input_entityID, TRUE);
8627   ObjMgrSendMsg (OM_MSG_UPDATE, bfp->input_entityID, 0, 0);
8628 }
8629 
8630 static TexT blast_wordsize_text = NULL;
8631 static TexT blast_expect_value_text = NULL;
8632 static ButtoN blast_allow_repeats_button = NULL;
8633 static IteM blast_i;
8634 
8635 static void DoAcceptBlastOptions (ButtoN b)
8636 
8637 {
8638    Char    buf [64];
8639    long    val1;
8640    FloatHi val2;
8641 
8642    GetTitle (blast_wordsize_text, buf, sizeof (buf));
8643    if (sscanf (buf, "%ld", &val1) == 1) {
8644      CKA_blast_wordsize = CKA_blast_detailed_wordsize = (Int4) val1;
8645    }
8646    GetTitle (blast_expect_value_text, buf, sizeof (buf));
8647    if (sscanf (buf, "%lf", &val2) == 1) {
8648      CKA_blast_expect_value = CKA_blast_detailed_expect_value = (FloatHi) val2;
8649    }
8650    CKA_blast_allow_repeats = CKA_blast_detailed_allow_repeats =
8651      (Boolean) GetStatus (blast_allow_repeats_button);
8652    Remove (ParentWindow (b));
8653    DoCreateSeqHistTPA(blast_i);
8654 }
8655 
8656 extern void CreateSeqHistTPADetailed (IteM i);
8657 extern void CreateSeqHistTPADetailed (IteM i)
8658 {
8659    GrouP   c;
8660    GrouP   g;
8661    GrouP   h;
8662    WindoW  w;
8663    Char    buf[64];
8664 
8665    blast_i = i;
8666 
8667    w = FixedWindow (-50, -33, -10, -10, "Blast Options", NULL);
8668    h = HiddenGroup (w, -1, 0, NULL);
8669    SetGroupSpacing (h, 3, 2);
8670    g = HiddenGroup (h, 2, 0, NULL);
8671 
8672    StaticPrompt (g, "Word Size", 0, dialogTextHeight, programFont, 'l');
8673    if (CKA_blast_detailed_wordsize <= 0) {
8674      CKA_blast_detailed_wordsize = 14;
8675    }
8676    CKA_blast_wordsize = CKA_blast_detailed_wordsize;
8677    sprintf(buf, "%d", CKA_blast_wordsize);
8678    blast_wordsize_text = DialogText (g, buf, 10, NULL);
8679 
8680    StaticPrompt (g, "Expect Value", 0, dialogTextHeight, programFont, 'l');
8681    if (CKA_blast_detailed_expect_value <= 0.0) {
8682      CKA_blast_detailed_expect_value = 0.001;
8683    }
8684    CKA_blast_expect_value = CKA_blast_detailed_expect_value;
8685    sprintf(buf, "%f", CKA_blast_expect_value);
8686    blast_expect_value_text = DialogText (g, buf, 10, NULL);
8687 
8688    blast_allow_repeats_button = CheckBox (g, "Allow Repeats", NULL);
8689    if (CKA_blast_detailed_allow_repeats) {
8690      SetStatus(blast_allow_repeats_button, TRUE);
8691    }
8692 
8693    c = HiddenGroup (w, 2, 0, NULL);
8694    SetGroupSpacing (c, 5, 5);
8695    DefaultButton (c, "Accept", DoAcceptBlastOptions);
8696    PushButton (c, "Cancel", StdCancelButtonProc);